Blame view

simulators/utils/DeviceSim.py 9.67 KB
605b65e5   Jeremy   Update simulators
1
2
3
4
5
import configparser
import socket
import select
import abc
import sys
f7dd3df1   Jeremy   Update simulators...
6
from . import settings
0b83e9b3   Quentin Durand   Activate Device a...
7
DEBUG_FILE = True
3224f14a   Jeremy   Fixed some simula...
8

605b65e5   Jeremy   Update simulators
9
10
'''
    Generic class for simulators.
c7583f6e   Etienne Pallier   Cleaner isolation...
11
    Initializes the sockets and the grammar, reads the CONFIG_FILE.
605b65e5   Jeremy   Update simulators
12
13
14
15

    Classes inheriting from it must call the __init__ function with their name (Telescope, CameraVIS, ...)
'''

1957226d   Etienne Pallier   Renamed (simulato...
16
class DeviceSim(object):
605b65e5   Jeremy   Update simulators
17
18
    __metaclass__ = abc.ABCMeta
    name = ""
a9d06e6f   Etienne Pallier   new PYROS_DOCKER_...
19
20
    #config_socket_file = "../../config/socket_config.ini"
    config_socket_file = "../../config/old_config/socket_config.ini"
605b65e5   Jeremy   Update simulators
21
22
23
24
25
    config = None
    connected = False
    sock = None
    ip = None
    port = None
f7dd3df1   Jeremy   Update simulators...
26
    connections = []
605b65e5   Jeremy   Update simulators
27
28
29
30
31
32
33

    def __init__(self, device_name):
        super().__init__()

    def setDevice(self, device_name):
        self.name = device_name
        self.getConfig()
c7583f6e   Etienne Pallier   Cleaner isolation...
34
35
        #self.getConnection(device_name)
        self.getConnection()
605b65e5   Jeremy   Update simulators
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
        self.listen()

    def configSocket(self):
        self.sock.settimeout(1)

    @abc.abstractmethod
    def set(self, command: str, *args):
        return

    @abc.abstractmethod
    def do(self, command: str, *args):
        return

    @abc.abstractmethod
    def get(self, command: str, *args):
        return

3224f14a   Jeremy   Fixed some simula...
53
54
55
    def forceLog(self, name, message: str):
        print(name + " FORCE LOG : " + message)

605b65e5   Jeremy   Update simulators
56
57
    def accept(self):
        try:
c7583f6e   Etienne Pallier   Cleaner isolation...
58
59
60
61
62
            # Accept a connection. 
            # The socket must be bound to an address and listening for connections. 
            # The return value is a pair (conn, address) 
            # where conn is a new socket object usable to send and receive data on the connection, 
            # and address is the address bound to the socket on the other end of the connection.
f7dd3df1   Jeremy   Update simulators...
63
            connection, address = self.sock.accept()
81026d94   Quentin Durand   Updating reconnec...
64
65
66
67
68
        except socket.timeout:
            if len(self.connections) == 0:
                print(self.name, "No connection established")
                self.log(self.name, "No connection established")
            return False
605b65e5   Jeremy   Update simulators
69
        except socket.error as e:
81026d94   Quentin Durand   Updating reconnec...
70
            print(str(e))
c7583f6e   Etienne Pallier   Cleaner isolation...
71
            print(self.name, "No connection established")
605b65e5   Jeremy   Update simulators
72
            self.log(self.name, "No connection established")
76dfa189   Unknown   Adding devices lo...
73

c7583f6e   Etienne Pallier   Cleaner isolation...
74
75
            return False
        self.connections.append({"connection": connection, "address": address})
76dfa189   Unknown   Adding devices lo...
76
        self.log(self.name, "Connection successfully established")
c7583f6e   Etienne Pallier   Cleaner isolation...
77
        return True
605b65e5   Jeremy   Update simulators
78

f7dd3df1   Jeremy   Update simulators...
79
80
81
82
    def close(self, connection_address):
        if (connection_address):
            connection_address["connection"].close()
            self.connections.remove(connection_address)
605b65e5   Jeremy   Update simulators
83
84
85
            return (0)
        return (1)

f7dd3df1   Jeremy   Update simulators...
86
87
    def sendMessage(self, message: str, co) -> int:
        if (not co["connection"] or not co["address"]):
c7583f6e   Etienne Pallier   Cleaner isolation...
88
89
            #(EP) return (1)
            raise Exception("sendMessage(): no connection or no address")
605b65e5   Jeremy   Update simulators
90
        try:
f7dd3df1   Jeremy   Update simulators...
91
            readable, writable, exceptional = select.select([], [co["connection"]], [co["connection"]], 0)
605b65e5   Jeremy   Update simulators
92
            if not (writable or exceptional):
f7dd3df1   Jeremy   Update simulators...
93
94
                raise (Exception("Socket not writable " + str(co["address"])))
            co["connection"].send(bytes(message, "UTF-8"))
c7583f6e   Etienne Pallier   Cleaner isolation...
95
96
            #self.forceLog(self.name, "Message sent [" + message + "] to " + str(co["address"]))
            self.forceLog(self.name, "Message sent to " + str(co["address"]) +" : [" + message + "]")
76dfa189   Unknown   Adding devices lo...
97
            self.log(self.name, "Message sent to " + str(co["address"]) +" : [" + message + "]")
605b65e5   Jeremy   Update simulators
98
99
        except Exception as e:
            if (settings.DEBUG):
c7583f6e   Etienne Pallier   Cleaner isolation...
100
                print(self.name, "Could not send message on socket "+ str(co["address"]) +" : " + message + " -> " + str(e))
f7dd3df1   Jeremy   Update simulators...
101
                self.log(self.name, "Could not send message on socket "+ str(co["address"]) +" : " + message + " -> " + str(e))
605b65e5   Jeremy   Update simulators
102
103
104
105
106
107
108
109
110
            return (1)
        return (0)

    def isError(self, message: str):
        if (message == "FAILED" or message == "NOT_SET" or message == "DISCONNECTED"):
            return (True)
        return (False)

    def isConnected(self):
f7dd3df1   Jeremy   Update simulators...
111
        self.accept()
c7583f6e   Etienne Pallier   Cleaner isolation...
112
113
114
        if not self.connections:
            return False
        return True
605b65e5   Jeremy   Update simulators
115

f7dd3df1   Jeremy   Update simulators...
116
117
    def readBytes(self, size, co) -> str:
        if (not co["connection"] or not co["address"]):
c7583f6e   Etienne Pallier   Cleaner isolation...
118
119
            #(EP) return ("NOT_SET")
            raise Exception("NOT_SET, no connection or address")
605b65e5   Jeremy   Update simulators
120
        try:
f7dd3df1   Jeremy   Update simulators...
121
            readable, writable, exceptional = select.select([co["connection"]], [], [co["connection"]], 0)
605b65e5   Jeremy   Update simulators
122
            if not (readable or exceptional):
f7dd3df1   Jeremy   Update simulators...
123
124
                raise (Exception("Socket not readable" + str(co["address"])))
            ret = co["connection"].recv(size).decode()
605b65e5   Jeremy   Update simulators
125
126
            if (not ret):
                if (settings.DEBUG):
c7583f6e   Etienne Pallier   Cleaner isolation...
127
                    print(self.name, "Connection has been killed" + str(co["address"]))
f7dd3df1   Jeremy   Update simulators...
128
129
                    self.log(self.name, "Connection has been killed" + str(co["address"]))
                self.connections.remove(co)
c7583f6e   Etienne Pallier   Cleaner isolation...
130
131
132
                #(EP) return ("DISCONNECTED")
                raise Exception("DISCONNECTED")
            self.forceLog(self.name, "Message received on " + str(co["address"]) +" : [" + ret + "]")
76dfa189   Unknown   Adding devices lo...
133
            self.log(self.name, "Message received on " + str(co["address"]) + " : [" + ret + "]")
605b65e5   Jeremy   Update simulators
134
135
        except Exception as e:
            if (settings.DEBUG):
c7583f6e   Etienne Pallier   Cleaner isolation...
136
                print(self.name, "Socket not readable : " + str(e))
605b65e5   Jeremy   Update simulators
137
138
                self.log(self.name, "Socket not readable : " + str(e))
            return ("FAILED")
c7583f6e   Etienne Pallier   Cleaner isolation...
139
            #raise Exception("FAILED")
605b65e5   Jeremy   Update simulators
140
141
142
143
144
145
146
        return (ret)

    def blockAndReadBytes(self, size) -> str:
        self.sock.setblocking(1)
        return (self.readBytes(size))

    def blockAndReadMessage(self) -> str:
f6076245   Patrick Maeght   penelope work part 1
147
        return (self.blockAndReadBytes(2048))
605b65e5   Jeremy   Update simulators
148

f7dd3df1   Jeremy   Update simulators...
149
150
    def setBlocking(self, flag, connection):
        if (not connection["connection"]):
605b65e5   Jeremy   Update simulators
151
            return (1)
f7dd3df1   Jeremy   Update simulators...
152
        connection["connection"].setblocking(flag)
605b65e5   Jeremy   Update simulators
153
154
        return (0)

f6076245   Patrick Maeght   penelope work part 1
155
    # TODO maybe read more than 2048 bytes for a single message ?????
f7dd3df1   Jeremy   Update simulators...
156
    def readMessage(self, connection) -> str:
f6076245   Patrick Maeght   penelope work part 1
157
        return self.readBytes(2048, connection)
605b65e5   Jeremy   Update simulators
158

c7583f6e   Etienne Pallier   Cleaner isolation...
159
160
161
162
163
164
    #def getConnection(self, device_name):
    def getConnection(self):
        #self.ip = self.config.get(device_name, "ip")
        #self.port = int(self.config.get(device_name, "port"))
        self.ip = self.config.get(self.name, "ip")
        self.port = int(self.config.get(self.name, "port"))
605b65e5   Jeremy   Update simulators
165
166
167
168
169
170
171
172
        return (0)

    def getConfig(self):
        self.config = configparser.ConfigParser()
        self.config.read(self.config_socket_file)
        return (0)

    def log(self, device_name: str, message: str):
3224f14a   Jeremy   Fixed some simula...
173
174
        if DEBUG_FILE:
            print("From simulator : " + device_name + " -> " + message, file=sys.stderr)
605b65e5   Jeremy   Update simulators
175
176
177
        return (0)

    def listen(self):
76dfa189   Unknown   Adding devices lo...
178

605b65e5   Jeremy   Update simulators
179
180
        if (self.ip is None or self.port is None):
            self.log(self.name, "Ip or Port not initialized")
c7583f6e   Etienne Pallier   Cleaner isolation...
181
182
183
184
            # (EP) It's a serious bug, so raise exception !!!
            #return (1)
            raise Exception(self.name +" has no ip or port")

605b65e5   Jeremy   Update simulators
185
        try:
76dfa189   Unknown   Adding devices lo...
186

605b65e5   Jeremy   Update simulators
187
188
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
f7dd3df1   Jeremy   Update simulators...
189
            self.sock.settimeout(1)
605b65e5   Jeremy   Update simulators
190
191
            self.sock.bind((self.ip, self.port))
            self.sock.listen(122)
605b65e5   Jeremy   Update simulators
192
193
194
        except Exception as e:
            if (settings.DEBUG):
                self.log(self.name, "Failed to listen to " + str(self.ip) + ":" + str(self.port))
c7583f6e   Etienne Pallier   Cleaner isolation...
195
196
197
            # (EP) It's a serious bug, so raise exception !!!
            #return (1)
            raise Exception(self.name, "failed to listen to " + str(self.ip) + ":" + str(self.port))
605b65e5   Jeremy   Update simulators
198
199
200
        self.connected = True
        return (0)

605b65e5   Jeremy   Update simulators
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

# class Device():
#     def __init__(self, simul_name):
#
#         config = configparser.ConfigParser()
#         config.read(CONFIG_FILE)
#
#         ip = config.get(simul_name, "ip")
#         port = int(config.get(simul_name, "port"))
#
#         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#         self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#         self.sock.bind((ip, port))
#         self.sock.listen(122)
#
#         self.set_msgs = []
#         self.get_msgs = []
#         self.do_msgs = []
#
#         self.enums = {}
#
#         with open(GRAMMAR_FILE) as grammar_file:
#             grammar = json.load(grammar_file)
#
#         enums = grammar["Enums"]
#
#         for enum in enums :
#             self.enums[enum] = enums[enum]
#
#         if simul_name[:6] == "Camera":
#             device = grammar["Camera"]
#
#             for item in device["set"]:
#                 param_type = item["param_type"]
#                 if len(param_type) < 4 or param_type[:4] != "Enum":
#                     ''' This transforms 'int' string to <int> type '''
#                     param_type = locate(param_type)
#                 self.set_msgs.append((item["name"], item["nb_param"], param_type))
#             for item in device["get"]:
#                 self.get_msgs.append(item)
#             for item in device["do"]:
#                 param_type = item["param_type"]
#                 if len(param_type) < 4 or param_type[:4] != "Enum":
#                     param_type = locate(param_type)
#                 self.do_msgs.append((item["name"], item["nb_param"], param_type))
#
#         device = grammar[simul_name]
#
#         for item in device["set"]:
#             param_type = item["param_type"]
#             if len(param_type) < 4 or param_type[:4] != "Enum":
#                 param_type = locate(param_type)
#             self.set_msgs.append((item["name"], item["nb_param"], param_type))
#         for item in device["get"]:
#             self.get_msgs.append(item)
#         for item in device["do"]:
#             param_type = item["param_type"]
#             if len(param_type) < 4 or param_type[:4] != "Enum":
#                 param_type = locate(param_type)
#             self.do_msgs.append((item["name"], item["nb_param"], param_type))