ajout de commentaire dans monitor-python.py

This commit is contained in:
vezde 2022-02-07 11:02:42 +01:00
parent 5e6f579007
commit fda59fc14d

View file

@ -11,11 +11,14 @@ import time
import sys import sys
class GlobVar: class GlobVar:
connectedToPi = False port = 5544 # default server port
port = 5544 timeout=1.0 # default waiting time for an answer. May be increased for debugging purpose
timeout=1000 address = "localhost" # default server address. Use this with 'nc -l <port>' for testing on your machine
address = "10.105.1.13" getBatteryLevelPeriod=-1 # periodic delay for requesting battery level. If value is 0 or below, not battery check is done
# do not modify value below this line
connectedToPi = False
connectedToDumber = False connectedToDumber = False
dumberStarted = False dumberStarted = False
@ -28,11 +31,17 @@ class GlobVar:
exceptionmsg= "" exceptionmsg= ""
# Network event from socket.
# Event are 'Connected to server' or 'disconnected from server'
class NetworkEvents: class NetworkEvents:
EVENT_CONNECTED=1 EVENT_CONNECTED=1
EVENT_CONNECTION_LOST=0 EVENT_CONNECTION_LOST=0
UNKNOWN_EVENT=-1 UNKNOWN_EVENT=-1
# Network managment class
# Contain a thread for conenction to server and data reception
# Contains functions for sending message to server
# Contains functions for answer decoding
class Network(): class Network():
receiveCallback=None receiveCallback=None
eventCallback=None eventCallback=None
@ -41,12 +50,19 @@ class Network():
receiveEvent = None receiveEvent = None
receivedAnswer = "" receivedAnswer = ""
# List of possible answers from server
ANSWER_ACK = "AACK" ANSWER_ACK = "AACK"
ANSWER_NACK = "ANAK" ANSWER_NACK = "ANAK"
ANSWER_COM_ERROR = "ACER" ANSWER_COM_ERROR = "ACER"
ANSWER_TIMEOUT = "ATIM" ANSWER_TIMEOUT = "ATIM"
ANSWER_CMD_REJECTED = "ACRJ" ANSWER_CMD_REJECTED = "ACRJ"
# List of possible messages from server
MESSAGE = "MSSG" MESSAGE = "MSSG"
ROBOT_BATTERY_LEVEL = "RBLV"
ROBOT_CURRENT_STATE = "RCST"
# List of accepted command by server
CAMERA_OPEN = "COPN" CAMERA_OPEN = "COPN"
CAMERA_CLOSE = "CCLS" CAMERA_CLOSE = "CCLS"
CAMERA_IMAGE = "CIMG" CAMERA_IMAGE = "CIMG"
@ -71,13 +87,12 @@ class Network():
ROBOT_GO_RIGHT = "RGRI" ROBOT_GO_RIGHT = "RGRI"
ROBOT_STOP = "RSTP" ROBOT_STOP = "RSTP"
ROBOT_POWEROFF = "RPOF" ROBOT_POWEROFF = "RPOF"
ROBOT_BATTERY_LEVEL = "RBLV"
ROBOT_GET_BATTERY = "RGBT" ROBOT_GET_BATTERY = "RGBT"
ROBOT_GET_STATE = "RGST" ROBOT_GET_STATE = "RGST"
ROBOT_CURRENT_STATE = "RCST"
SEPARATOR_CHAR = ':' SEPARATOR_CHAR = ':'
# Decoded answers
ACK = 1 ACK = 1
NACK =2 NACK =2
COM_ERROR =3 COM_ERROR =3
@ -85,13 +100,18 @@ class Network():
CMD_REJECTED=5 CMD_REJECTED=5
UNKNOWN=-1 UNKNOWN=-1
# Initialisation method.
def __init__(self, receiveCallback=None, eventCallback=None) -> None: def __init__(self, receiveCallback=None, eventCallback=None) -> None:
self.receiveCallback = receiveCallback self.receiveCallback = receiveCallback
self.eventCallback = eventCallback self.eventCallback = eventCallback
self.waitForAnswer=False self.waitForAnswer=False
self.receiveEvent = threading.Event() self.receiveEvent = threading.Event()
def ReceptionThread(self): # Reception thread used for conencting to server and receiving data.
# Never stop, auto reconnect if connection is lost
# Send event when conencting to or disconnecting from server
# send received message to appropriate callback
def ReceptionThread(self) -> None:
while True: while True:
try: try:
self.__connect() self.__connect()
@ -110,11 +130,13 @@ class Network():
time.sleep(2.0) time.sleep(2.0)
# Method helper for starting reception thread
def startReceptionThread(self) -> None: def startReceptionThread(self) -> None:
self.threadId = threading.Thread(target=self.ReceptionThread, args=()) self.threadId = threading.Thread(target=self.ReceptionThread, args=())
self.threadId.daemon=True self.threadId.daemon=True
self.threadId.start() self.threadId.start()
# Private method for connecting to server
def __connect(self) -> None: def __connect(self) -> None:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -125,6 +147,7 @@ class Network():
self.waitForAnswer=False self.waitForAnswer=False
# Private method for sending raw data to server
def __write(self, msg: str) -> None: def __write(self, msg: str) -> None:
totalsent = 0 totalsent = 0
if msg[-1] != '\n': if msg[-1] != '\n':
@ -140,6 +163,8 @@ class Network():
raise RuntimeError("Unable to send data to " + GlobVar.address + ":" + str(GlobVar.port)) raise RuntimeError("Unable to send data to " + GlobVar.address + ":" + str(GlobVar.port))
totalsent = totalsent + sent totalsent = totalsent + sent
# Private method for receiving data from server.
# Data received are sent to callback __receiveHandler for decoding
def __read(self) -> None: def __read(self) -> None:
chunks = [] chunks = []
bytes_recd = 0 bytes_recd = 0
@ -159,6 +184,8 @@ class Network():
bytes_recd =0 bytes_recd =0
last_char=0 last_char=0
# private callback for reception and decoding of data.
# If no answer is wait, send data to caller callback
def __receiveHandler(self, data: str) -> None: def __receiveHandler(self, data: str) -> None:
# traitement a faire lors de la reception de donnée # traitement a faire lors de la reception de donnée
if self.waitForAnswer: if self.waitForAnswer:
@ -170,7 +197,8 @@ class Network():
if self.receiveCallback != None: if self.receiveCallback != None:
self.receiveCallback(data) self.receiveCallback(data)
def __sendCommand(self,cmd, waitans) -> str: # Private method for sending command to server
def __sendCommand(self,cmd, waitans: bool) -> str:
if waitans == True: if waitans == True:
self.waitForAnswer = True self.waitForAnswer = True
else: else:
@ -181,7 +209,7 @@ class Network():
if waitans: if waitans:
ans = self.ANSWER_TIMEOUT ans = self.ANSWER_TIMEOUT
try: try:
self.receiveEvent.wait(timeout=1.0) # timeout set to 0.3 sec self.receiveEvent.wait(timeout=GlobVar.timeout) # Max waiting time = GlobVar.timeout
if self.receiveEvent.is_set(): if self.receiveEvent.is_set():
ans=self.receivedAnswer ans=self.receivedAnswer
@ -200,7 +228,8 @@ class Network():
else: else:
return self.ANSWER_ACK return self.ANSWER_ACK
def __decodeAnswer(self, ans) -> int: # Private method for decoding answer from server
def __decodeAnswer(self, ans: str) -> int:
if self.ANSWER_ACK in ans: if self.ANSWER_ACK in ans:
return self.ACK return self.ACK
elif self.ANSWER_NACK in ans: elif self.ANSWER_NACK in ans:
@ -214,49 +243,61 @@ class Network():
else: else:
return self.UNKNOWN return self.UNKNOWN
# Send OpenCom command to server
def robotOpenCom(self) -> int: def robotOpenCom(self) -> int:
ans = self.__sendCommand(self.ROBOT_COM_OPEN, True) ans = self.__sendCommand(self.ROBOT_COM_OPEN, True)
return self.__decodeAnswer(ans) return self.__decodeAnswer(ans)
# Send CloseCom command to server
def robotCloseCom(self) -> int: def robotCloseCom(self) -> int:
ans = self.__sendCommand(self.ROBOT_COM_CLOSE, True) ans = self.__sendCommand(self.ROBOT_COM_CLOSE, True)
return self.__decodeAnswer(ans) return self.__decodeAnswer(ans)
# Send StartWithWatchdog command to server
def robotStartWithWatchdog(self) -> int: def robotStartWithWatchdog(self) -> int:
ans = self.__sendCommand(self.ROBOT_START_WITH_WD, True) ans = self.__sendCommand(self.ROBOT_START_WITH_WD, True)
return self.__decodeAnswer(ans) return self.__decodeAnswer(ans)
# Send StartWithoutWatchdog command to server
def robotStartWithoutWatchdog(self) -> int: def robotStartWithoutWatchdog(self) -> int:
ans = self.__sendCommand(self.ROBOT_START_WITHOUT_WD, True) ans = self.__sendCommand(self.ROBOT_START_WITHOUT_WD, True)
return self.__decodeAnswer(ans) return self.__decodeAnswer(ans)
# Send Reset command to server
def robotReset(self) -> int: def robotReset(self) -> int:
ans = self.__sendCommand(self.ROBOT_RESET, True) ans = self.__sendCommand(self.ROBOT_RESET, True)
return self.__decodeAnswer(ans) return self.__decodeAnswer(ans)
# Send Stop command to server
def robotStop(self) -> int: def robotStop(self) -> int:
ans = self.__sendCommand(self.ROBOT_STOP, True) ans = self.__sendCommand(self.ROBOT_STOP, True)
return self.__decodeAnswer(ans) return self.__decodeAnswer(ans)
# Send GoLeft command to server
def robotGoLeft(self) -> int: def robotGoLeft(self) -> int:
ans = self.__sendCommand(self.ROBOT_GO_LEFT, True) ans = self.__sendCommand(self.ROBOT_GO_LEFT, True)
return self.__decodeAnswer(ans) return self.__decodeAnswer(ans)
# Send GoRight command to server
def robotGoRight(self) -> int: def robotGoRight(self) -> int:
ans = self.__sendCommand(self.ROBOT_GO_RIGHT, True) ans = self.__sendCommand(self.ROBOT_GO_RIGHT, True)
return self.__decodeAnswer(ans) return self.__decodeAnswer(ans)
# Send GoForward command to server
def robotGoForward(self) -> int: def robotGoForward(self) -> int:
ans = self.__sendCommand(self.ROBOT_GO_FORWARD, True) ans = self.__sendCommand(self.ROBOT_GO_FORWARD, True)
return self.__decodeAnswer(ans) return self.__decodeAnswer(ans)
# Send GoBackward command to server
def robotGoBackward(self) -> int: def robotGoBackward(self) -> int:
ans = self.__sendCommand(self.ROBOT_GO_BACKWARD, True) ans = self.__sendCommand(self.ROBOT_GO_BACKWARD, True)
return self.__decodeAnswer(ans) return self.__decodeAnswer(ans)
# Send GetBattery command to server
def robotGetBattery(self) -> None: def robotGetBattery(self) -> None:
ans = self.__sendCommand(self.ROBOT_GET_BATTERY,False) ans = self.__sendCommand(self.ROBOT_GET_BATTERY,False)
# Function for decoding battery level
def batterylevelToStr(batlvl: int) -> str: def batterylevelToStr(batlvl: int) -> str:
switcher = { switcher = {
2: "Full", 2: "Full",
@ -266,6 +307,7 @@ def batterylevelToStr(batlvl: int) -> str:
return switcher.get(batlvl, "Unknown") return switcher.get(batlvl, "Unknown")
# Function for display human readable answer
def answertoStr(ans: int) -> str: def answertoStr(ans: int) -> str:
switcher = { switcher = {
Network.ACK: "Acknowledged", Network.ACK: "Acknowledged",
@ -277,7 +319,8 @@ def answertoStr(ans: int) -> str:
return switcher.get(ans, "Unknown answer") return switcher.get(ans, "Unknown answer")
def threadRefreshScreen(currentWindow): # Thread for updtating display
def threadRefreshScreen(currentWindow) -> None:
while 1: while 1:
currentWindow.clear() currentWindow.clear()
currentWindow.addstr("Connected to " + GlobVar.address + ":" + str(GlobVar.port) +" = " + str(GlobVar.connectedToPi)) currentWindow.addstr("Connected to " + GlobVar.address + ":" + str(GlobVar.port) +" = " + str(GlobVar.connectedToPi))
@ -293,13 +336,13 @@ def threadRefreshScreen(currentWindow):
currentWindow.addstr("Last answer received = " + answertoStr(GlobVar.last_answer)) currentWindow.addstr("Last answer received = " + answertoStr(GlobVar.last_answer))
currentWindow.move(9,0) currentWindow.move(9,0)
currentWindow.addstr("Messages received (log)") currentWindow.addstr("Messages received (log)")
# up to 8 messages
for i in range(0,len(GlobVar.message)): for i in range(0,len(GlobVar.message)):
currentWindow.move(10+i,0) currentWindow.move(10+i,0)
currentWindow.addstr("[mes "+str(i)+ "] ") currentWindow.addstr("[mes "+str(i)+ "] ")
currentWindow.addstr(str(GlobVar.message[i])) currentWindow.addstr(str(GlobVar.message[i]))
# up to 8 messages
currentWindow.move(20,0) currentWindow.move(20,0)
currentWindow.addstr("Commands : \'O\' = Open COM with robot/ \'C\' = Close COM with robot") currentWindow.addstr("Commands : \'O\' = Open COM with robot/ \'C\' = Close COM with robot")
currentWindow.move(21,0) currentWindow.move(21,0)
@ -311,7 +354,8 @@ def threadRefreshScreen(currentWindow):
currentWindow.refresh() currentWindow.refresh()
time.sleep(0.5) time.sleep(0.5)
def threadGetKeys(win, net:Network): # Thread for reading keyboard keys and sending corresponding commands to server
def threadGetKeys(win: curses.window, net:Network) -> None:
while 1: while 1:
try: try:
key = win.getkey() key = win.getkey()
@ -366,15 +410,20 @@ def threadGetKeys(win, net:Network):
except Exception as e: except Exception as e:
GlobVar.exceptionmsg="Exception received: " + str(e) GlobVar.exceptionmsg="Exception received: " + str(e)
def threadPeriodic(net: Network): # Thread used for requesting battery level, exit if getBatteryLevelPeriod is 0 or below
def threadPeriodic(net: Network) -> None:
while True: while True:
time.sleep(5.0) if GlobVar.getBatteryLevelPeriod>0:
time.sleep(GlobVar.getBatteryLevelPeriod)
GlobVar.batteryLevel = -1 GlobVar.batteryLevel = -1
if GlobVar.connectedToPi: if GlobVar.connectedToPi:
net.robotGetBattery() net.robotGetBattery()
else:
break
def receptionCallback(s:str): # Callback used to decode non answer message from server (mainly battery level and log message)
def receptionCallback(s:str) -> None:
if Network.ROBOT_BATTERY_LEVEL in s: if Network.ROBOT_BATTERY_LEVEL in s:
str_split = s.split(':') str_split = s.split(':')
@ -394,13 +443,15 @@ def receptionCallback(s:str):
if len(GlobVar.message) > 8: if len(GlobVar.message) > 8:
GlobVar.message.pop(0) GlobVar.message.pop(0)
def eventCallback(event): # Callback for connection/deconnection event from network manager
def eventCallback(event: NetworkEvents) -> None:
if event == NetworkEvents.EVENT_CONNECTED: if event == NetworkEvents.EVENT_CONNECTED:
GlobVar.connectedToPi = True GlobVar.connectedToPi = True
elif event == NetworkEvents.EVENT_CONNECTION_LOST: elif event == NetworkEvents.EVENT_CONNECTION_LOST:
GlobVar.connectedToPi = False GlobVar.connectedToPi = False
def main(win): # Main program, wait for keys thread to end (CTRL-C)
def main(win: curses.window) -> None:
win.keypad(True) win.keypad(True)
net = Network(receiveCallback=receptionCallback, eventCallback=eventCallback) net = Network(receiveCallback=receptionCallback, eventCallback=eventCallback)
@ -417,7 +468,7 @@ def main(win):
periodicThread = threading.Thread(target=threadPeriodic, args=(net,)) periodicThread = threading.Thread(target=threadPeriodic, args=(net,))
periodicThread.daemon=True periodicThread.daemon=True
# periodicThread.start() periodicThread.start()
keyThread.join() keyThread.join()
@ -431,18 +482,13 @@ try:
print ("No target address specified") print ("No target address specified")
print ("Usage: monitor-python.py address [port]") print ("Usage: monitor-python.py address [port]")
exit (-1) #exit (-1) # Comment this line for connecting to localhost
#GlobVar.address = "10.105.1.12"
if len(sys.argv)>=3: if len(sys.argv)>=3:
GlobVar.port = int(sys.argv[2]) GlobVar.port = int(sys.argv[2])
else:
GlobVar.port = 5544
curses.wrapper(main) curses.wrapper(main)
except KeyboardInterrupt: except KeyboardInterrupt: # exception when pressing CTRL-C
print ("Bye bye") print ("Bye bye")
except:
raise