diff --git a/arduino/protocol/lib/commsControl/commsConstants.h b/arduino/protocol/lib/commsControl/commsConstants.h index 03b7a83eea5b28bff11b75141918d2624bbe79b7..44e51f2691394ce37aacb6e52a0542f889356eb8 100644 --- a/arduino/protocol/lib/commsControl/commsConstants.h +++ b/arduino/protocol/lib/commsControl/commsConstants.h @@ -4,7 +4,7 @@ #include <Arduino.h> #define CONST_TIMEOUT_ALARM 5 -#define CONST_TIMEOUT_DATA 5000 +#define CONST_TIMEOUT_DATA 10 #define CONST_TIMEOUT_CMD 50 @@ -31,25 +31,43 @@ #define PACKET_DATA 0x40 #define PACKET_SET 0x20 //set vs get ? -// TODO: make sensible -#define PRESSURE_PEEP_LOW 0x01 -#define PRESSURE_PEEP_HIGH 0x02 +#define HEV_FORMAT_VERSION 0xA0 + +enum command_codes {CMD_START = 1, + CMD_STOP = 2}; // struct for all data sent struct dataFormat { - uint8_t version; - uint8_t size = 3; - uint8_t count = 0; + uint8_t version = HEV_FORMAT_VERSION; // + uint8_t fsm_state = 0; + uint16_t pressure_air_supply = 0; + uint16_t pressure_air_regulated = 0; + uint16_t pressure_o2_supply = 0; + uint16_t pressure_o2_regulated = 0; + uint16_t pressure_buffer = 0; + uint16_t pressure_inhale = 0; + uint16_t pressure_patient = 0; + uint16_t temperature_buffer = 0; + uint16_t pressure_diff_patient = 0; + uint8_t readback_valve_air_in = 0; + uint8_t readback_valve_o2_in = 0; + uint8_t readback_valve_inhale = 0; + uint8_t readback_valve_exhale = 0; + uint8_t readback_valve_purge = 0; + uint8_t readback_mode = 0; }; struct cmdFormat { - uint8_t version; - uint8_t size = 2; + uint8_t version = HEV_FORMAT_VERSION; // + uint8_t cmdCode = 0; + uint32_t param = 0; }; -struct alarmFormat { - uint8_t version; - uint8_t size = 2; +struct alarmFormat{ + uint8_t version = HEV_FORMAT_VERSION; // + uint8_t alarmCode = 0; + uint32_t param = 0; + // do we do the same as dataFormat and put all alarms in one message? }; // enum of all transfer types @@ -65,28 +83,44 @@ enum payloadType { // information is set as information in the protocol class payload { public: - payload(payloadType type = payloadType::payloadUnset) {type_ = type; data_ = nullptr; cmd_ = nullptr; alarm_ = nullptr; } - ~payload() {unsetData(); unsetAlarm(); unsetCmd();} + payload(payloadType type = payloadType::payloadUnset) {type_ = type; } //data_ = nullptr; cmd_ = nullptr; alarm_ = nullptr; } + payload(const payload &other) { +// unsetAll(); + type_ = other.type_; + /*if ( other. data_ != nullptr) { data_ = new dataFormat;*/ memcpy(& data_, & other.data_, sizeof( dataFormat));// } else { data_ = nullptr; } + /*if ( other. cmd_ != nullptr) { cmd_ = new cmdFormat;*/ memcpy(& cmd_, & other.cmd_, sizeof( cmdFormat));// } else { cmd_ = nullptr; } + /*if ( other.alarm_ != nullptr) { alarm_ = new alarmFormat;*/ memcpy(&alarm_, &other.alarm_, sizeof(alarmFormat));// } else {alarm_ = nullptr; } + } + payload& operator=(const payload& other) { +// unsetAll(); + type_ = other.type_; + /*if ( other. data_ != nullptr) { data_ = new dataFormat;*/ memcpy(& data_, & other.data_, sizeof( dataFormat));// } else { data_ = nullptr; } + /*if ( other. cmd_ != nullptr) { cmd_ = new cmdFormat;*/ memcpy(& cmd_, & other.cmd_, sizeof( cmdFormat));// } else { cmd_ = nullptr; } + /*if ( other.alarm_ != nullptr) { alarm_ = new alarmFormat;*/ memcpy(&alarm_, &other.alarm_, sizeof(alarmFormat));// } else {alarm_ = nullptr; } + + return *this; + } + + ~payload() {;}//unsetData(); unsetAlarm(); unsetCmd();} void setType(payloadType type) { type_ = type; } payloadType getType() {return type_; } // requires argument as new struct - void setData (dataFormat *data) { unsetAll(); data_ = new dataFormat; memcpy( data_, data, data->size); } - void setCmd (cmdFormat *cmd) { unsetAll(); cmd_ = new cmdFormat; memcpy( cmd_, cmd, cmd->size); } - void setAlarm(alarmFormat *alarm) { unsetAll(); alarm_ = new alarmFormat; memcpy(alarm_, alarm, alarm->size); } + void setData (dataFormat *data) { /*unsetAll(); type_ = payloadType::payloadData; data_ = new dataFormat( *data); }*/ memcpy(& data_, data, sizeof( dataFormat)); } + void setCmd (cmdFormat *cmd) { /*unsetAll(); type_ = payloadType::payloadCmd; cmd_ = new cmdFormat( *cmd); }*/ memcpy(& cmd_, cmd, sizeof( cmdFormat)); } + void setAlarm(alarmFormat *alarm) { /*unsetAll(); type_ = payloadType::payloadAlarm; alarm_ = new alarmFormat( *alarm); }*/ memcpy(&alarm_, alarm, sizeof(alarmFormat)); } - dataFormat *getData () {return data_; } - cmdFormat *getCmd () {return cmd_; } - alarmFormat *getAlarm() {return alarm_; } + dataFormat *getData () {return &data_; } + cmdFormat *getCmd () {return &cmd_; } + alarmFormat *getAlarm() {return &alarm_; } - void unsetAll() { unsetData(); unsetAlarm(); unsetCmd(); } - void unsetData() { if ( data_ != nullptr) { delete data_; data_ = nullptr; } } - void unsetCmd() { if ( cmd_ != nullptr) { delete cmd_; cmd_ = nullptr; } } - void unsetAlarm() { if (alarm_ != nullptr) { delete alarm_; alarm_ = nullptr; } } +// void unsetAll() { unsetData(); unsetAlarm(); unsetCmd(); type_ = payloadType::payloadUnset; } +// void unsetData() { if ( data_ != nullptr) { delete data_; data_ = nullptr; } } +// void unsetCmd() { if ( cmd_ != nullptr) { delete cmd_; cmd_ = nullptr; } } +// void unsetAlarm() { if (alarm_ != nullptr) { delete alarm_; alarm_ = nullptr; } } void setPayload(payloadType type, void* dt) { - setType(type); switch (type) { case payloadType::payloadData: setData(reinterpret_cast<dataFormat*>(dt)); @@ -119,11 +153,11 @@ public: uint8_t getInformationSize() { switch (type_) { case payloadType::payloadData: - return getData()->size; + return static_cast<uint8_t>(sizeof( dataFormat)); case payloadType::payloadCmd: - return getCmd()->size; + return static_cast<uint8_t>(sizeof( cmdFormat)); case payloadType::payloadAlarm: - return getAlarm()->size; + return static_cast<uint8_t>(sizeof(alarmFormat)); default: return 0; } @@ -132,9 +166,9 @@ public: private: payloadType type_; - dataFormat *data_; - cmdFormat *cmd_; - alarmFormat *alarm_; + dataFormat data_; + cmdFormat cmd_; + alarmFormat alarm_; }; #endif diff --git a/arduino/protocol/lib/commsControl/commsControl.cpp b/arduino/protocol/lib/commsControl/commsControl.cpp index 86c7570df6c608075484654af5d8c09a14f6fc95..62a8938585c98a0e2c2e25c55d795e5a51cdd256 100644 --- a/arduino/protocol/lib/commsControl/commsControl.cpp +++ b/arduino/protocol/lib/commsControl/commsControl.cpp @@ -19,7 +19,7 @@ commsControl::commsControl(uint32_t baudrate) { queueData_ = new RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING>(); queueCmd_ = new RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING>(); - queueReceived_ = new RingBuf<payload *, CONST_MAX_SIZE_RB_RECEIVING>(); + queueReceived_ = new RingBuf<payload, CONST_MAX_SIZE_RB_RECEIVING>(); commsTmp_ = commsFormat(CONST_MAX_SIZE_PACKET - CONST_MIN_SIZE_PACKET ); @@ -135,45 +135,44 @@ void commsControl::receiver() { } } -bool commsControl::writePayload(payload *pl) { +bool commsControl::writePayload(payload &pl) { commsFormat* tmpComms; + payloadType type = pl.getType(); // switch on different received payload types // TODO simplify the static functions - switch(pl->getType()) { + switch(type) { case payloadAlarm: - tmpComms = commsFormat::generateALARM(pl); + tmpComms = commsFormat::generateALARM(&pl); break; case payloadData: - tmpComms = commsFormat::generateDATA(pl); + tmpComms = commsFormat::generateDATA(&pl); break; case payloadCmd: - tmpComms = commsFormat::generateCMD(pl); + tmpComms = commsFormat::generateCMD(&pl); break; default: return false; } + RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *tmpQueue = getQueue(&type); // add new entry to the queue - if (queueData_->isFull()) { + if (tmpQueue->isFull()) { commsFormat *tmpCommsRm; - if (queueData_->pop(tmpCommsRm)) { + if (tmpQueue->pop(tmpCommsRm)) { delete tmpCommsRm; } } - if (queueData_->push(tmpComms) ) { + if (tmpQueue->push(tmpComms) ) { return true; } return false; } -bool commsControl::readPayload( payload* pl) { +bool commsControl::readPayload( payload &pl) { if ( !queueReceived_->isEmpty()) { - payload *tmpPl; - if (queueReceived_->pop(tmpPl)) { - memcpy(pl, tmpPl, sizeof(payload)); - delete tmpPl; + if (queueReceived_->pop(pl)) { return true; } } @@ -259,9 +258,8 @@ void commsControl::resendPacket(RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING // receiving anything of commsFormat -// TODO remove address and use commsTmp only bool commsControl::receivePacket(payloadType *type) { - payload *tmpPl = new payload(*type); + payload tmpPl = payload(*type); void *tmpInformation = nullptr; switch (*type) { @@ -282,13 +280,12 @@ bool commsControl::receivePacket(payloadType *type) { return false; } memcpy(tmpInformation, commsTmp_.getInformation(), commsTmp_.getInfoSize()); - tmpPl->setPayload(*type, tmpInformation); + tmpPl.setPayload(*type, tmpInformation); // remove first entry if RB is full if (queueReceived_->isFull()) { - payload *tmpDataRm = nullptr; - if (queueReceived_->pop(tmpDataRm)) { - delete tmpDataRm; + payload tmpPlRm; + if (queueReceived_->pop(tmpPlRm)) { } } diff --git a/arduino/protocol/lib/commsControl/commsControl.h b/arduino/protocol/lib/commsControl/commsControl.h index e04178845cd027df1d57c7e8a7cefb56e38dcfda..789f360585a89a886a8a022e01a2faef831622f5 100644 --- a/arduino/protocol/lib/commsControl/commsControl.h +++ b/arduino/protocol/lib/commsControl/commsControl.h @@ -19,8 +19,8 @@ public: void beginSerial(); - bool writePayload(payload *pl); - bool readPayload (payload *pl); + bool writePayload(payload &pl); + bool readPayload (payload &pl); void sender(); void receiver(); @@ -50,7 +50,7 @@ private: RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *queueData_; RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *queueCmd_; - RingBuf<payload *, CONST_MAX_SIZE_RB_RECEIVING> *queueReceived_; + RingBuf<payload, CONST_MAX_SIZE_RB_RECEIVING> *queueReceived_; commsFormat commsTmp_; diff --git a/arduino/protocol/lib/commsControl/commsFormat.cpp b/arduino/protocol/lib/commsControl/commsFormat.cpp index affb4200f9bbfb8aba9709c026e5b45bdd366ffa..b4951e597f8dc635810eb730d2d3f38bc7f38398 100644 --- a/arduino/protocol/lib/commsControl/commsFormat.cpp +++ b/arduino/protocol/lib/commsControl/commsFormat.cpp @@ -73,7 +73,6 @@ void commsFormat::generateCrc(bool assign) { // assign crc to fcs if (assign) { - ; assignBytes(getFcs(), reinterpret_cast<uint8_t*>(&crc_), 2, false); } } diff --git a/arduino/protocol/lib/commsControl/commsFormat.h b/arduino/protocol/lib/commsControl/commsFormat.h index ddfc6e3a73fd50cde0b073cf1874f46d82234e84..81b2ca47a1b1eb7b1facb952567ccc8638254771 100644 --- a/arduino/protocol/lib/commsControl/commsFormat.h +++ b/arduino/protocol/lib/commsControl/commsFormat.h @@ -14,6 +14,20 @@ class commsFormat { public: commsFormat(uint8_t infoSize = 0, uint8_t address = 0x00, uint16_t control = 0x0000); + commsFormat(const commsFormat& other) { + crc_ = other.crc_; + packetSize_ = other.packetSize_; + infoSize_ = other.infoSize_; + memcpy(data_, other.data_, CONST_MAX_SIZE_PACKET); + } + commsFormat& operator=(const commsFormat& other) { + crc_ = other.crc_; + packetSize_ = other.packetSize_; + infoSize_ = other.infoSize_; + memcpy(data_, other.data_, CONST_MAX_SIZE_PACKET); + + return *this; + } uint8_t* getData() { return data_; } uint8_t getSize() { return packetSize_; } diff --git a/arduino/protocol/src/protocol.cpp b/arduino/protocol/src/protocol.cpp index da9d4dc624a0c80d28a69da540df2ff51b9297b3..3b94233029e10c58fa7698e42781c8af40e63a32 100644 --- a/arduino/protocol/src/protocol.cpp +++ b/arduino/protocol/src/protocol.cpp @@ -11,82 +11,96 @@ payload plReceive_; payload plSend_; commsControl comms_; dataFormat data_; +alarmFormat alarm_; -int currentState = 0; -int previousState = 0; +int currentState_ = 0; +int previousState_ = 0; -int led = 0; -bool blue = false; -bool green = false; -bool red = false; +int led_ = 0; +bool blue_ = false; +bool green_ = false; +bool red_ = false; // dirty function to switch one of the LEDs void switchLED(int led) { - int state = HIGH; - switch (led) { - case LED_BLUE: - if (blue) - state = LOW; - blue = !blue; - break; - case LED_RED: - if (red) - state = LOW; - red = !red; - break; - case LED_GREEN: - if (green) - state = LOW; - green = !green; - break; - } - digitalWrite(led, state); + int state = HIGH; + switch (led) { + case LED_BLUE: + if (blue_) + state = LOW; + blue_ = !blue_; + break; + case LED_RED: + if (red_) + state = LOW; + red_ = !red_; + break; + case LED_GREEN: + if (green_) + state = LOW; + green_ = !green_; + break; + } + digitalWrite(led, state); } void setup() { - plSend_.setType(payloadType::payloadData); + plSend_.setType(payloadType::payloadData); - // initialize digital pin LED_BUILTIN as an output. - pinMode(LED_BLUE, OUTPUT); - pinMode(LED_GREEN, OUTPUT); - pinMode(LED_RED, OUTPUT); + // initialize digital pin LED_BUILTIN as an output. + pinMode(LED_BLUE, OUTPUT); + pinMode(LED_GREEN, OUTPUT); + pinMode(LED_RED, OUTPUT); - pinMode(BTN, INPUT); + pinMode(BTN, INPUT); - // initialize comms connection - comms_.beginSerial(); + // initialize comms connection + comms_.beginSerial(); } void loop() { - // testing increase of values to be sent - // will only increase the count on the button release (reasons) - currentState = digitalRead(BTN); - if ( currentState != previousState){ - if (currentState != HIGH) { - switchLED(LED_BLUE); - // counter increase on button press - data_.count += 1; - plSend_.setData(&data_); - // register new data in comms - comms_.writePayload(&plSend_); + // testing increase of values to be sent + // will only increase the count on the button release (reasons) + currentState_ = digitalRead(BTN); + if ( currentState_ != previousState_) { + if (currentState_ != HIGH) { + switchLED(LED_BLUE); + // counter increase on button press + data_.fsm_state += 1; + plSend_.setData(&data_); + // register new data in comms + comms_.writePayload(plSend_); + } + previousState_ = currentState_; } - previousState = currentState; - } - - // per cycle sender - comms_.sender(); - // per cycle receiver - comms_.receiver(); - - // per cycle data checker - the received entry is automatically removed from the buffer - if (comms_.readPayload(&plReceive_)) { - if (plReceive_.getType() == payloadType::payloadData) { - switchLED(plReceive_.getData()->count); - plReceive_.setType(payloadType::payloadUnset); - } - } - +// switchLED(LED_BLUE); + // counter increase on button press +// plSend_.getData()->fsm_state += 1; +// comms_.writePayload(plSend_); + + // per cycle sender + comms_.sender(); + // per cycle receiver + comms_.receiver(); + + // per cycle data checker - the received entry is automatically removed from the buffer + if (comms_.readPayload(plReceive_)) { + + switch (plReceive_.getType()) { + case payloadType::payloadCmd: + switchLED(plReceive_.getCmd()->cmdCode); + alarm_.alarmCode = plReceive_.getCmd()->cmdCode + 1; + plSend_.setAlarm(&alarm_); + comms_.writePayload(plSend_); + break; + default: + break; + } + + plReceive_.setType(payloadType::payloadUnset); + } + delay(50); } diff --git a/raspberry-dataserver/commsConstants.py b/raspberry-dataserver/commsConstants.py index 6043fdd07fc6618d4615230383ae7bbb5892eb2f..6a3eea3093f8a344b6319a5732eedc7c0c5ef9b5 100644 --- a/raspberry-dataserver/commsConstants.py +++ b/raspberry-dataserver/commsConstants.py @@ -1,6 +1,11 @@ from struct import Struct -from enum import Enum +from enum import Enum, auto +class payloadType(Enum): + payloadAlarm = auto() + payloadCmd = auto() + payloadData = auto() + payloadUnset = auto() # VERSIONING # change version in baseFormat for all data @@ -10,9 +15,10 @@ from enum import Enum class BaseFormat(): def __init__(self): self.RPI_VERSION = 0xA0 - self.rpi_size = 0 self.version = 0 - self.size = 0 + self.byteArray = None + self._type = payloadType.payloadUnset + # check for mismatch between pi and microcontroller version def checkVersion(self): if self.RPI_VERSION == self.version : @@ -20,15 +26,19 @@ class BaseFormat(): else : self.version_error = False - def checkSize(self): - if self.rpi_size == self.size: - self.version_error = True - else : - self.version_error = False + def getSize(self): + return len(self.byteArray) + + def getType(self): + return self._type + +# ======================================= +# data type payload +# ======================================= class dataFormat(BaseFormat): - # define the format here, including version and size + # define the format here, including version def __init__(self): super().__init__() # struct will set the num bytes per variable @@ -38,13 +48,13 @@ class dataFormat(BaseFormat): # < = little endian # > = big endian # ! = network format (big endian) - self.dataStruct = Struct("!BBBHHHHHHHHHBBBBBB") + self.dataStruct = Struct("!BBHHHHHHHHHBBBBBB") self.byteArray = None - self.rpi_size = 27 + self._type = payloadType.payloadData + # make all zero to start with self.version = 0 - self.size = 0 self.fsm_state = 0 self.pressure_air_supply = 0 self.pressure_air_regulated = 0 @@ -65,7 +75,6 @@ class dataFormat(BaseFormat): def __repr__(self): return f"""{{ "version" : {self.version}, - "size" : {self.size}, "fsm_state" : {self.fsm_state}, "pressure_air_supply" : {self.pressure_air_supply}, "pressure_air_regulated" : {self.pressure_air_regulated}, @@ -89,7 +98,6 @@ class dataFormat(BaseFormat): def fromByteArray(self, byteArray): self.byteArray = byteArray (self.version, - self.size, self.fsm_state, self.pressure_air_supply, self.pressure_air_regulated, @@ -114,11 +122,9 @@ class dataFormat(BaseFormat): def toByteArray(self): # since pi is sender self.version = self.RPI_VERSION - self.size = self.rpi_size self.byteArray = self.dataStruct.pack( self.RPI_VERSION, - self.rpi_size, self.fsm_state, self.pressure_air_supply, self.pressure_air_regulated, @@ -140,7 +146,6 @@ class dataFormat(BaseFormat): def getDict(self): data = { "version" : self.version, - "size" : self.size, "fsm_state" : self.fsm_state, "pressure_air_supply" : self.pressure_air_supply, "pressure_air_regulated" : self.pressure_air_regulated, @@ -160,22 +165,23 @@ class dataFormat(BaseFormat): } return data +# ======================================= +# cmd type payload +# ======================================= class commandFormat(BaseFormat): def __init__(self): super().__init__() - self.dataStruct = Struct("!BBBI") + self.dataStruct = Struct("!BBI") self.byteArray = None - self.rpi_size = 7 + self._type = payloadType.payloadCmd self.version = 0 - self.size = 0 self.cmdCode = 0 self.param = 0 def fromByteArray(self, byteArray): self.byteArray = byteArray (self.version, - self.size, self.cmdCode, self.param) = self.dataStruct.unpack(self.byteArray) @@ -183,38 +189,41 @@ class commandFormat(BaseFormat): # since pi is sender self.byteArray = self.dataStruct.pack( self.RPI_VERSION, - self.rpi_size, self.cmdCode, self.param - ) + ) + +class command_codes(Enum): + CMD_START = 1 + CMD_STOP = 2 +# ======================================= +# alarm type payload +# ======================================= class alarmFormat(BaseFormat): def __init__(self): super().__init__() - self.dataStruct = Struct("!BBBI") + self.dataStruct = Struct("!BBI") self.byteArray = None - self.rpi_size = 7 + self._type = payloadType.payloadAlarm self.version = 0 - self.size = 0 self.alarmCode = 0 self.param = 0 def fromByteArray(self, byteArray): self.byteArray = byteArray (self.version, - self.size, self.alarmCode, self.param) = self.dataStruct.unpack(self.byteArray) def toByteArray(self): self.byteArray = self.dataStruct.pack( self.RPI_VERSION, - self.rpi_size, self.alarmCode, self.param ) -class command_codes(Enum): - CMD_START = 1 - CMD_STOP = 2 +class alarm_codes(Enum): + ALARM_START = 1 + ALARM_STOP = 2 \ No newline at end of file diff --git a/raspberry-dataserver/commsControl.py b/raspberry-dataserver/commsControl.py index 362b9d2acd96dae1abf3e78508dcfb7aac95ea7d..eed16ae4219a187870576bff83022fec70bdb718 100644 --- a/raspberry-dataserver/commsControl.py +++ b/raspberry-dataserver/commsControl.py @@ -6,31 +6,33 @@ import serial from serial.tools import list_ports +import threading import time import commsFormat -from commsConstants import dataFormat +import commsConstants from collections import deque + +import binascii import logging -logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') -import threading # communication class that governs talking between devices class commsControl(): - def __init__(self, port, baudrate = 115200, queueSize = 16): + def __init__(self, port, baudrate = 115200, queueSizeReceive = 16, queueSizeSend = 16): self.serial_ = None self.openSerial(port, baudrate) # send queues are FIFO ring-buffers of the defined size - self.alarms_ = deque(maxlen = queueSize) - self.commands_ = deque(maxlen = queueSize) - self.data_ = deque(maxlen = queueSize) + 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 = queueSize) - self._observers = [] + self.payloadrecv_ = deque(maxlen = queueSizeReceive) + self.observers_ = [] # needed to find packet frames self.received_ = [] @@ -61,13 +63,13 @@ class commsControl(): try: self.serial_.close() except: - logging.warning("warning: device not open") + logging.warning("Serial device not open") self.serial_ = None def sender(self): while self.sending_: self._datavalid.wait() - if not self.serial_ is None: + if self.serial_ is not None: if not self.serial_.in_waiting > 0: self.sendQueue(self.alarms_ , 10) self.sendQueue(self.commands_, 50) @@ -77,56 +79,71 @@ class commsControl(): def receiver(self): while self.receiving_: - if not self.serial_ is None: + 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) - self.packetReceived(data) + 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_) - packet = queue.popleft() - self.sendPacket(packet) - logging.debug(f"Sent packet: {packet}") + self.sendPacket(queue[0]) - def getQueue(self, packetFlag): - if packetFlag == 0xC0: + def getQueue(self, payloadType): + if payloadType == commsConstants.payloadType.payloadAlarm: return self.alarms_ - elif packetFlag == 0x80: + elif payloadType == commsConstants.payloadType.payloadCmd: return self.commands_ - elif packetFlag == 0x40: + elif payloadType == commsConstants.payloadType.payloadData: return self.data_ else: return None + + def getInfoType(self, address): + address &= 0xC0 + if address == 0xC0: + return commsConstants.payloadType.payloadAlarm + elif address == 0x80: + return commsConstants.payloadType.payloadCmd + elif address == 0x40: + return commsConstants.payloadType.payloadData + else: + return commsConstants.payloadType.payloadUnset - def packetReceived(self, data): + def processPacket(self, data): for byte in data: byte = bytes([byte]) # TODO: this could be written in more pythonic way # force read byte by byte self.received_.append(byte) - logging.debug(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_) + # find ending flag of the packet elif byte == bytes([0x7E]) : decoded = self.decoder(self.received_, self.receivedStart_) if decoded is not None: - logging.debug(decoded) + logging.debug(binascii.hexlify(decoded)) tmpComms = commsFormat.commsFromBytes(decoded) if tmpComms.compareCrc(): - ctrlFlag = decoded[3] & 0x0F - packetFlag = decoded[1] & 0xC0 + control = tmpComms.getData()[tmpComms.getControl()+1] + self.sequenceReceive_ = (tmpComms.getData()[tmpComms.getControl()] >> 1) & 0x7F - self.sequenceReceive_ = (decoded[2] >> 1) & 0x7F - - tmpQueue = self.getQueue(packetFlag) + # get type of payload and corresponding queue + payloadType = self.getInfoType(tmpComms.getData()[tmpComms.getAddress()]) + tmpQueue = self.getQueue(payloadType) + + # get type of packet + ctrlFlag = control & 0x0F if ctrlFlag == 0x05: logging.debug("Received NACK") # received NACK @@ -135,16 +152,18 @@ class commsControl(): # received ACK self.finishPacket(tmpQueue) else: - # decode data + sequenceReceive = ((control >> 1) & 0x7F) + 1 + address = tmpComms.getData()[tmpComms.getAddress():tmpComms.getControl()] + payload = tmpComms.getData()[tmpComms.getInformation() : tmpComms.getFcs()] - # append to array - df = dataFormat() - df.fromByteArray(payload) - self.payloadrecv = df - # send ack - logging.debug("Preparing ACK") - commsResponse = commsFormat.commsACK(address = decoded[1]) - commsResponse.setSequenceReceive((decoded[3] >> 1) + 1) + + if self.receivePacket(payloadType, tmpComms): + logging.debug("Preparing ACK") + commsResponse = commsFormat.commsACK(address = address[0]) + else: + logging.debug("Preparing NACK") + commsResponse = commsFormat.commsNACK(address = address) + commsResponse.setSequenceReceive(sequenceReceive) self.sendPacket(commsResponse) self.received_.clear() @@ -152,16 +171,28 @@ class commsControl(): self.foundStart_ = False self.receivedStart_ = -1 - def registerData(self, value): - tmpData = commsFormat.commsDATA() - tmpData.setInformation(value) - self.data_.append(tmpData) + def writePayload(self, payload): + payloadType = payload.getType() + if payloadType == commsConstants.payloadType.payloadAlarm: + tmpComms = commsFormat.generateAlarm(payload) + elif payloadType == commsConstants.payloadType.payloadCmd: + tmpComms = commsFormat.generateCmd(payload) + elif payloadType == commsConstants.payloadType.payloadData: + tmpComms = commsFormat.generateData(payload) + else: + return False + tmpComms.setInformation(payload) + + tmpQueue = self.getQueue(payloadType) + tmpQueue.append(tmpComms) with self._dvlock: self._datavalid.set() + + return True def sendPacket(self, comms): logging.debug("Sending data...") - logging.debug(self.encoder(comms.getData())) + logging.debug(binascii.hexlify(self.encoder(comms.getData()))) self.serial_.write(self.encoder(comms.getData())) def finishPacket(self, queue): @@ -173,6 +204,20 @@ class commsControl(): queue.popleft() except: logging.debug("Queue is probably empty") + + def receivePacket(self, payloadType, commsPacket): + if payloadType == commsConstants.payloadType.payloadAlarm: + payload = commsConstants.alarmFormat() + elif payloadType == commsConstants.payloadType.payloadCmd: + payload = commsConstants.cmdFormat() + elif payloadType == commsConstants.payloadType.payloadData: + payload = commsConstants.dataFormat() + else: + return False + + payload.fromByteArray(commsPacket.getData()[commsPacket.getInformation():commsPacket.getFcs()]) + self.payloadrecv = payload + return True # escape any 0x7D or 0x7E with 0x7D and swap bit 5 def escapeByte(self, byte): @@ -203,31 +248,31 @@ class commsControl(): return result except: return None - + # 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): + def poppayloadrecv_(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 @@ -238,10 +283,10 @@ if __name__ == "__main__" : self._lli.bind_to(self.update_llipacket) def update_llipacket(self, payload): - logging.debug(f"payload received: {payload!r}") +# logging.debug(f"payload received: {payload!r}") self._llipacket = payload # pop from queue - protects against Dependant going down and not receiving packets - self._lli.pop_payloadrecv() + self._lli.poppayloadrecv_() # get port number for arduino, mostly for debugging for port in list_ports.comports(): @@ -253,15 +298,25 @@ if __name__ == "__main__" : commsCtrl = commsControl(port = port) example = Dependant(commsCtrl) + + payloadSend = commsConstants.commandFormat() + payloadSend.cmdCode = 3 + payloadSend.toByteArray() + + def burst(payload): + for i in range(16): + commsCtrl.writePayload(payload) + +# commsCtrl.writePayload(payloadSend) - commsCtrl.payloadrecv = "testpacket1" - commsCtrl.payloadrecv = "testpacket2" +# commsCtrl.payloadrecv = "testpacket1" +# commsCtrl.payloadrecv = "testpacket2" - LEDs = [3,5,7] - for _ in range(30): - for led in LEDs: - commsCtrl.registerData(led) - time.sleep(5) +# LEDs = [3,5,7] +# for _ in range(30): +# for led in LEDs: +# commsCtrl.registerData(led) +# time.sleep(5) - while True: - pass \ No newline at end of file +# while True: +# pass \ No newline at end of file diff --git a/raspberry-dataserver/commsFormat.py b/raspberry-dataserver/commsFormat.py index ba1034aaa604a634a5bade7c0956fb8b4f8f80fa..55abb02b79597fa6192149194498d9c5f36311c7 100644 --- a/raspberry-dataserver/commsFormat.py +++ b/raspberry-dataserver/commsFormat.py @@ -11,6 +11,22 @@ def commsFromBytes(byteArray): return comms +def generateAlarm(payload): + comms = commsFormat(infoSize = payload.getSize(), address = 0xC0) + comms.setInformation(payload) + return comms + +def generateCmd(payload): + comms = commsFormat(infoSize = payload.getSize(), address = 0x80) + comms.setInformation(payload) + return comms + +def generateData(payload): + comms = commsFormat(infoSize = payload.getSize(), address = 0x40) + comms.setInformation(payload) + return comms + + # basic format based on HDLC class commsFormat: def __init__(self, infoSize = 0, address = 0x00, control = [0x00, 0x00]): @@ -44,9 +60,9 @@ class commsFormat: def setControl(self, control): self.assignBytes(self.getControl(), bytes(control), 2) - def setInformation(self, value, size = 2): + def setInformation(self, payload): # convert provided value - self.assignBytes(self.getInformation(), value.to_bytes(size, byteorder='little')) + self.assignBytes(self.getInformation(), payload.byteArray) def setSequenceSend(self, value): # sequence sent valid only for info frames (not supervisory ACK/NACK) @@ -95,21 +111,6 @@ class commsFormat: def copyBytes(self, bytesArray): self.infoSize_ = len(bytesArray) - 7 self.data_ = bytesArray - -# DATA specific formating -class commsDATA(commsFormat): - def __init__(self): - super().__init__(infoSize = 8, address = 0x40) - -# CMD specific formating -class commsCMD(commsFormat): - def __init__(self): - super().__init__(infoSize = 8, address = 0x80) - -# ALARM specific formating -class commsALARM(commsFormat): - def __init__(self): - super().__init__(infoSize = 4, address = 0xC0) # ACK specific formating class commsACK(commsFormat):