diff --git a/raspberry-dataserver/commsConstants.py b/raspberry-dataserver/commsConstants.py index 6a3eea3093f8a344b6319a5732eedc7c0c5ef9b5..3a69ca2d2490acde7edb555688296766fb8b52ee 100644 --- a/raspberry-dataserver/commsConstants.py +++ b/raspberry-dataserver/commsConstants.py @@ -14,20 +14,28 @@ class payloadType(Enum): class BaseFormat(): def __init__(self): - self.RPI_VERSION = 0xA0 - self.version = 0 - self.byteArray = None + self._RPI_VERSION = 0xA0 + self._byteArray = None self._type = payloadType.payloadUnset + self._version = 0 + + @property + def byteArray(self): + return self._byteArray + + @byteArray.setter + def byteArray(self): + print("Use fromByteArray to change this") # check for mismatch between pi and microcontroller version def checkVersion(self): - if self.RPI_VERSION == self.version : - self.version_error = True + if self._RPI_VERSION == self._version : + self._version_error = True else : - self.version_error = False + self._version_error = False def getSize(self): - return len(self.byteArray) + return len(self._byteArray) def getType(self): return self._type @@ -48,72 +56,72 @@ class dataFormat(BaseFormat): # < = little endian # > = big endian # ! = network format (big endian) - self.dataStruct = Struct("!BBHHHHHHHHHBBBBBB") - self.byteArray = None + self._dataStruct = Struct("!BBHHHHHHHHHBBBBBB") + self._byteArray = None self._type = payloadType.payloadData # make all zero to start with - self.version = 0 - self.fsm_state = 0 - self.pressure_air_supply = 0 - self.pressure_air_regulated = 0 - self.pressure_o2_supply = 0 - self.pressure_o2_regulated = 0 - self.pressure_buffer = 0 - self.pressure_inhale = 0 - self.pressure_patient = 0 - self.temperature_buffer = 0 - self.pressure_diff_patient = 0 - self.readback_valve_air_in = 0 - self.readback_valve_o2_in = 0 - self.readback_valve_inhale = 0 - self.readback_valve_exhale = 0 - self.readback_valve_purge = 0 - self.readback_mode = 0 + self._version = 0 + self._fsm_state = 0 + self._pressure_air_supply = 0 + self._pressure_air_regulated = 0 + self._pressure_o2_supply = 0 + self._pressure_o2_regulated = 0 + self._pressure_buffer = 0 + self._pressure_inhale = 0 + self._pressure_patient = 0 + self._temperature_buffer = 0 + self._pressure_diff_patient = 0 + self._readback_valve_air_in = 0 + self._readback_valve_o2_in = 0 + self._readback_valve_inhale = 0 + self._readback_valve_exhale = 0 + self._readback_valve_purge = 0 + self._readback_mode = 0 def __repr__(self): return f"""{{ - "version" : {self.version}, - "fsm_state" : {self.fsm_state}, - "pressure_air_supply" : {self.pressure_air_supply}, - "pressure_air_regulated" : {self.pressure_air_regulated}, - "pressure_o2_supply" : {self.pressure_o2_supply}, - "pressure_o2_regulated" : {self.pressure_o2_regulated}, - "pressure_buffer" : {self.pressure_buffer}, - "pressure_inhale" : {self.pressure_inhale}, - "pressure_patient" : {self.pressure_patient}, - "temperature_buffer" : {self.temperature_buffer}, - "pressure_diff_patient" : {self.pressure_diff_patient}, - "readback_valve_air_in" : {self.readback_valve_air_in}, - "readback_valve_o2_in" : {self.readback_valve_o2_in}, - "readback_valve_inhale" : {self.readback_valve_inhale}, - "readback_valve_exhale" : {self.readback_valve_exhale}, - "readback_valve_purge" : {self.readback_valve_purge}, - "readback_mode" : {self.readback_mode} + "version" : {self._version}, + "fsm_state" : {self._fsm_state}, + "pressure_air_supply" : {self._pressure_air_supply}, + "pressure_air_regulated" : {self._pressure_air_regulated}, + "pressure_o2_supply" : {self._pressure_o2_supply}, + "pressure_o2_regulated" : {self._pressure_o2_regulated}, + "pressure_buffer" : {self._pressure_buffer}, + "pressure_inhale" : {self._pressure_inhale}, + "pressure_patient" : {self._pressure_patient}, + "temperature_buffer" : {self._temperature_buffer}, + "pressure_diff_patient" : {self._pressure_diff_patient}, + "readback_valve_air_in" : {self._readback_valve_air_in}, + "readback_valve_o2_in" : {self._readback_valve_o2_in}, + "readback_valve_inhale" : {self._readback_valve_inhale}, + "readback_valve_exhale" : {self._readback_valve_exhale}, + "readback_valve_purge" : {self._readback_valve_purge}, + "readback_mode" : {self._readback_mode} }}""" # for receiving dataFormat from microcontroller # fill the struct from a byteArray, def fromByteArray(self, byteArray): - self.byteArray = byteArray - (self.version, - self.fsm_state, - self.pressure_air_supply, - self.pressure_air_regulated, - self.pressure_o2_supply, - self.pressure_o2_regulated, - self.pressure_buffer, - self.pressure_inhale, - self.pressure_patient, - self.temperature_buffer, - self.pressure_diff_patient, - self.readback_valve_air_in, - self.readback_valve_o2_in, - self.readback_valve_inhale, - self.readback_valve_exhale, - self.readback_valve_purge, - self.readback_mode) = self.dataStruct.unpack(self.byteArray) + self._byteArray = byteArray + (self._version, + self._fsm_state, + self._pressure_air_supply, + self._pressure_air_regulated, + self._pressure_o2_supply, + self._pressure_o2_regulated, + self._pressure_buffer, + self._pressure_inhale, + self._pressure_patient, + self._temperature_buffer, + self._pressure_diff_patient, + self._readback_valve_air_in, + self._readback_valve_o2_in, + self._readback_valve_inhale, + self._readback_valve_exhale, + self._readback_valve_purge, + self._readback_mode) = self._dataStruct.unpack(self._byteArray) # for sending dataFormat to microcontroller @@ -121,47 +129,47 @@ class dataFormat(BaseFormat): # to the microcontroller def toByteArray(self): # since pi is sender - self.version = self.RPI_VERSION - - self.byteArray = self.dataStruct.pack( - self.RPI_VERSION, - self.fsm_state, - self.pressure_air_supply, - self.pressure_air_regulated, - self.pressure_o2_supply, - self.pressure_o2_regulated, - self.pressure_buffer, - self.pressure_inhale, - self.pressure_patient, - self.temperature_buffer, - self.pressure_diff_patient, - self.readback_valve_air_in, - self.readback_valve_o2_in, - self.readback_valve_inhale, - self.readback_valve_exhale, - self.readback_valve_purge, - self.readback_mode + self._version = self._RPI_VERSION + + self._byteArray = self._dataStruct.pack( + self._RPI_VERSION, + self._fsm_state, + self._pressure_air_supply, + self._pressure_air_regulated, + self._pressure_o2_supply, + self._pressure_o2_regulated, + self._pressure_buffer, + self._pressure_inhale, + self._pressure_patient, + self._temperature_buffer, + self._pressure_diff_patient, + self._readback_valve_air_in, + self._readback_valve_o2_in, + self._readback_valve_inhale, + self._readback_valve_exhale, + self._readback_valve_purge, + self._readback_mode ) def getDict(self): data = { - "version" : self.version, - "fsm_state" : self.fsm_state, - "pressure_air_supply" : self.pressure_air_supply, - "pressure_air_regulated" : self.pressure_air_regulated, - "pressure_o2_supply" : self.pressure_o2_supply, - "pressure_o2_regulated" : self.pressure_o2_regulated, - "pressure_buffer" : self.pressure_buffer, - "pressure_inhale" : self.pressure_inhale, - "pressure_patient" : self.pressure_patient, - "temperature_buffer" : self.temperature_buffer, - "pressure_diff_patient" : self.pressure_diff_patient, - "readback_valve_air_in" : self.readback_valve_air_in, - "readback_valve_o2_in" : self.readback_valve_o2_in, - "readback_valve_inhale" : self.readback_valve_inhale, - "readback_valve_exhale" : self.readback_valve_exhale, - "readback_valve_purge" : self.readback_valve_purge, - "readback_mode" : self.readback_mode + "version" : self._version, + "fsm_state" : self._fsm_state, + "pressure_air_supply" : self._pressure_air_supply, + "pressure_air_regulated" : self._pressure_air_regulated, + "pressure_o2_supply" : self._pressure_o2_supply, + "pressure_o2_regulated" : self._pressure_o2_regulated, + "pressure_buffer" : self._pressure_buffer, + "pressure_inhale" : self._pressure_inhale, + "pressure_patient" : self._pressure_patient, + "temperature_buffer" : self._temperature_buffer, + "pressure_diff_patient" : self._pressure_diff_patient, + "readback_valve_air_in" : self._readback_valve_air_in, + "readback_valve_o2_in" : self._readback_valve_o2_in, + "readback_valve_inhale" : self._readback_valve_inhale, + "readback_valve_exhale" : self._readback_valve_exhale, + "readback_valve_purge" : self._readback_valve_purge, + "readback_mode" : self._readback_mode } return data @@ -171,26 +179,26 @@ class dataFormat(BaseFormat): class commandFormat(BaseFormat): def __init__(self): super().__init__() - self.dataStruct = Struct("!BBI") - self.byteArray = None + self._dataStruct = Struct("!BBI") + self._byteArray = None self._type = payloadType.payloadCmd - self.version = 0 - self.cmdCode = 0 - self.param = 0 + self._version = 0 + self._cmdCode = 0 + self._param = 0 def fromByteArray(self, byteArray): - self.byteArray = byteArray - (self.version, - self.cmdCode, - self.param) = self.dataStruct.unpack(self.byteArray) + self._byteArray = byteArray + (self._version, + self._cmdCode, + self._param) = self._dataStruct.unpack(self._byteArray) def toByteArray(self): # since pi is sender - self.byteArray = self.dataStruct.pack( - self.RPI_VERSION, - self.cmdCode, - self.param + self._byteArray = self._dataStruct.pack( + self._RPI_VERSION, + self._cmdCode, + self._param ) class command_codes(Enum): @@ -203,25 +211,25 @@ class command_codes(Enum): class alarmFormat(BaseFormat): def __init__(self): super().__init__() - self.dataStruct = Struct("!BBI") - self.byteArray = None + self._dataStruct = Struct("!BBI") + self._byteArray = None self._type = payloadType.payloadAlarm - self.version = 0 - self.alarmCode = 0 - self.param = 0 + self._version = 0 + self._alarmCode = 0 + self._param = 0 def fromByteArray(self, byteArray): - self.byteArray = byteArray - (self.version, - self.alarmCode, - self.param) = self.dataStruct.unpack(self.byteArray) + self._byteArray = byteArray + (self._version, + self._alarmCode, + self._param) = self._dataStruct.unpack(self._byteArray) def toByteArray(self): - self.byteArray = self.dataStruct.pack( - self.RPI_VERSION, - self.alarmCode, - self.param + self._byteArray = self._dataStruct.pack( + self._RPI_VERSION, + self._alarmCode, + self._param ) class alarm_codes(Enum): diff --git a/raspberry-dataserver/commsControl.py b/raspberry-dataserver/commsControl.py index e664cab94965df9fa95e5454cda2d0c00cc4d77d..291a7ea5d39496f087b83416bd9e46f43899354c 100644 --- a/raspberry-dataserver/commsControl.py +++ b/raspberry-dataserver/commsControl.py @@ -22,34 +22,34 @@ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %( class commsControl(): def __init__(self, port, baudrate = 115200, queueSizeReceive = 16, queueSizeSend = 16): - self.serial_ = None + self._serial = None self.openSerial(port, baudrate) # send queues are FIFO ring-buffers of the defined size - self.alarms_ = deque(maxlen = queueSizeSend) - self.commands_ = deque(maxlen = queueSizeSend) - self.data_ = deque(maxlen = queueSizeSend) + self._alarms = deque(maxlen = queueSizeSend) + self._commands = deque(maxlen = queueSizeSend) + self._data = deque(maxlen = queueSizeSend) # received queue and observers to be notified on update - self.payloadrecv_ = deque(maxlen = queueSizeReceive) - self.observers_ = [] + self._payloadrecv = deque(maxlen = queueSizeReceive) + self._observers = [] # needed to find packet frames - self.received_ = [] - self.foundStart_ = False - self.timeLastTransmission_ = int(round(time.time() * 1000)) + self._received = [] + self._foundStart = False + self._timeLastTransmission = int(round(time.time() * 1000)) # packet counter checker - self.sequenceSend_ = 0 - self.sequenceReceive_ = 0 + self._sequenceSend = 0 + self._sequenceReceive = 0 # initialize of the multithreading - self.lock_ = threading.Lock() - self.receiving_ = True + self._lock = threading.Lock() + self._receiving = True receivingWorker = threading.Thread(target=self.receiver, daemon=True) receivingWorker.start() - self.sending_ = True + self._sending = True self._datavalid = threading.Event() # callback for send process self._dvlock = threading.Lock() # make callback threadsafe sendingWorker = threading.Thread(target=self.sender, daemon=True) @@ -58,51 +58,51 @@ class commsControl(): # open serial port def openSerial(self, port, baudrate = 115200, timeout = 2): if port is not None: - self.serial_ = serial.Serial(port = port, baudrate=baudrate, timeout = timeout) + self._serial = serial.Serial(port = port, baudrate=baudrate, timeout = timeout) else: try: - self.serial_.close() + self._serial.close() except: logging.warning("Serial device not open") - self.serial_ = None + self._serial = None def sender(self): - while self.sending_: + while self._sending: self._datavalid.wait() - if self.serial_ is not None: - if not self.serial_.in_waiting > 0: - self.sendQueue(self.alarms_ , 10) - self.sendQueue(self.commands_, 50) - self.sendQueue(self.data_ , 200) + if self._serial is not None: + if not self._serial.in_waiting > 0: + self.sendQueue(self._alarms , 10) + self.sendQueue(self._commands, 50) + self.sendQueue(self._data , 200) with self._dvlock: self._datavalid.clear() def receiver(self): - while self.receiving_: - if self.serial_ is not None: - if self.serial_.in_waiting > 0: - with self.lock_: + while self._receiving: + if self._serial is not None: + if self._serial.in_waiting > 0: + with self._lock: logging.debug("Receiving data...") - data = self.serial_.read(self.serial_.in_waiting) + data = self._serial.read(self._serial.in_waiting) self.processPacket(data) def sendQueue(self, queue, timeout): if len(queue) > 0: logging.debug(f'Queue length: {len(queue)}') currentTime = int(round(time.time() * 1000)) - if currentTime > (self.timeLastTransmission_ + timeout): - with self.lock_: - self.timeLastTransmission_ = currentTime - queue[0].setSequenceSend(self.sequenceSend_) + if currentTime > (self._timeLastTransmission + timeout): + with self._lock: + self._timeLastTransmission = currentTime + queue[0].setSequenceSend(self._sequenceSend) self.sendPacket(queue[0]) def getQueue(self, payloadType): if payloadType == commsConstants.payloadType.payloadAlarm: - return self.alarms_ + return self._alarms elif payloadType == commsConstants.payloadType.payloadCmd: - return self.commands_ + return self._commands elif payloadType == commsConstants.payloadType.payloadData: - return self.data_ + return self._data else: return None @@ -122,21 +122,21 @@ class commsControl(): byte = bytes([byte]) # TODO: this could be written in more pythonic way # force read byte by byte - self.received_.append(byte) + self._received.append(byte) # logging.debug(byte) # find starting flag of the packet - if not self.foundStart_ and byte == bytes([0x7E]): - self.foundStart_ = True - self.receivedStart_ = len(self.received_) + if not self._foundStart and byte == bytes([0x7E]): + self._foundStart = True + self._receivedStart = len(self._received) # find ending flag of the packet elif byte == bytes([0x7E]) : - decoded = self.decoder(self.received_, self.receivedStart_) + decoded = self.decoder(self._received, self._receivedStart) if decoded is not None: logging.debug(binascii.hexlify(decoded)) tmpComms = commsFormat.commsFromBytes(decoded) if tmpComms.compareCrc(): control = tmpComms.getData()[tmpComms.getControl()+1] - self.sequenceReceive_ = (tmpComms.getData()[tmpComms.getControl()] >> 1) & 0x7F + self._sequenceReceive = (tmpComms.getData()[tmpComms.getControl()] >> 1) & 0x7F # get type of payload and corresponding queue payloadType = self.getInfoType(tmpComms.getData()[tmpComms.getAddress()]) @@ -166,10 +166,10 @@ class commsControl(): commsResponse.setSequenceReceive(sequenceReceive) self.sendPacket(commsResponse) - self.received_.clear() + self._received.clear() - self.foundStart_ = False - self.receivedStart_ = -1 + self._foundStart = False + self._receivedStart = -1 def writePayload(self, payload): payloadType = payload.getType() @@ -193,14 +193,14 @@ class commsControl(): def sendPacket(self, comms): logging.debug("Sending data...") logging.debug(binascii.hexlify(self.encoder(comms.getData()))) - self.serial_.write(self.encoder(comms.getData())) + self._serial.write(self.encoder(comms.getData())) def finishPacket(self, queue): try: if len(queue) > 0: # 0x7F to deal with possible overflows (0 should follow after 127) - if ((queue[0].getSequenceSend() + 1) & 0x7F) == self.sequenceReceive_: - self.sequenceSend_ = (self.sequenceSend_ + 1) % 128 + if ((queue[0].getSequenceSend() + 1) & 0x7F) == self._sequenceReceive: + self._sequenceSend = (self._sequenceSend + 1) % 128 queue.popleft() except: logging.debug("Queue is probably empty") @@ -252,27 +252,27 @@ class commsControl(): # callback to dependants to read the received payload @property def payloadrecv(self): - return self.payloadrecv_ + return self._payloadrecv @payloadrecv.setter def payloadrecv(self, payload): - self.payloadrecv_.append(payload) + self._payloadrecv.append(payload) logging.debug(f"Pushed {payload} to FIFO") - for callback in self.observers_: + for callback in self._observers: # peek at the leftmost item, don't pop until receipt confirmed - callback(self.payloadrecv_[0]) + callback(self._payloadrecv[0]) def bind_to(self, callback): - self.observers_.append(callback) + self._observers.append(callback) def pop_payloadrecv(self): # from callback. confirmed receipt, pop value - poppedval = self.payloadrecv_.popleft() + poppedval = self._payloadrecv.popleft() logging.debug(f"Popped {poppedval} from FIFO") - if len(self.payloadrecv_) > 0: + if len(self._payloadrecv) > 0: # purge full queue if Dependant goes down when it comes back up - for callback in self.observers_: - callback(self.payloadrecv_[0]) + for callback in self._observers: + callback(self._payloadrecv[0]) if __name__ == "__main__" : # example dependant diff --git a/raspberry-dataserver/commsFormat.py b/raspberry-dataserver/commsFormat.py index 55abb02b79597fa6192149194498d9c5f36311c7..f483ee29709b94bd461860f33b5b4fe99505cfad 100644 --- a/raspberry-dataserver/commsFormat.py +++ b/raspberry-dataserver/commsFormat.py @@ -30,9 +30,9 @@ def generateData(payload): # basic format based on HDLC class commsFormat: def __init__(self, infoSize = 0, address = 0x00, control = [0x00, 0x00]): - self.data_ = bytearray(7 + infoSize) - self.infoSize_ = infoSize - self.crc_ = None + self._data = bytearray(7 + infoSize) + self._infoSize = infoSize + self._crc = None self.assignBytes(self.getStart() , bytes([0x7E]) , calcCrc = False) self.assignBytes(self.getAddress(), bytes([address]), calcCrc = False) @@ -50,11 +50,11 @@ class commsFormat: def getInformation(self): return 4 def getFcs(self): - return 4 + self.infoSize_ + return 4 + self._infoSize def getStop(self): - return 4 + self.infoSize_ + 2 + return 4 + self._infoSize + 2 - def setAddress(self, adddress): + def setAddress(self, address): self.assignBytes(self.getAddress(), bytes([address]), 1) def setControl(self, control): @@ -66,7 +66,7 @@ class commsFormat: def setSequenceSend(self, value): # sequence sent valid only for info frames (not supervisory ACK/NACK) - if (self.data_[self.getControl() + 1] & 0x01) == 0: + if (self._data[self.getControl() + 1] & 0x01) == 0: value = (value << 1) & 0xFE self.assignBytes(self.getControl() + 1, value.to_bytes(1, byteorder='little'), 1) @@ -76,41 +76,41 @@ class commsFormat: def getSequenceSend(self): # sequence sent valid only for info frames (not supervisory ACK/NACK) - if (self.data_[self.getControl() + 1] & 0x01) == 0: - return (self.data_[self.getControl() + 1] >> 1) & 0x7F + if (self._data[self.getControl() + 1] & 0x01) == 0: + return (self._data[self.getControl() + 1] >> 1) & 0x7F else: return 0xFF def getSequenceReceive(self): - return (self.data_[self.getControl()] >> 1) & 0x7F + return (self._data[self.getControl()] >> 1) & 0x7F def assignBytes(self, start, values, calcCrc = True): for idx in range(len(values)): - self.data_[start + idx] = values[idx] + self._data[start + idx] = values[idx] if calcCrc: self.generateCrc() # generate checksum def generateCrc(self, assign = True): - self.crc_ = libscrc.x25(bytes(self.data_[self.getAddress():self.getFcs()])).to_bytes(2, byteorder='little') + self._crc = libscrc.x25(bytes(self._data[self.getAddress():self.getFcs()])).to_bytes(2, byteorder='little') if assign: - self.assignBytes(self.getFcs(), self.crc_, calcCrc = False) + self.assignBytes(self.getFcs(), self._crc, calcCrc = False) def compareCrc(self): self.generateCrc(False) fcs = self.getData()[self.getFcs():self.getFcs()+2] - return self.crc_ in fcs + return self._crc in fcs def getData(self): - return self.data_ + return self._data def copyData(self, dataArray): - self.copyBytes(dataArray.to_bytes(self.infoSize_, byteorder='little')) + self.copyBytes(dataArray.to_bytes(self._infoSize, byteorder='little')) def copyBytes(self, bytesArray): - self.infoSize_ = len(bytesArray) - 7 - self.data_ = bytesArray + self._infoSize = len(bytesArray) - 7 + self._data = bytesArray # ACK specific formating class commsACK(commsFormat):