Blame view

simulators/utils/DeviceSim.py 9.6 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
19
20
21
22
23
24
    __metaclass__ = abc.ABCMeta
    name = ""
    config_socket_file = "../../config/socket_config.ini"
    config = None
    connected = False
    sock = None
    ip = None
    port = None
f7dd3df1   Jeremy   Update simulators...
25
    connections = []
605b65e5   Jeremy   Update simulators
26
27
28
29
30
31
32

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

    def setDevice(self, device_name):
        self.name = device_name
        self.getConfig()
c7583f6e   Etienne Pallier   Cleaner isolation...
33
34
        #self.getConnection(device_name)
        self.getConnection()
605b65e5   Jeremy   Update simulators
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
        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...
52
53
54
    def forceLog(self, name, message: str):
        print(name + " FORCE LOG : " + message)

605b65e5   Jeremy   Update simulators
55
56
    def accept(self):
        try:
c7583f6e   Etienne Pallier   Cleaner isolation...
57
58
59
60
61
            # 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...
62
            connection, address = self.sock.accept()
81026d94   Quentin Durand   Updating reconnec...
63
64
65
66
67
        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
68
        except socket.error as e:
81026d94   Quentin Durand   Updating reconnec...
69
            print(str(e))
c7583f6e   Etienne Pallier   Cleaner isolation...
70
            print(self.name, "No connection established")
605b65e5   Jeremy   Update simulators
71
            self.log(self.name, "No connection established")
76dfa189   Unknown   Adding devices lo...
72

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

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

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

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

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

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

c7583f6e   Etienne Pallier   Cleaner isolation...
158
159
160
161
162
163
    #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
164
165
166
167
168
169
170
171
        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...
172
173
        if DEBUG_FILE:
            print("From simulator : " + device_name + " -> " + message, file=sys.stderr)
605b65e5   Jeremy   Update simulators
174
175
176
        return (0)

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

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

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

605b65e5   Jeremy   Update simulators
186
187
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
f7dd3df1   Jeremy   Update simulators...
188
            self.sock.settimeout(1)
605b65e5   Jeremy   Update simulators
189
190
            self.sock.bind((self.ip, self.port))
            self.sock.listen(122)
605b65e5   Jeremy   Update simulators
191
192
193
        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...
194
195
196
            # (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
197
198
199
        self.connected = True
        return (0)

605b65e5   Jeremy   Update simulators
200
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

# 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))