From 63c5372cb7cfa5aefab854a4d1a86d8023f96ded Mon Sep 17 00:00:00 2001 From: Peter Svihra <peter.svihra@cern.ch> Date: Sat, 18 Apr 2020 18:11:01 +0200 Subject: [PATCH] refactor changes --- arduino/common/lib/CommsControl/CommsCommon.h | 179 ++++++++++ .../common/lib/CommsControl/CommsControl.h | 74 ++++ arduino/common/lib/CommsControl/CommsFormat.h | 76 +++++ .../common/lib/commsControl/commsConstants.h | 205 ----------- .../common/lib/commsControl/commsControl.cpp | 323 ------------------ .../common/lib/commsControl/commsControl.h | 74 ---- .../common/lib/commsControl/commsFormat.cpp | 111 ------ arduino/common/lib/commsControl/commsFormat.h | 76 ----- arduino/hev_prototype_v1/platformio.ini | 2 +- arduino/hev_prototype_v1/platformio.pro | 49 +++ .../hev_prototype_v1/src/BreathingLoop.cpp | 38 +-- arduino/hev_prototype_v1/src/BreathingLoop.h | 16 +- arduino/hev_prototype_v1/src/UILoop.cpp | 57 +++- arduino/hev_prototype_v1/src/UILoop.h | 13 +- arduino/hev_prototype_v1/src/common.cpp | 129 ++++++- arduino/hev_prototype_v1/src/common.h | 132 ++++++- arduino/hev_prototype_v1/src/main.cpp | 24 +- 17 files changed, 724 insertions(+), 854 deletions(-) create mode 100644 arduino/common/lib/CommsControl/CommsCommon.h create mode 100644 arduino/common/lib/CommsControl/CommsControl.h create mode 100644 arduino/common/lib/CommsControl/CommsFormat.h delete mode 100644 arduino/common/lib/commsControl/commsConstants.h delete mode 100644 arduino/common/lib/commsControl/commsControl.cpp delete mode 100644 arduino/common/lib/commsControl/commsControl.h delete mode 100644 arduino/common/lib/commsControl/commsFormat.cpp delete mode 100644 arduino/common/lib/commsControl/commsFormat.h create mode 100644 arduino/hev_prototype_v1/platformio.pro diff --git a/arduino/common/lib/CommsControl/CommsCommon.h b/arduino/common/lib/CommsControl/CommsCommon.h new file mode 100644 index 00000000..575a83cc --- /dev/null +++ b/arduino/common/lib/CommsControl/CommsCommon.h @@ -0,0 +1,179 @@ +#ifndef COMMSCONSTANTS_H +#define COMMSCONSTANTS_H + +#include <Arduino.h> + +#define CONST_TIMEOUT_ALARM 5 +#define CONST_TIMEOUT_DATA 10 +#define CONST_TIMEOUT_CMD 50 + + +#define CONST_MAX_SIZE_RB_RECEIVING 10 +#define CONST_MAX_SIZE_RB_SENDING 5 +#define CONST_MAX_SIZE_PACKET 64 +#define CONST_MAX_SIZE_BUFFER 128 +#define CONST_MIN_SIZE_PACKET 7 + +#define COMMS_FRAME_BOUNDARY 0x7E +#define COMMS_FRAME_ESCAPE 0x7D +#define COMMS_ESCAPE_BIT_SWAP 5 + +#define COMMS_CONTROL_INFORMATION 0x00 +#define COMMS_CONTROL_SUPERVISORY 0x01 + +#define COMMS_CONTROL_TYPES 0x0F +#define COMMS_CONTROL_ACK 0x00 | COMMS_CONTROL_SUPERVISORY +#define COMMS_CONTROL_NACK 0x04 | COMMS_CONTROL_SUPERVISORY + +#define PACKET_TYPE 0xC0 +#define PACKET_ALARM 0xC0 +#define PACKET_CMD 0x80 +#define PACKET_DATA 0x40 +#define PACKET_SET 0x20 //set vs get ? + +#define HEV_FORMAT_VERSION 0xA0 + +// struct for all data sent +struct data_format { + uint8_t version = HEV_FORMAT_VERSION; + uint32_t timestamp = 0; + 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 cmd_format { + uint8_t version = HEV_FORMAT_VERSION; + uint32_t timestamp = 0; + uint8_t cmd_type = 0; + uint8_t cmd_code = 0; + uint32_t param = 0; +}; + +struct alarm_format { + uint8_t version = HEV_FORMAT_VERSION; + uint32_t timestamp = 0; + uint8_t alarm_type = 0; + uint8_t alarm_code = 0; + uint32_t param = 0; +}; + +// enum of all transfer types +enum PAYLOAD_TYPE { + DATA, + CMD, + ALARM, + UNSET +}; + +// payload consists of type and information +// type is set as address in the protocol +// information is set as information in the protocol +class Payload { +public: + Payload(PAYLOAD_TYPE type = PAYLOAD_TYPE::UNSET) {type_ = type; } //data_ = nullptr; cmd_ = nullptr; alarm_ = nullptr; } + Payload(const Payload &other) { + type_ = other.type_; + memcpy(& data_, &other. data_, sizeof( data_format)); + memcpy(& cmd_, &other. cmd_, sizeof( cmd_format)); + memcpy(&alarm_, &other.alarm_, sizeof(alarm_format)); + } + Payload& operator=(const Payload& other) { + type_ = other.type_; + memcpy(& data_, &other. data_, sizeof( data_format)); + memcpy(& cmd_, &other. cmd_, sizeof( cmd_format)); + memcpy(&alarm_, &other.alarm_, sizeof(alarm_format)); + return *this; + } + + ~Payload() { unsetAll(); } + + void setType(PAYLOAD_TYPE type) { type_ = type; } + PAYLOAD_TYPE getType() {return type_; } + + // requires argument as new struct + void setData (data_format *data) { type_ = PAYLOAD_TYPE::DATA; memcpy(& data_, data, sizeof( data_format)); } + void setCmd (cmd_format *cmd) { type_ = PAYLOAD_TYPE::CMD; memcpy(& cmd_, cmd, sizeof( cmd_format)); } + void setAlarm(alarm_format *alarm) { type_ = PAYLOAD_TYPE::ALARM; memcpy(&alarm_, alarm, sizeof(alarm_format)); } + + // get pointers to particular payload types + data_format *getData () {return & data_; } + cmd_format *getCmd () {return & cmd_; } + alarm_format *getAlarm() {return &alarm_; } + + void unsetAll() { unsetData(); unsetAlarm(); unsetCmd(); type_ = PAYLOAD_TYPE::UNSET; } + void unsetData() { memset(& data_, 0, sizeof( data_format)); } + void unsetCmd() { memset(& cmd_, 0, sizeof( cmd_format)); } + void unsetAlarm() { memset(&alarm_, 0, sizeof(alarm_format)); } + + void setPayload(PAYLOAD_TYPE type, void* information) { + setType(type); + setInformation(information); + } + + void setInformation(void* information) { + switch (type_) { + case PAYLOAD_TYPE::DATA: + setData (reinterpret_cast< data_format*>(information)); + break; + case PAYLOAD_TYPE::CMD: + setCmd (reinterpret_cast< cmd_format*>(information)); + break; + case PAYLOAD_TYPE::ALARM: + setAlarm(reinterpret_cast<alarm_format*>(information)); + break; + default: + break; + } + } + + // returns void pointer, in case you know what to do with data or dont care what the format is + void *getInformation() { + switch (type_) { + case PAYLOAD_TYPE::DATA: + return reinterpret_cast<void*>(getData ()); + case PAYLOAD_TYPE::CMD: + return reinterpret_cast<void*>(getCmd ()); + case PAYLOAD_TYPE::ALARM: + return reinterpret_cast<void*>(getAlarm()); + default: + return nullptr; + } + } + + // returns payload information size + uint8_t getSize() { + switch (type_) { + case PAYLOAD_TYPE::DATA: + return static_cast<uint8_t>(sizeof( data_format)); + case PAYLOAD_TYPE::CMD: + return static_cast<uint8_t>(sizeof( cmd_format)); + case PAYLOAD_TYPE::ALARM: + return static_cast<uint8_t>(sizeof(alarm_format)); + default: + return 0; + } + } + +private: + PAYLOAD_TYPE type_; + + data_format data_; + cmd_format cmd_; + alarm_format alarm_; +}; + +#endif diff --git a/arduino/common/lib/CommsControl/CommsControl.h b/arduino/common/lib/CommsControl/CommsControl.h new file mode 100644 index 00000000..9bf60725 --- /dev/null +++ b/arduino/common/lib/CommsControl/CommsControl.h @@ -0,0 +1,74 @@ +#ifndef COMMS_CONTROL_H +#define COMMS_CONTROL_H + +// Communication protocol between rasp and arduino based on HDLC format +// author Peter Svihra <peter.svihra@cern.ch> + +#include <Arduino.h> +#include "RingBuf.h" + +#include "CommsCommon.h" +#include "CommsFormat.h" + +/////////////////////////////////////////////////////////////////////////// +// class to provide simple communication protocol based on the data format +class CommsControl { +public: + CommsControl(uint32_t baudrate = 115200); + ~CommsControl(); + + void beginSerial(); + + bool writePayload(Payload &pl); + bool readPayload (Payload &pl); + + void sender(); + void receiver(); + +private: + RingBuf<CommsFormat *,CONST_MAX_SIZE_RB_SENDING> *getQueue(PAYLOAD_TYPE &type); + PAYLOAD_TYPE getInfoType(uint8_t *address); + + void sendQueue (RingBuf<CommsFormat *, CONST_MAX_SIZE_RB_SENDING> *queue); + void resendPacket (RingBuf<CommsFormat *, CONST_MAX_SIZE_RB_SENDING> *queue); + bool receivePacket(PAYLOAD_TYPE &type); + void finishPacket (PAYLOAD_TYPE &type); + + bool encoder(uint8_t* payload, uint8_t dataSize); + bool decoder(uint8_t* payload, uint8_t dataStart, uint8_t dataStop); + + void sendPacket(CommsFormat* packet); + +private: + uint8_t _sequence_send; + uint8_t _sequence_receive; + + CommsFormat* _comms_ack; + CommsFormat* _comms_nck; + + RingBuf<CommsFormat *, CONST_MAX_SIZE_RB_SENDING> *_ring_buff_alarm; + RingBuf<CommsFormat *, CONST_MAX_SIZE_RB_SENDING> *_ring_buff_data; + RingBuf<CommsFormat *, CONST_MAX_SIZE_RB_SENDING> *_ring_buff_cmd; + + RingBuf<Payload, CONST_MAX_SIZE_RB_RECEIVING> *_ring_buff_received; + + Payload _payload_tmp; + CommsFormat _comms_tmp; + + uint32_t _baudrate; + + uint64_t _last_trans_time; + + uint8_t _comms_received[CONST_MAX_SIZE_BUFFER]; + uint8_t _comms_received_size; + uint8_t _comms_send [CONST_MAX_SIZE_BUFFER]; + uint8_t _comms_send_size; + + uint8_t _last_trans[CONST_MAX_SIZE_BUFFER]; + uint8_t _start_trans_index; + uint8_t _last_trans_index; + + bool _found_start; +}; + +#endif diff --git a/arduino/common/lib/CommsControl/CommsFormat.h b/arduino/common/lib/CommsControl/CommsFormat.h new file mode 100644 index 00000000..ff8916e4 --- /dev/null +++ b/arduino/common/lib/CommsControl/CommsFormat.h @@ -0,0 +1,76 @@ +#ifndef COMMSFORMAT_H +#define COMMSFORMAT_H + +// Communication protocol based on HDLC format +// author Peter Svihra <peter.svihra@cern.ch> + +#include <Arduino.h> +#include <uCRC16Lib.h> + +#include "CommsCommon.h" + +/////////////////////////////////////////////////////////////////////////// +// class to provide all needed control in data format +class CommsFormat { +public: + CommsFormat(uint8_t infoSize = 0, uint8_t address = 0x00, uint16_t control = 0x0000); + CommsFormat(const CommsFormat& other) { + _crc = other._crc; + _packet_size = other._packet_size; + _info_size = other._info_size; + memcpy(_data, other._data, CONST_MAX_SIZE_PACKET); + } + CommsFormat& operator=(const CommsFormat& other) { + _crc = other._crc; + _packet_size = other._packet_size; + _info_size = other._info_size; + memcpy(_data, other._data, CONST_MAX_SIZE_PACKET); + + return *this; + } + + uint8_t* getData() { return _data; } + uint8_t getSize() { return _packet_size; } + + void setAddress(uint8_t* address) {assignBytes(getAddress(), address, 1); } + void setControl(uint8_t* control) {assignBytes(getControl(), control, 2); } + void setInformation(Payload *pl); + + void assignBytes(uint8_t* target, uint8_t* source, uint8_t size, bool calcCrc = true); + + void generateCrc(bool assign = true); + bool compareCrc(); + + // get data pointer of different parts + uint8_t* getStart() {return _data + 0;} // starting flag of the chain + uint8_t* getAddress() {return _data + 1;} // address where to send data, last bit is 8bit extension enable(0)/disable(1) + uint8_t* getControl() {return _data + 2;} // frame control commands + uint8_t* getInformation() {return _data + 4;} // user information + uint8_t* getFcs() {return _data + 4 + _info_size;} // checksum + uint8_t* getStop() {return _data + 4 + _info_size + 2;} // ending flag of the chain + + uint8_t getInfoSize() { return _info_size; } + + void setSequenceSend (uint8_t counter); + void setSequenceReceive(uint8_t counter); + + uint8_t getSequenceSend (); + uint8_t getSequenceReceive(); + + void copyData(uint8_t* payload, uint8_t dataSize); + + static CommsFormat* generateACK() { return new CommsFormat(0, 0, COMMS_CONTROL_ACK << 8); } + static CommsFormat* generateNACK() { return new CommsFormat(0, 0, COMMS_CONTROL_NACK << 8); } + + static CommsFormat* generateALARM(Payload *pl); + static CommsFormat* generateCMD (Payload *pl); + static CommsFormat* generateDATA (Payload *pl); + +private: + uint8_t _data[CONST_MAX_SIZE_PACKET]; + uint8_t _packet_size; + uint8_t _info_size; + uint16_t _crc; +}; + +#endif // COMMSFORMAT_H diff --git a/arduino/common/lib/commsControl/commsConstants.h b/arduino/common/lib/commsControl/commsConstants.h deleted file mode 100644 index e387dcd4..00000000 --- a/arduino/common/lib/commsControl/commsConstants.h +++ /dev/null @@ -1,205 +0,0 @@ -#ifndef COMMSCONSTANTS_H -#define COMMSCONSTANTS_H - -#include <Arduino.h> - -#define CONST_TIMEOUT_ALARM 5 -#define CONST_TIMEOUT_DATA 10 -#define CONST_TIMEOUT_CMD 50 - - -#define CONST_MAX_SIZE_RB_RECEIVING 10 -#define CONST_MAX_SIZE_RB_SENDING 5 -#define CONST_MAX_SIZE_PACKET 64 -#define CONST_MAX_SIZE_BUFFER 128 -#define CONST_MIN_SIZE_PACKET 7 - -#define COMMS_FRAME_BOUNDARY 0x7E -#define COMMS_FRAME_ESCAPE 0x7D -#define COMMS_ESCAPE_BIT_SWAP 5 - -#define COMMS_CONTROL_INFORMATION 0x00 -#define COMMS_CONTROL_SUPERVISORY 0x01 - -#define COMMS_CONTROL_TYPES 0x0F -#define COMMS_CONTROL_ACK 0x00 | COMMS_CONTROL_SUPERVISORY -#define COMMS_CONTROL_NACK 0x04 | COMMS_CONTROL_SUPERVISORY - -#define PACKET_TYPE 0xC0 -#define PACKET_ALARM 0xC0 -#define PACKET_CMD 0x80 -#define PACKET_DATA 0x40 -#define PACKET_SET 0x20 //set vs get ? - -#define HEV_FORMAT_VERSION 0xA0 - -enum command_codes {CMD_START = 1, - CMD_STOP = 2}; - -// Taken from safety doc. Correct as of 1400 on 20200416 -enum alarm_codes {APNEA = 1, // HP - CHECK_VALVE_EXHALE = 2, // HP - CHECK_P_PATIENT = 3, // HP - EXPIRATION_SENSE_FAULT_OR_LEAK = 4, // MP - EXPIRATION_VALVE_Leak = 5, // MP - HIGH_FIO2 = 6, // MP - HIGH_PRESSURE = 7, // HP - HIGH_RR = 8, // MP - HIGH_VTE = 9, // MP - LOW_VTE = 10, // MP - HIGH_VTI = 11, // MP - LOW_VTI = 12, // MP - INTENTIONAL_STOP = 13, // HP - LOW_BATTERY = 14, // HP (LP) if AC power isn't (is) connected - LOW_FIO2 = 15, // HP - OCCLUSION = 16, // HP - HIGH_PEEP = 17, // HP - LOW_PEEP = 18, // HP - AC_POWER_DISCONNECTION = 19, // MP - BATTERY_FAULT_SRVC = 20, // MP - BATTERY_CHARGE = 21, // MP - AIR_FAIL = 22, // HP - O2_FAIL = 23, // HP - PRESSURE_SENSOR_FAULT = 24, // HP - ARDUINO_FAIL = 25}; // HP - -// struct for all data sent -struct dataFormat { - 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 = HEV_FORMAT_VERSION; // - uint8_t cmdCode = 0; - uint32_t param = 0; -}; - -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 -enum payloadType { - payloadData, - payloadCmd, - payloadAlarm, - payloadUnset -}; - -// payload consists of type and information -// type is set as address in the protocol -// 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(const payload &other) { - type_ = other.type_; - memcpy(& data_, &other. data_, sizeof( dataFormat)); - memcpy(& cmd_, &other. cmd_, sizeof( cmdFormat)); - memcpy(&alarm_, &other.alarm_, sizeof(alarmFormat)); - } - payload& operator=(const payload& other) { - type_ = other.type_; - memcpy(& data_, &other. data_, sizeof( dataFormat)); - memcpy(& cmd_, &other. cmd_, sizeof( cmdFormat)); - memcpy(&alarm_, &other.alarm_, sizeof(alarmFormat)); - return *this; - } - - ~payload() { unsetAll(); } - - void setType(payloadType type) { type_ = type; } - payloadType getType() {return type_; } - - // requires argument as new struct - void setData (dataFormat *data) { type_ = payloadType::payloadData; memcpy(& data_, data, sizeof( dataFormat)); } - void setCmd (cmdFormat *cmd) { type_ = payloadType::payloadCmd; memcpy(& cmd_, cmd, sizeof( cmdFormat)); } - void setAlarm(alarmFormat *alarm) { type_ = payloadType::payloadAlarm; memcpy(&alarm_, alarm, sizeof(alarmFormat)); } - - // get pointers to particular payload types - dataFormat *getData () {return & data_; } - cmdFormat *getCmd () {return & cmd_; } - alarmFormat *getAlarm() {return &alarm_; } - - void unsetAll() { unsetData(); unsetAlarm(); unsetCmd(); type_ = payloadType::payloadUnset; } - void unsetData() { memset(& data_, 0, sizeof( dataFormat)); } - void unsetCmd() { memset(& cmd_, 0, sizeof( cmdFormat)); } - void unsetAlarm() { memset(&alarm_, 0, sizeof(alarmFormat)); } - - void setPayload(payloadType type, void* information) { - setType(type); - setInformation(information); - } - - void setInformation(void* information) { - switch (type_) { - case payloadType::payloadData: - setData (reinterpret_cast< dataFormat*>(information)); - break; - case payloadType::payloadCmd: - setCmd (reinterpret_cast< cmdFormat*>(information)); - break; - case payloadType::payloadAlarm: - setAlarm(reinterpret_cast<alarmFormat*>(information)); - break; - default: - break; - } - } - - // returns void pointer, in case you know what to do with data or dont care what the format is - void *getInformation() { - switch (type_) { - case payloadType::payloadData: - return reinterpret_cast<void*>(getData ()); - case payloadType::payloadCmd: - return reinterpret_cast<void*>(getCmd ()); - case payloadType::payloadAlarm: - return reinterpret_cast<void*>(getAlarm()); - default: - return nullptr; - } - } - - // returns payload information size - uint8_t getSize() { - switch (type_) { - case payloadType::payloadData: - return static_cast<uint8_t>(sizeof( dataFormat)); - case payloadType::payloadCmd: - return static_cast<uint8_t>(sizeof( cmdFormat)); - case payloadType::payloadAlarm: - return static_cast<uint8_t>(sizeof(alarmFormat)); - default: - return 0; - } - } - -private: - payloadType type_; - - dataFormat data_; - cmdFormat cmd_; - alarmFormat alarm_; -}; - -#endif diff --git a/arduino/common/lib/commsControl/commsControl.cpp b/arduino/common/lib/commsControl/commsControl.cpp deleted file mode 100644 index 091f93a8..00000000 --- a/arduino/common/lib/commsControl/commsControl.cpp +++ /dev/null @@ -1,323 +0,0 @@ -#include "commsControl.h" - -commsControl::commsControl(uint32_t baudrate) { - baudrate_ = baudrate; - - lastTransTime_ = millis(); - - startTransIndex_ = 0xFF; - lastTransIndex_ = 0; - commsReceivedSize_ = 0; - commsSendSize_ = 0; - foundStart_ = false; - - memset(lastTrans_ , 0, sizeof(lastTrans_ )); - memset(commsReceived_, 0, sizeof(commsReceived_)); - memset(commsSend_ , 0, sizeof(commsSend_ )); - - queueAlarm_ = new RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING>(); - 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>(); - - commsTmp_ = commsFormat(CONST_MAX_SIZE_PACKET - CONST_MIN_SIZE_PACKET ); - - commsAck_ = commsFormat::generateACK(); - commsNck_ = commsFormat::generateNACK(); - - sequenceSend_ = 0; - sequenceReceive_ = 0; -} - -// WIP -commsControl::~commsControl() { - ; -} - -void commsControl::beginSerial() { - Serial.begin(baudrate_); -} - -// main function to always call and try and send data -// TODO: needs switch on data type with global timeouts on data pushing -void commsControl::sender() { - if (millis() > lastTransTime_ + CONST_TIMEOUT_ALARM ) { - sendQueue(queueAlarm_); - } - - if (millis() > lastTransTime_ + CONST_TIMEOUT_CMD ) { - sendQueue(queueCmd_); - } - - if (millis() > lastTransTime_ + CONST_TIMEOUT_DATA ) { - sendQueue(queueData_); - } -} - -// main function to always try to receive data -// TODO: needs switch on data type with global timeouts on data pushing -void commsControl::receiver() { - uint8_t currentTransIndex; - - // check if any data in waiting - if (Serial.available()) { - // while able to read data (unable == -1) - while (Serial.peek() >= 0) { - // read byte by byte, just in case the transmission is somehow blocked - - // WARNING: for mkrvidor4000, readbytes takes char* not uchar* - lastTransIndex_ += Serial.readBytes(lastTrans_ + lastTransIndex_, 1); - - // if managed to read at least 1 byte - if (lastTransIndex_ > 0 && lastTransIndex_ < CONST_MAX_SIZE_BUFFER) { - currentTransIndex = lastTransIndex_ - 1; - - // find the boundary of frames - if (lastTrans_[currentTransIndex] == COMMS_FRAME_BOUNDARY) { - // if not found start or if read the same byte as last time - if (!foundStart_ || startTransIndex_ == currentTransIndex) { - foundStart_ = true; - startTransIndex_ = currentTransIndex; - } else { - // if managed to decode and compare CRC - if (decoder(lastTrans_, startTransIndex_, lastTransIndex_)) { - - sequenceReceive_ = (*(commsTmp_.getControl()) >> 1 ) & 0x7F; - // to decide ACK/NACK/other; for other gain sequenceReceive - uint8_t control = *(commsTmp_.getControl() + 1); - - // to decide what kind of packets received - payloadType type = getInfoType(commsTmp_.getAddress()); - - // switch on received data to know what to do - received ACK/NACK or other - switch(control & COMMS_CONTROL_TYPES) { - case COMMS_CONTROL_NACK: - // received NACK - // TODO: modify timeout for next sent frame? - // resendPacket(&address); - break; - case COMMS_CONTROL_ACK: - // received ACK - finishPacket(type); - break; - default: - uint8_t tmpSequenceReceive = (control >> 1 ) & 0x7F; - tmpSequenceReceive += 1; - // received DATA - if (receivePacket(type)) { - commsAck_->setAddress(commsTmp_.getAddress()); - commsAck_->setSequenceReceive(tmpSequenceReceive); - sendPacket(commsAck_); - } else { - commsNck_->setAddress(commsTmp_.getAddress()); - commsNck_->setSequenceReceive(tmpSequenceReceive); - sendPacket(commsNck_); - } - - break; - } - } - - // reset the frame - foundStart_ = false; - lastTransIndex_ = 0; - startTransIndex_ = 0xFF; - - // break the loop, even if more data waiting in the bus - this frame is finished - break; - } - } - } else if (lastTransIndex_ >= CONST_MAX_SIZE_BUFFER) { - lastTransIndex_ = 0; - } - } - } -} - -bool commsControl::writePayload(payload &pl) { - commsFormat* tmpComms; - payloadType type = pl.getType(); - - // switch on different received payload types - // TODO simplify the static functions - switch(type) { - case payloadAlarm: - tmpComms = commsFormat::generateALARM(&pl); - break; - case payloadData: - tmpComms = commsFormat::generateDATA(&pl); - break; - case payloadCmd: - tmpComms = commsFormat::generateCMD(&pl); - break; - default: - return false; - } - - RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *queue = getQueue(type); - // add new entry to the queue - if (queue->isFull()) { - commsFormat *tmpCommsRm; - if (queue->pop(tmpCommsRm)) { - delete tmpCommsRm; - } - } - - if (queue->push(tmpComms) ) { - return true; - } - return false; -} - -bool commsControl::readPayload( payload &pl) { - if ( !queueReceived_->isEmpty()) { - if (queueReceived_->pop(pl)) { - return true; - } - } - return false; -} - -// general encoder of any transmission -bool commsControl::encoder(uint8_t *data, uint8_t dataSize) { - if (dataSize > 0) { - commsSendSize_ = 0; - uint8_t tmpVal = 0; - - commsSend_[commsSendSize_++] = data[0]; - for (uint8_t idx = 1; idx < dataSize - 1; idx++) { - tmpVal = data[idx]; - if (tmpVal == COMMS_FRAME_ESCAPE || tmpVal == COMMS_FRAME_BOUNDARY) { - commsSend_[commsSendSize_++] = COMMS_FRAME_ESCAPE; - tmpVal ^= (1 << COMMS_ESCAPE_BIT_SWAP); - } - commsSend_[commsSendSize_++] = tmpVal; - } - commsSend_[commsSendSize_++] = data[dataSize-1]; - - return true; - } - return false; -} - - -// general decoder of any transmission -bool commsControl::decoder(uint8_t* data, uint8_t dataStart, uint8_t dataStop) { - // need to have more than 1 byte transferred - if (dataStop > (dataStart + 1)) { - commsReceivedSize_ = 0; - uint8_t tmpVal = 0; - bool escaped = false; - - for (uint8_t idx = dataStart; idx < dataStop; idx++) { - tmpVal = data[idx]; - if (tmpVal == COMMS_FRAME_ESCAPE) { - escaped = true; - } else { - if (escaped) { - tmpVal ^= (1 << COMMS_ESCAPE_BIT_SWAP); - escaped = false; - } - commsReceived_[commsReceivedSize_++] = tmpVal; - } - } - commsTmp_.copyData(commsReceived_, commsReceivedSize_); - return commsTmp_.compareCrc(); - } - return false; -} - -// sending anything of commsDATA format -void commsControl::sendQueue(RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *queue) { - // if have data to send - if (!queue->isEmpty()) { - // reset sending counter - lastTransTime_ = millis(); - - queue->operator [](0)->setSequenceSend(sequenceSend_); - - sendPacket(queue->operator [](0)); - } -} - -void commsControl::sendPacket(commsFormat *packet) { - // if encoded and able to write data - if (encoder(packet->getData(), packet->getSize()) ) { - if (Serial.availableForWrite() >= commsSendSize_) { - Serial.write(commsSend_, commsSendSize_); - } - } -} - -// resending the packet, can lower the timeout since either NACK or wrong FCS already checked -//WIP -void commsControl::resendPacket(RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *queue) { - ; -} - - -// receiving anything of commsFormat -bool commsControl::receivePacket(payloadType &type) { - payloadTmp_.unsetAll(); - payloadTmp_.setType(type); - void *tmpInformation = payloadTmp_.getInformation(); - // if type is definet, copy information from comms to payload - if (tmpInformation != nullptr) { - memcpy(tmpInformation, commsTmp_.getInformation(), commsTmp_.getInfoSize()); - - // remove first entry if queue is full - if (queueReceived_->isFull()) { - payload tmpPlRm; - if (queueReceived_->pop(tmpPlRm)) { - ; - } - } - return queueReceived_->push(payloadTmp_); - } - return false; -} - -// if FCS is ok, remove from queue -void commsControl::finishPacket(payloadType &type) { - RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *tmpQueue = getQueue(type); - - if (tmpQueue != nullptr && !tmpQueue->isEmpty()) { - // get the sequence send from first entry in the queue, add one as that should be return - // 0x7F to deal with possible overflows (0 should follow after 127) - if (((tmpQueue->operator [](0)->getSequenceSend() + 1) & 0x7F) == sequenceReceive_) { - sequenceSend_ = (sequenceSend_ + 1) % 128; - commsFormat * tmpComms; - if (tmpQueue->pop(tmpComms)) { - delete tmpComms; - } - } - } -} - -payloadType commsControl::getInfoType(uint8_t *address) { - switch (*address & PACKET_TYPE) { - case PACKET_ALARM: - return payloadType::payloadAlarm; - case PACKET_CMD: - return payloadType::payloadCmd; - case PACKET_DATA: - return payloadType::payloadData; - default: - return payloadType::payloadUnset; - } -} - -// get link to queue according to packet format -RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *commsControl::getQueue(payloadType &type) { - switch (type) { - case payloadType::payloadAlarm: - return queueAlarm_; - case payloadType::payloadCmd: - return queueCmd_; - case payloadType::payloadData: - return queueData_; - default: - return nullptr; - } -} diff --git a/arduino/common/lib/commsControl/commsControl.h b/arduino/common/lib/commsControl/commsControl.h deleted file mode 100644 index 21dc3d55..00000000 --- a/arduino/common/lib/commsControl/commsControl.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef COMMS_CONTROL_H -#define COMMS_CONTROL_H - -// Communication protocol between rasp and arduino based on HDLC format -// author Peter Svihra <peter.svihra@cern.ch> - -#include <Arduino.h> -#include "RingBuf.h" - -#include "commsConstants.h" -#include "commsFormat.h" - -/////////////////////////////////////////////////////////////////////////// -// class to provide simple communication protocol based on the data format -class commsControl { -public: - commsControl(uint32_t baudrate = 115200); - ~commsControl(); - - void beginSerial(); - - bool writePayload(payload &pl); - bool readPayload (payload &pl); - - void sender(); - void receiver(); - -private: - RingBuf<commsFormat *,CONST_MAX_SIZE_RB_SENDING> *getQueue(payloadType &type); - payloadType getInfoType(uint8_t *address); - - void sendQueue (RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *queue); - void resendPacket (RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *queue); - bool receivePacket(payloadType &type); - void finishPacket (payloadType &type); - - bool encoder(uint8_t* payload, uint8_t dataSize); - bool decoder(uint8_t* payload, uint8_t dataStart, uint8_t dataStop); - - void sendPacket(commsFormat* packet); - -private: - uint8_t sequenceSend_; - uint8_t sequenceReceive_; - - commsFormat* commsAck_; - commsFormat* commsNck_; - - RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *queueAlarm_; - RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *queueData_; - RingBuf<commsFormat *, CONST_MAX_SIZE_RB_SENDING> *queueCmd_; - - RingBuf<payload, CONST_MAX_SIZE_RB_RECEIVING> *queueReceived_; - - payload payloadTmp_; - commsFormat commsTmp_; - - uint32_t baudrate_; - - uint64_t lastTransTime_; - - uint8_t commsReceived_[CONST_MAX_SIZE_BUFFER]; - uint8_t commsReceivedSize_; - uint8_t commsSend_ [CONST_MAX_SIZE_BUFFER]; - uint8_t commsSendSize_; - - uint8_t lastTrans_[CONST_MAX_SIZE_BUFFER]; - uint8_t startTransIndex_; - uint8_t lastTransIndex_; - - bool foundStart_; -}; - -#endif diff --git a/arduino/common/lib/commsControl/commsFormat.cpp b/arduino/common/lib/commsControl/commsFormat.cpp deleted file mode 100644 index 22bde48b..00000000 --- a/arduino/common/lib/commsControl/commsFormat.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "commsFormat.h" - -// constructor to init variables -commsFormat::commsFormat(uint8_t infoSize, uint8_t address, uint16_t control) { - memset(data_, 0, sizeof(data_)); - - infoSize_ = infoSize; - packetSize_ = infoSize + CONST_MIN_SIZE_PACKET ; // minimum size (start,address,control,fcs,stop) - if (packetSize_ > CONST_MAX_SIZE_PACKET) { - return; - } - - assignBytes(getAddress(), &address, 1, false); - assignBytes(getControl(), reinterpret_cast<uint8_t*>(&control), 2, false); - - // hardcoded defaults - *getStart() = COMMS_FRAME_BOUNDARY; // fixed start flag - *getStop() = COMMS_FRAME_BOUNDARY; // fixed stop flag - - generateCrc(); -} - -void commsFormat::assignBytes(uint8_t* target, uint8_t* source, uint8_t size, bool calcCrc) { - memcpy(target, source, size); - if (calcCrc) { - generateCrc(); - } -} - -void commsFormat::setSequenceSend(uint8_t counter) { - // sequence send valid only for info frames (not supervisory ACK/NACK) - if ((*(getControl() + 1) & COMMS_CONTROL_SUPERVISORY) == 0) { - counter = (counter << 1) & 0xFE; - assignBytes(getControl() + 1, &counter, 1); - } -} - -uint8_t commsFormat::getSequenceSend() { - // sequence send valid only for info frames (not supervisory ACK/NACK) - if ((*(getControl() + 1) & COMMS_CONTROL_SUPERVISORY) == 0) { - return (*(getControl() + 1) >> 1) & 0x7F; - } else { - return 0xFF; - } -} - -void commsFormat::setSequenceReceive(uint8_t counter) { - counter = (counter << 1) & 0xFE; - assignBytes(getControl() , &counter, 1); -} - -uint8_t commsFormat::getSequenceReceive() { - return (*(getControl()) >> 1) & 0x7F; -} - -// compare calculated and received CRC value -bool commsFormat::compareCrc() { - // generate data crc - generateCrc(false); - - // get crc from fcs - uint16_t tmpFcs; - assignBytes(reinterpret_cast<uint8_t*>(&tmpFcs), getFcs(), 2, false); - - // return comparison - return tmpFcs == crc_; -} - -// calculate CRC value -void commsFormat::generateCrc(bool assign) { - // calculate crc - crc_ = uCRC16Lib::calculate(reinterpret_cast<char*>(getAddress()), static_cast<uint16_t>(infoSize_ + 3)); - - // assign crc to fcs - if (assign) { - assignBytes(getFcs(), reinterpret_cast<uint8_t*>(&crc_), 2, false); - } -} - -// assign received information to packet -void commsFormat::setInformation(payload *pl) { - assignBytes(getInformation(), reinterpret_cast<uint8_t*>(pl->getInformation()), getInfoSize()); -} - -void commsFormat::copyData(uint8_t* data, uint8_t dataSize) { - packetSize_ = dataSize; - infoSize_ = dataSize - CONST_MIN_SIZE_PACKET; - memset(getData(), 0, sizeof(data_)); - - assignBytes(getData(), data, dataSize); -} - - -// STATIC METHODS -// TODO rewrite in a slightly better way using the enum -commsFormat* commsFormat::generateALARM(payload *pl) { - commsFormat *tmpComms = new commsFormat(pl->getSize(), PACKET_ALARM); - tmpComms->setInformation(pl); - return tmpComms; -} -commsFormat* commsFormat::generateCMD (payload *pl) { - commsFormat *tmpComms = new commsFormat(pl->getSize(), PACKET_CMD ); - tmpComms->setInformation(pl); - return tmpComms; -} -commsFormat* commsFormat::generateDATA (payload *pl) { - commsFormat *tmpComms = new commsFormat(pl->getSize(), PACKET_DATA ); - tmpComms->setInformation(pl); - return tmpComms; -} - diff --git a/arduino/common/lib/commsControl/commsFormat.h b/arduino/common/lib/commsControl/commsFormat.h deleted file mode 100644 index 81b2ca47..00000000 --- a/arduino/common/lib/commsControl/commsFormat.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef COMMSFORMAT_H -#define COMMSFORMAT_H - -// Communication protocol based on HDLC format -// author Peter Svihra <peter.svihra@cern.ch> - -#include <Arduino.h> -#include <uCRC16Lib.h> - -#include "commsConstants.h" - -/////////////////////////////////////////////////////////////////////////// -// class to provide all needed control in data format -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_; } - - void setAddress(uint8_t* address) {assignBytes(getAddress(), address, 1); } - void setControl(uint8_t* control) {assignBytes(getControl(), control, 2); } - void setInformation(payload *pl); - - void assignBytes(uint8_t* target, uint8_t* source, uint8_t size, bool calcCrc = true); - - void generateCrc(bool assign = true); - bool compareCrc(); - - // get data pointer of different parts - uint8_t* getStart() {return data_ + 0;} // starting flag of the chain - uint8_t* getAddress() {return data_ + 1;} // address where to send data, last bit is 8bit extension enable(0)/disable(1) - uint8_t* getControl() {return data_ + 2;} // frame control commands - uint8_t* getInformation() {return data_ + 4;} // user information - uint8_t* getFcs() {return data_ + 4 + infoSize_;} // checksum - uint8_t* getStop() {return data_ + 4 + infoSize_ + 2;} // ending flag of the chain - - uint8_t getInfoSize() { return infoSize_; } - - void setSequenceSend (uint8_t counter); - void setSequenceReceive(uint8_t counter); - - uint8_t getSequenceSend (); - uint8_t getSequenceReceive(); - - void copyData(uint8_t* payload, uint8_t dataSize); - - static commsFormat* generateACK() { return new commsFormat(0, 0, COMMS_CONTROL_ACK << 8); } - static commsFormat* generateNACK() { return new commsFormat(0, 0, COMMS_CONTROL_NACK << 8); } - - static commsFormat* generateALARM(payload *pl); - static commsFormat* generateCMD (payload *pl); - static commsFormat* generateDATA (payload *pl); - -private: - uint8_t data_[CONST_MAX_SIZE_PACKET]; - uint8_t packetSize_; - uint8_t infoSize_; - uint16_t crc_; -}; - -#endif // COMMSFORMAT_H diff --git a/arduino/hev_prototype_v1/platformio.ini b/arduino/hev_prototype_v1/platformio.ini index c369a0e6..9c1c4d63 100644 --- a/arduino/hev_prototype_v1/platformio.ini +++ b/arduino/hev_prototype_v1/platformio.ini @@ -13,7 +13,7 @@ default_envs = nodemcu-32s [env] lib_deps = - commsControl + CommsControl 5574 ; INA2xx 820 ; Adafruit MCP9808 5390 ; uCRC16Lib diff --git a/arduino/hev_prototype_v1/platformio.pro b/arduino/hev_prototype_v1/platformio.pro new file mode 100644 index 00000000..f5af1a55 --- /dev/null +++ b/arduino/hev_prototype_v1/platformio.pro @@ -0,0 +1,49 @@ +win32 { + HOMEDIR += $$(USERPROFILE) +} +else { + HOMEDIR += $$(HOME) +} + +INCLUDEPATH += "$${_PRO_FILE_PWD_}/include" +INCLUDEPATH += "$${_PRO_FILE_PWD_}/src" +INCLUDEPATH += "$${_PRO_FILE_PWD_}/../common/lib/CommsControl" +INCLUDEPATH += "$${_PRO_FILE_PWD_}/.pio/libdeps/nodemcu-32s/uCRC16Lib_ID5390/src" +INCLUDEPATH += "$${_PRO_FILE_PWD_}/.pio/libdeps/nodemcu-32s/RingBuffer_ID5418/src" +INCLUDEPATH += "$${_PRO_FILE_PWD_}/../common/include" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/framework-arduino-avr/cores/arduino" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/framework-arduino-avr/variants/standard" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/framework-arduino-avr/libraries/EEPROM/src" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/framework-arduino-avr/libraries/HID/src" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/framework-arduino-avr/libraries/SPI/src" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/framework-arduino-avr/libraries/SoftwareSerial/src" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/framework-arduino-avr/libraries/Wire/src" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/toolchain-atmelavr/avr/include" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/toolchain-atmelavr/lib/gcc/avr/5.4.0/include" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/toolchain-atmelavr/lib/gcc/avr/5.4.0/include-fixed" +INCLUDEPATH += "$${HOMEDIR}/.platformio/packages/tool-unity" + +DEFINES += "PLATFORMIO=40301" +DEFINES += "ARDUINO_AVR_UNO" +DEFINES += "F_CPU=16000000L" +DEFINES += "ARDUINO_ARCH_AVR" +DEFINES += "ARDUINO=10808" +DEFINES += "__AVR_ATmega328P__" + +OTHER_FILES += platformio.ini + +HEADERS += src/common.h \ + src/MemoryFree.h \ + src/BreathingLoop.h \ + src/UILoop.h \ + ../common/lib/CommsControl/CommsCommon.h \ + ../common/lib/CommsControl/CommsControl.h \ + ../common/lib/CommsControl/CommsFormat.h + +SOURCES += src/main.cpp \ + src/MemoryFree.cpp \ + src/BreathingLoop.cpp \ + src/common.cpp \ + src/UILoop.cpp \ + ../common/lib/commsControl/CommsControl.cpp \ + ../common/lib/commsControl/CommsFormat.cpp diff --git a/arduino/hev_prototype_v1/src/BreathingLoop.cpp b/arduino/hev_prototype_v1/src/BreathingLoop.cpp index d3c63fb2..2d280410 100644 --- a/arduino/hev_prototype_v1/src/BreathingLoop.cpp +++ b/arduino/hev_prototype_v1/src/BreathingLoop.cpp @@ -21,12 +21,12 @@ BreathingLoop::~BreathingLoop() ; } -byte BreathingLoop::getLabCycleMode() +uint8_t BreathingLoop::getLabCycleMode() { return _ventilation_mode; } -byte BreathingLoop::getFsmState() +uint8_t BreathingLoop::getFsmState() { return _bs_state; } @@ -138,27 +138,26 @@ void BreathingLoop::FSM_breath_cycle() // TODO // do calib - measure P_regulated for 10 s and calc mean // P_patient, P_buffer and P_inhale shoudl be equal - _timeout = 10000; + _timeout = fsm_timeout.calibration; case BL_STATES::BUFF_PREFILL: - // TODO - exhale settable; timeout expert settable + // TODO - exhale settable setValves(V_CLOSED, V_CLOSED, 0.0, 0.8, V_CLOSED, V_CLOSED); - _timeout = 100; + _timeout = fsm_timeout.buff_prefill; break; case BL_STATES::BUFF_FILL: - // TODO - exhale settable; timeout settable + // TODO - exhale settable setValves(V_OPEN, V_OPEN, 0.0, 0.8, V_CLOSED, V_CLOSED); - _timeout = 600; + _timeout = fsm_timeout.buff_fill; break; case BL_STATES::BUFF_LOADED: - // TODO - exhale settable; timeout expert settable + // TODO - exhale settable // Calc pressure and stay in loaded if not ok // pressure settable by expert setValves(V_CLOSED, V_CLOSED, 0.0, 0.8, V_CLOSED, V_CLOSED); - _timeout = 100; + _timeout = fsm_timeout.buff_loaded; break; case BL_STATES::BUFF_PRE_INHALE: - // TODO - timeout settable - // spontaneous trigger can be enabled + // TODO spontaneous trigger can be enabled // - can be triggered by : // P_inhale ; // P_diff_patient //=flow @@ -177,7 +176,7 @@ void BreathingLoop::FSM_breath_cycle() break; default: - _timeout = 100; + _timeout = fsm_timeout.buff_pre_inhale; } break; @@ -189,35 +188,34 @@ void BreathingLoop::FSM_breath_cycle() // if p_inhale > max thresh pressure(def: 50?) // go to exhale fill setValves(V_CLOSED, V_CLOSED, 0.8, 0.0, V_CLOSED, V_CLOSED); - _timeout =1000; + _timeout = fsm_timeout.inhale; break; case BL_STATES::PAUSE: - // TODO: timeout setting setValves(V_CLOSED, V_CLOSED, 0.0, 0.0, V_CLOSED, V_CLOSED); - _timeout = 500; + _timeout = fsm_timeout.pause; break; case BL_STATES::EXHALE_FILL: - // TODO: timeout setting setValves(V_OPEN, V_OPEN, 0.0, 0.9, V_CLOSED, V_CLOSED); - _timeout = 600; + _timeout = fsm_timeout.exhale_fill; break; case BL_STATES::EXHALE: // TODO: exhale timeout based on // (inhale_time* (Exhale/Inhale ratio)) - fill time + fsm_timeout.exhale = getTimeoutExhale(); setValves(V_CLOSED, V_CLOSED, 0.0, 0.9, V_CLOSED, V_CLOSED); - _timeout = 400; + _timeout = fsm_timeout.exhale; break; case BL_STATES::BUFF_PURGE: setValves(V_CLOSED, V_CLOSED, 0.0, 0.9, V_OPEN, V_CLOSED); - _timeout =1000; + _timeout = fsm_timeout.buff_purge; break; case BL_STATES::BUFF_FLUSH: setValves(V_CLOSED, V_CLOSED, 0.9, 0.9, V_CLOSED, V_CLOSED); - _timeout =1000; + _timeout = fsm_timeout.buff_flush; break; case BL_STATES::STOP: // TODO : require a reset command to go back to idle diff --git a/arduino/hev_prototype_v1/src/BreathingLoop.h b/arduino/hev_prototype_v1/src/BreathingLoop.h index 89c1ba17..dbac2f93 100644 --- a/arduino/hev_prototype_v1/src/BreathingLoop.h +++ b/arduino/hev_prototype_v1/src/BreathingLoop.h @@ -13,8 +13,8 @@ class BreathingLoop public: BreathingLoop(); ~BreathingLoop(); - byte getLabCycleMode(); - byte getFsmState(); + uint8_t getLabCycleMode(); + uint8_t getFsmState(); void FSM_assignment(); void FSM_breath_cycle(); void doStart(); @@ -24,7 +24,7 @@ public: void updatePressures(); // states - enum BL_STATES : byte + enum BL_STATES : uint8_t { IDLE, CALIBRATION, @@ -42,7 +42,7 @@ public: }; //TODO: this should probably be common - enum VENTILATION_MODES : byte + enum VENTILATION_MODES : uint8_t { LAB_MODE_BREATHE = 0, LAB_MODE_PURGE = 1, @@ -51,9 +51,9 @@ public: private: uint64_t _fsm_time ; - int _timeout; - byte _ventilation_mode; - byte _bs_state; + uint32_t _timeout; + uint8_t _ventilation_mode; + uint8_t _bs_state; bool _running; bool _reset; int _next_state; @@ -62,4 +62,4 @@ private: -#endif \ No newline at end of file +#endif diff --git a/arduino/hev_prototype_v1/src/UILoop.cpp b/arduino/hev_prototype_v1/src/UILoop.cpp index 6d1dcdfa..66bb2a40 100644 --- a/arduino/hev_prototype_v1/src/UILoop.cpp +++ b/arduino/hev_prototype_v1/src/UILoop.cpp @@ -9,16 +9,55 @@ UILoop::UILoop(BreathingLoop *bl) UILoop::~UILoop() {;} -int UILoop::doCommand(cmdFormat *cf) +int UILoop::doCommand(cmd_format *cf) { - - switch(cf->cmdCode){ - case 0x1 : _breathing_loop->doStart(); - break; - case 0x2 : _breathing_loop->doStop(); - break; + switch(cf->cmd_type) { + case CMD_TYPE::GENERAL: + cmdGeneral(cf); + break; + case CMD_TYPE::SET_TIMEOUT: + cmdSetTimeout(cf); + break; + case CMD_TYPE::SET_MODE: + cmdSetMode(cf); + break; + case CMD_TYPE::SET_THRESHOLD_MIN : + cmdSetThresholdMin(cf); + break; + case CMD_TYPE::SET_THRESHOLD_MAX : + cmdSetThresholdMax(cf); + break; default: - break; + break; } return 0; -} \ No newline at end of file +} + +void UILoop::cmdGeneral(cmd_format *cf) { + switch (cf->cmd_code) { + case 0x1 : _breathing_loop->doStart(); + break; + case 0x2 : _breathing_loop->doStop(); + break; + default: + break; + } +} + +void UILoop::cmdSetTimeout(cmd_format *cf) { + setTimeout(static_cast<CMD_SET_TIMEOUT>(cf->cmd_code), fsm_timeout, cf->param); +} + +void UILoop::cmdSetMode(cmd_format *cf) { + ; +} + +void UILoop::cmdSetThresholdMin(cmd_format *cf) { + setThreshold(static_cast<ALARM_CODES>(cf->cmd_code), alarm_threshold_min, cf->param); +} + +void UILoop::cmdSetThresholdMax(cmd_format *cf) { + setThreshold(static_cast<ALARM_CODES>(cf->cmd_code), alarm_threshold_max, cf->param); +} + + diff --git a/arduino/hev_prototype_v1/src/UILoop.h b/arduino/hev_prototype_v1/src/UILoop.h index 949a1ac4..957e8dea 100644 --- a/arduino/hev_prototype_v1/src/UILoop.h +++ b/arduino/hev_prototype_v1/src/UILoop.h @@ -1,6 +1,7 @@ #include <Arduino.h> -#include "commsFormat.h" +#include "CommsFormat.h" #include "BreathingLoop.h" +#include "common.h" class UILoop { @@ -8,7 +9,13 @@ class UILoop public: UILoop(BreathingLoop *bl); ~UILoop(); - int doCommand(cmdFormat *cf); + int doCommand(cmd_format *cf); private: + void cmdGeneral(cmd_format *cf); + void cmdSetTimeout(cmd_format *cf); + void cmdSetMode(cmd_format *cf); + void cmdSetThresholdMin(cmd_format *cf); + void cmdSetThresholdMax(cmd_format *cf); + BreathingLoop *_breathing_loop; -}; \ No newline at end of file +}; diff --git a/arduino/hev_prototype_v1/src/common.cpp b/arduino/hev_prototype_v1/src/common.cpp index 835e310d..7e989473 100644 --- a/arduino/hev_prototype_v1/src/common.cpp +++ b/arduino/hev_prototype_v1/src/common.cpp @@ -44,4 +44,131 @@ void getValves(bool &vin_air, bool &vin_o2, float &vinhale, vexhale = valve_port_states.exhale; vpurge = valve_port_states.purge ; vatmos = valve_port_states.atmos; -} \ No newline at end of file +} + +void setThreshold(ALARM_CODES alarm, alarm_thresholds &thresholds, uint32_t value) { + switch (alarm) { + case ALARM_CODES::APNEA : + thresholds.apnea = value; + break; + case ALARM_CODES::CHECK_VALVE_EXHALE : + thresholds.check_valve_exhale = value; + break; + case ALARM_CODES::CHECK_P_PATIENT : + thresholds.check_p_patient = value; + break; + case ALARM_CODES::EXPIRATION_SENSE_FAULT_OR_LEAK: + thresholds.expiration_sense_fault_or_leak = value; + break; + case ALARM_CODES::EXPIRATION_VALVE_Leak : + thresholds.expiration_valve_leak = value; + break; + case ALARM_CODES::HIGH_FIO2 : + thresholds.high_fio2 = value; + break; + case ALARM_CODES::HIGH_PRESSURE : + thresholds.high_pressure = value; + break; + case ALARM_CODES::HIGH_RR : + thresholds.high_rr = value; + break; + case ALARM_CODES::HIGH_VTE : + thresholds.high_vte = value; + break; + case ALARM_CODES::LOW_VTE : + thresholds.low_vte = value; + break; + case ALARM_CODES::HIGH_VTI : + thresholds.high_vti = value; + break; + case ALARM_CODES::LOW_VTI : + thresholds.low_vti = value; + break; + case ALARM_CODES::INTENTIONAL_STOP : + thresholds.intentional_stop = value; + break; + case ALARM_CODES::LOW_BATTERY : + thresholds.low_battery = value; + break; + case ALARM_CODES::LOW_FIO2 : + thresholds.low_fio2 = value; + break; + case ALARM_CODES::OCCLUSION : + thresholds.occlusion = value; + break; + case ALARM_CODES::HIGH_PEEP : + thresholds.high_peep = value; + break; + case ALARM_CODES::LOW_PEEP : + thresholds.low_peep = value; + break; + case ALARM_CODES::AC_POWER_DISCONNECTION : + thresholds.ac_power_disconnection = value; + break; + case ALARM_CODES::BATTERY_FAULT_SRVC : + thresholds.battery_fault_srvc = value; + break; + case ALARM_CODES::BATTERY_CHARGE : + thresholds.battery_charge = value; + break; + case ALARM_CODES::AIR_FAIL : + thresholds.air_fail = value; + break; + case ALARM_CODES::O2_FAIL : + thresholds.o2_fail = value; + break; + case ALARM_CODES::PRESSURE_SENSOR_FAULT : + thresholds.pressure_sensor_fault = value; + break; + case ALARM_CODES::ARDUINO_FAIL : + thresholds.arduino_fail = value; + break; + default: + break; + } +} + +void setTimeout(CMD_SET_TIMEOUT cmd, fsm_timeouts &timeouts, uint32_t value) { + switch (cmd) { + case CMD_SET_TIMEOUT::CALIBRATION: + timeouts.calibration = value; + break; + case CMD_SET_TIMEOUT::BUFF_PURGE: + timeouts.buff_purge = value; + break; + case CMD_SET_TIMEOUT::BUFF_FLUSH: + timeouts.buff_flush = value; + break; + case CMD_SET_TIMEOUT::BUFF_PREFILL: + timeouts.buff_prefill = value; + break; + case CMD_SET_TIMEOUT::BUFF_FILL: + timeouts.buff_fill = value; + break; + case CMD_SET_TIMEOUT::BUFF_LOADED: + timeouts.buff_loaded = value; + break; + case CMD_SET_TIMEOUT::BUFF_PRE_INHALE: + timeouts.buff_pre_inhale = value; + break; + case CMD_SET_TIMEOUT::INHALE: + timeouts.inhale = value; + break; + case CMD_SET_TIMEOUT::PAUSE: + timeouts.pause = value; + break; + case CMD_SET_TIMEOUT::EXHALE_FILL: + timeouts.exhale_fill = value; + break; + case CMD_SET_TIMEOUT::EXHALE: + timeouts.exhale = value; + break; + default: + break; + } +} + +uint32_t getTimeoutExhale() { + // FIXME 1/1 has to be replaced using exhale/inhale ratio + return static_cast<uint32_t>(fsm_timeout.inhale * ( 1/ 1) ) - fsm_timeout.buff_fill; +} diff --git a/arduino/hev_prototype_v1/src/common.h b/arduino/hev_prototype_v1/src/common.h index c2ac7b55..3eecb47f 100644 --- a/arduino/hev_prototype_v1/src/common.h +++ b/arduino/hev_prototype_v1/src/common.h @@ -27,29 +27,137 @@ #endif // input params -enum hev_modes : byte -{ +enum CMD_TYPE : uint8_t { + GENERAL = 1, + SET_TIMEOUT = 2, + SET_MODE = 3, + SET_THRESHOLD_MIN = 4, + SET_THRESHOLD_MAX = 5 +}; + +enum CMD_GENERAL : uint8_t { + START = 1, + STOP = 2, + PURGE = 3, + FLUSH = 4 +}; + +// Taken from the FSM doc. Correct as of 1400 on 20200417 +enum CMD_SET_TIMEOUT : uint8_t { + CALIBRATION = 1, + BUFF_PURGE = 2, + BUFF_FLUSH = 3, + BUFF_PREFILL = 4, + BUFF_FILL = 5, + BUFF_LOADED = 6, + BUFF_PRE_INHALE = 7, + INHALE = 8, + PAUSE = 9, + EXHALE_FILL = 10, + EXHALE = 11 +}; + +enum CMD_SET_MODE : uint8_t { HEV_MODE_PS, HEV_MODE_CPAP, HEV_MODE_PRVC, HEV_MODE_TEST }; -enum valve_states : bool -{ +enum ALARM_TYPE: uint8_t { + LP = 1, + MP = 2, + HP = 3 +}; + +enum ALARM_CODES: uint8_t { + APNEA = 1, // HP + CHECK_VALVE_EXHALE = 2, // HP + CHECK_P_PATIENT = 3, // HP + EXPIRATION_SENSE_FAULT_OR_LEAK = 4, // MP + EXPIRATION_VALVE_Leak = 5, // MP + HIGH_FIO2 = 6, // MP + HIGH_PRESSURE = 7, // HP + HIGH_RR = 8, // MP + HIGH_VTE = 9, // MP + LOW_VTE = 10, // MP + HIGH_VTI = 11, // MP + LOW_VTI = 12, // MP + INTENTIONAL_STOP = 13, // HP + LOW_BATTERY = 14, // HP (LP) if AC power isn't (is) connected + LOW_FIO2 = 15, // HP + OCCLUSION = 16, // HP + HIGH_PEEP = 17, // HP + LOW_PEEP = 18, // HP + AC_POWER_DISCONNECTION = 19, // MP + BATTERY_FAULT_SRVC = 20, // MP + BATTERY_CHARGE = 21, // MP + AIR_FAIL = 22, // HP + O2_FAIL = 23, // HP + PRESSURE_SENSOR_FAULT = 24, // HP + ARDUINO_FAIL = 25 // HP +}; + +enum VALVE_STATES : bool { V_OPEN = HIGH, V_CLOSED = LOW }; -static struct struct_valve_port_states -{ +struct fsm_timeouts { + uint32_t calibration; + uint32_t buff_purge; + uint32_t buff_flush; + uint32_t buff_prefill; + uint32_t buff_fill; + uint32_t buff_loaded; + uint32_t buff_pre_inhale; + uint32_t inhale; + uint32_t pause; + uint32_t exhale_fill; + uint32_t exhale; // has to be calculated using function getTimeoutExhale() +}; + +struct alarm_thresholds { + uint32_t apnea; + uint32_t check_valve_exhale; + uint32_t check_p_patient; + uint32_t expiration_sense_fault_or_leak; + uint32_t expiration_valve_leak; + uint32_t high_fio2; + uint32_t high_pressure; + uint32_t high_rr; + uint32_t high_vte; + uint32_t low_vte; + uint32_t high_vti; + uint32_t low_vti; + uint32_t intentional_stop; + uint32_t low_battery; + uint32_t low_fio2; + uint32_t occlusion; + uint32_t high_peep; + uint32_t low_peep; + uint32_t ac_power_disconnection; + uint32_t battery_fault_srvc; + uint32_t battery_charge; + uint32_t air_fail; + uint32_t o2_fail; + uint32_t pressure_sensor_fault; + uint32_t arduino_fail; +}; + +// default values definitions +static fsm_timeouts fsm_timeout = {10000, 600, 600, 100, 600, 100, 100, 1000, 500, 600, 400}; +static alarm_thresholds alarm_threshold_min; +static alarm_thresholds alarm_threshold_max; + +static struct struct_valve_port_states { // bools are used for valves that are digitally controlled - i.e. only on or off. - bool air_in; + bool air_in; bool o2_in; - float inhale; + float inhale; float exhale; bool purge; - bool atmos; + bool atmos; } valve_port_states; // static uint32_t valve_port_states = 0x0; @@ -61,4 +169,8 @@ void setValves(bool vin_air, bool vin_o2, float vinhale, void getValves(bool &vin_air, bool &vin_o2, float &vinhale, float &vexhale, bool &vpurge, bool &vatmos); -#endif \ No newline at end of file +void setThreshold(ALARM_CODES alarm, alarm_thresholds &thresholds, uint32_t value); +void setTimeout(CMD_SET_TIMEOUT cmd, fsm_timeouts &timeouts, uint32_t value); +uint32_t getTimeoutExhale(); + +#endif diff --git a/arduino/hev_prototype_v1/src/main.cpp b/arduino/hev_prototype_v1/src/main.cpp index d366b661..62fda8c2 100644 --- a/arduino/hev_prototype_v1/src/main.cpp +++ b/arduino/hev_prototype_v1/src/main.cpp @@ -3,7 +3,7 @@ #include <Wire.h> #include "Adafruit_MCP9808.h" #include <INA.h> -#include "commsControl.h" +#include "CommsControl.h" #include "BreathingLoop.h" #include "UILoop.h" #include "common.h" @@ -27,10 +27,10 @@ float expiratory_minute_volume; // calc?? same as inspiratory_minute_volume? float trigger_sensitivity; // comms -dataFormat data; -commsControl comms; -payload plReceive; -payload plSend; +data_format data; +CommsControl comms; +Payload plReceive; +Payload plSend; // loops BreathingLoop breathing_loop; @@ -39,19 +39,19 @@ UILoop ui_loop(&breathing_loop); bool start_fsm = false; // calculations -float calc_tidal_volume() +float calcTidalVolume() { return inspiratory_minute_volume / respiratory_rate; } -float calc_expiration_time() +float calcExpirationTime() { float total_respiratory_time = 60.0 / respiratory_rate; // total = expire + inspire + pause return (total_respiratory_time - inspiratory_time - pause_time); } -float calc_expiratory_minute_volume() +float calcExpiratoryMinuteVolume() { // probably need to calculate this from readings return 0; @@ -132,22 +132,20 @@ void loop() report_cnt++; if(report_cnt % (update_freq/report_freq) == 0) { - plSend.setType(payloadType::payloadData); + plSend.setType(PAYLOAD_TYPE::DATA); plSend.setData(&data); comms.writePayload(plSend); } // per cycle sender comms.sender(); // per cycle receiver - comms.receiver(); uint8_t cmdCode = 0; if(comms.readPayload(plReceive)){ - if (plReceive.getType() == payloadType::payloadCmd) { - // cmdCode = (plReceive.getCmd()->cmdCode); + if (plReceive.getType() == PAYLOAD_TYPE::CMD) { ui_loop.doCommand(plReceive.getCmd()); - plReceive.setType(payloadType::payloadUnset); + plReceive.setType(PAYLOAD_TYPE::UNSET); } } -- GitLab