Skip to content
Snippets Groups Projects
Commit 253fc28d authored by Karol Hennessy's avatar Karol Hennessy
Browse files

first version breathing_with_comms and some additional

code functions/utilities
parent 1d21b835
Branches
No related merge requests found
Showing
with 1243 additions and 0 deletions
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html
#ifndef COMMSCONSTANTS_H
#define COMMSCONSTANTS_H
#include <Arduino.h>
#define CONST_MAX_SIZE_QUEUE 16
#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_TYPES 0x0F
#define COMMS_CONTROL_ACK 0x01
#define COMMS_CONTROL_NACK 0x05
#define PACKET_TYPE 0xC0
#define PACKET_ALARM 0xC0
#define PACKET_CMD 0x80
#define PACKET_DATA 0x40
#define PACKET_SET 0x20
// TODO: make sensible
#define PRESSURE_PEEP_LOW 0x01
#define PRESSURE_PEEP_HIGH 0x02
// struct for all data sent
// TODO: the same for all settings?
struct dataFormat {
uint16_t count;
uint16_t pressure;
};
// enum of all transfer types
enum dataType {
dataAlarm,
dataNormal,
dataCommand
};
#endif
#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_ = DataQueue<commsALARM>(CONST_MAX_SIZE_QUEUE);
queueData_ = DataQueue<commsDATA> (CONST_MAX_SIZE_QUEUE);
queueCmd_ = DataQueue<commsCMD> (CONST_MAX_SIZE_QUEUE);
commsTmp_ = commsFormat(CONST_MAX_SIZE_PACKET - CONST_MIN_SIZE_PACKET );
}
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_ + 5 ) {
sendPacket(reinterpret_cast<DataQueue<commsFormat>*>(&queueAlarm_));
}
if (millis() > lastTransTime_ + 5000 ) {
sendPacket(reinterpret_cast<DataQueue<commsFormat>*>(&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_)) {
// to decide ACK/NACK/other
uint8_t control = commsReceived_[3];
// to decide what kind of packets received
uint8_t address = commsReceived_[1];
DataQueue<commsFormat>* tmpQueue = getQueue(address);
if (tmpQueue != nullptr) {
// 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(tmpQueue);
break;
case COMMS_CONTROL_ACK:
// received ACK
finishPacket(tmpQueue);
break;
default:
// received DATA
receivePacket(tmpQueue);
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;
}
}
}
}
// adding new values into queue
// WIP
void commsControl::registerData(dataType type, dataFormat* values) {
commsDATA newValue;
// switch on different received data types
switch(type) {
case dataAlarm:
break;
case dataNormal:
newValue.setInformation(values);
break;
case dataCommand:
break;
default:
break;
}
// calculate CRC for the new entry
newValue.generateCrc();
// add new entry to the queue
queueData_.enqueue(newValue);
}
// 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::sendPacket(DataQueue<commsFormat>* queue) {
// if have data to send
if (!queue->isEmpty()) {
// reset sending counter
lastTransTime_ = millis();
// if encoded and able to write data
if (encoder(queue->front().getData(), queue->front().getSize()) ) {
if (Serial.availableForWrite() >= commsSendSize_) {
// TODO define transmission counter
// queue->front().setCounter(someValue)
Serial.write(commsSend_, commsSendSize_);
}
}
}
}
// resending the packet, can lower the timeout since either NACK or wrong FCS already checked
//WIP
void commsControl::resendPacket(DataQueue<commsFormat>* queue) {
;
}
// receiving anything of commsFormat
// WIP
void commsControl::receivePacket(DataQueue<commsFormat>* queue) {
;
}
// if FCS is ok, remove from queue
void commsControl::finishPacket(DataQueue<commsFormat>* queue) {
queue->dequeue();
}
// get link to queue according to packet format
DataQueue<commsFormat>* commsControl::getQueue(uint8_t address) {
switch (address & PACKET_TYPE) {
case PACKET_ALARM:
return reinterpret_cast<DataQueue<commsFormat>*>(&queueAlarm_);
case PACKET_CMD:
return reinterpret_cast<DataQueue<commsFormat>*>(&queueCmd_);
case PACKET_DATA:
return reinterpret_cast<DataQueue<commsFormat>*>(&queueData_);
default:
return nullptr;
}
}
#ifndef COMMS_CONTROL_H
#define COMMS_CONTROL_H
#include <Arduino.h>
#include "Queue.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);
void beginSerial();
// TODO: passed as struct, or simply array of size and memcpy? should be dataType or just define?
void registerData(dataType type, dataFormat* values);
void sender();
void receiver();
private:
DataQueue<commsFormat>* getQueue(uint8_t address);
void sendPacket (DataQueue<commsFormat>* queue);
void resendPacket (DataQueue<commsFormat>* queue);
void receivePacket(DataQueue<commsFormat>* queue);
void finishPacket (DataQueue<commsFormat>* queue);
bool encoder(uint8_t* data, uint8_t dataSize);
bool decoder(uint8_t* data, uint8_t dataStart, uint8_t dataStop);
private:
DataQueue<commsALARM> queueAlarm_;
DataQueue<commsDATA> queueData_ ;
DataQueue<commsCMD> queueCmd_ ;
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
#include "commsFormat.h"
// constructor to init variables
commsFormat::commsFormat(uint8_t infoSize) {
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;
}
// hardcoded defaults
*getStart() = COMMS_FRAME_BOUNDARY; // fixed start flag
*getAddress() = 0xFF; // 0xFF means sending to all devices
*getStop() = COMMS_FRAME_BOUNDARY; // fixed stop flag
}
void commsFormat::setCounter(uint8_t counter) {
*(getControl() + 2) |= (counter << 4);
}
// compare calculated and received CRC value
bool commsFormat::compareCrc() {
// generate data crc
generateCrc(false);
// get crc from fcs
uint16_t tmpFcs;
memcpy(&tmpFcs, getFcs(), 2);
// return comparison
return tmpFcs == crc_;
}
// calculate CRC value
void commsFormat::generateCrc(bool assign) {
// calculate crc
crc_ = uCRC16Lib::calculate(reinterpret_cast<char*>(getAddress()), infoSize_ + 3);
// assign crc to fcs
if (assign) {
memcpy(getFcs(), &crc_, 2);
}
}
// assign received information to packet
// TODO: set according to TBD dataFormat
void commsFormat::setInformation(dataFormat* values) {
// assign values to
memcpy(getInformation(), &values->count, 2);
}
void commsFormat::copyData(uint8_t* data, uint8_t dataSize) {
infoSize_ = dataSize - CONST_MIN_SIZE_PACKET;
packetSize_ = dataSize;
memset(data_, 0, sizeof(data_));
memcpy(data_, data, dataSize );
}
#ifndef COMMSFORMAT_H
#define COMMSFORMAT_H
#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* getData() { return data_; }
uint8_t getSize() { return packetSize_; }
void setInformation(dataFormat* values);
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
void setCounter(uint8_t counter);
void copyData(uint8_t* data, uint8_t dataSize);
private:
uint8_t data_[CONST_MAX_SIZE_PACKET];
uint8_t packetSize_;
uint8_t infoSize_;
uint16_t crc_;
};
///////////////////////////////////////////////////////////////////////////
// DATA specific class - contains X bytes of data
class commsDATA: public commsFormat {
public:
commsDATA() : commsFormat(8) { *(getAddress()) = 0x40; } // contains 8 information bytes
};
///////////////////////////////////////////////////////////////////////////
// ALARM specific class - contains X bytes of data and specific control flag
class commsALARM: public commsFormat {
public:
commsALARM() : commsFormat(4) { *(getAddress()) = 0xC0; } // contains 4 information bytes
};
///////////////////////////////////////////////////////////////////////////
// CMD specific class - contains X bytes of data and specific control flag
class commsCMD: public commsFormat {
public:
commsCMD() : commsFormat(8) { *(getAddress()) = 0x80; } // contains 8 information bytes
};
///////////////////////////////////////////////////////////////////////////
// ACK specific class - contains specific control flag
class commsACK : public commsFormat {
public:
commsACK() : commsFormat() { *(getControl()+1) = COMMS_CONTROL_ACK; } // contains 0 information bytes, has specific control type
};
///////////////////////////////////////////////////////////////////////////
// NACK specific class - contains specific control flag
class commsNACK: public commsFormat {
public:
commsNACK() : commsFormat() { *(getControl()+1) = COMMS_CONTROL_NACK; } // contains 0 information bytes, has specific control type
};
#endif // COMMSFORMAT_H
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
; [env:uno]
; platform = atmelavr
; framework = arduino
; board = uno
; [env:mkrvidor4000]
; platform = atmelsam
; framework = arduino
; board = mkrvidor4000
[env:featheresp32]
platform = espressif32
framework = arduino
board = featheresp32
upload_port = /dev/ttyUSB0
; [env:due]
; platform = atmelsam
; framework = arduino
; board = due
; [env:yun]
; platform = atmelavr
; framework = arduino
; board = yun
; [env:mkrwifi1010]
; platform = atmelsam
; framework = arduino
; board = mkrwifi1010
; [env:nodemcu-32s]
; platform = espressif32
; framework = arduino
; board = nodemcu-32s
// Arduino Due
//#include <LiquidCrystal.h>
// pwm pins
const int pin_valve_in = 11;
const int pin_valve_out = 6;
const int pin_valve_scavenge = 5;
const int pin_valve_purge = 3;
// adcs
const int pin_p_supply = A0;
const int pin_p_regulated = A1;
const int pin_p_buffer = A2;
const int pin_p_inhale = A3;
const int pin_p_patient = A4;
const int pin_temp = A5;
// leds
const int pin_led_0 = 0;
const int pin_led_1 = 1;
const int pin_led_2 = 2;
// buzzer
const int pin_buzzer = 9;
// lcd
const int pin_lcd_rs = 13;
const int pin_lcd_en = 4;
const int pin_lcd_d4 = 7;
const int pin_lcd_d5 = 8;
const int pin_lcd_d6 = 10;
const int pin_lcd_d7 = 12;
const int pin_button_0 = 14;
\ No newline at end of file
// Arduino MKR 1010 Wifi
// pwm pins
const int pin_valve_in = 2;
const int pin_valve_out = 3;
const int pin_valve_scavenge = 4;
const int pin_valve_purge = 5;
// adcs
const int pin_p_supply = A0;
const int pin_p_regulated = A1;
const int pin_p_buffer = A2;
const int pin_p_inhale = A3;
const int pin_p_patient = A4;
const int pin_temp = A5;
// leds
const int pin_led_0 = 6;
const int pin_led_1 = 7;
const int pin_led_2 = 8;
// buzzer
const int pin_buzzer = 0;
// lcd
const int pin_lcd_rs = 9;
const int pin_lcd_en = 10;
const int pin_lcd_d4 = 11;
const int pin_lcd_d5 = 12;
const int pin_lcd_d6 = 13;
const int pin_lcd_d7 = 14;
// buttons
const int pin_button_0 = 1;
\ No newline at end of file
// arduino MKR 4000 Vidor
// pwm pins
const int pin_valve_in = 2;
const int pin_valve_out = 3;
const int pin_valve_scavenge = 4;
const int pin_valve_purge = 5;
// adcs
const int pin_p_supply = A0;
const int pin_p_regulated = A1;
const int pin_p_buffer = A2;
const int pin_p_inhale = A3;
const int pin_p_patient = A4;
const int pin_temp = A5;
// leds
const int pin_led_0 = 6;
const int pin_led_1 = 7;
const int pin_led_2 = 8;
// buzzer
const int pin_buzzer = 0;
// lcd
const int pin_lcd_rs = 9;
const int pin_lcd_en = 10;
const int pin_lcd_d4 = 11;
const int pin_lcd_d5 = 12;
const int pin_lcd_d6 = 13;
const int pin_lcd_d7 = 14;
// buttons
const int pin_button_0 = 1;
// Arduino Yun
//#include <LiquidCrystal.h>
// pwm pins
const int pin_valve_in = 11;
const int pin_valve_out = 6;
const int pin_valve_scavenge = 5;
const int pin_valve_purge = 3;
// adcs
const int pin_p_supply = A0;
const int pin_p_regulated = A1;
const int pin_p_buffer = A2;
const int pin_p_inhale = A3;
const int pin_p_patient = A4;
const int pin_temp = A5;
// leds
const int pin_led_0 = 0;
const int pin_led_1 = 1;
const int pin_led_2 = 2;
// buzzer
const int pin_buzzer = 9;
// lcd
const int pin_lcd_rs = 13;
const int pin_lcd_en = 4;
const int pin_lcd_d4 = 7;
const int pin_lcd_d5 = 8;
const int pin_lcd_d6 = 10;
const int pin_lcd_d7 = 12;
const int pin_button_0 = 1;
\ No newline at end of file
// Arduino Uno
//#include <LiquidCrystal.h>
// pwm pins
const int pin_valve_in = 11;
const int pin_valve_out = 6;
const int pin_valve_scavenge = 5;
const int pin_valve_purge = 3;
// adcs
const int pin_p_supply = A0;
const int pin_p_regulated = A1;
const int pin_p_buffer = A2;
const int pin_p_inhale = A3;
const int pin_p_patient = A4;
const int pin_temp = A5;
// leds
const int pin_led_0 = 0;
const int pin_led_1 = 1;
const int pin_led_2 = 2;
// buzzer
const int pin_buzzer = 9;
// lcd
// const int pin_lcd_rs = 13;
// const int pin_lcd_en = 4;
// const int pin_lcd_d4 = 7;
// const int pin_lcd_d5 = 8;
// const int pin_lcd_d6 = 10;
// const int pin_lcd_d7 = 12;
const int pin_button_0 = 13;
#include <Wire.h> // I2C control
// #include <LiquidCrystal_I2C.h> //LCD over I2C
// ESP32 HUZZAH
// pwm pins
const int pin_valve_in = 13;
const int pin_valve_out = 12;
const int pin_valve_scavenge = 27;
const int pin_valve_purge = 21;
// adcs
const int pin_p_supply = A0;
const int pin_p_regulated = A1;
const int pin_p_buffer = A2;
const int pin_p_inhale = A3;
const int pin_p_patient = A4;
const int pin_temp = A13;
// leds
const int pin_led_0 = 33;
const int pin_led_1 = 15;
const int pin_led_2 = 32;
// buzzer
const int pin_buzzer = 14;
// buttons
const int pin_button_0 = 4;
// lcd Not enough GPIOs, we can use I2C if needed NOTE: This code was not tested through I2C
// constants needed
// by default static DO NOT UNCOMMENT SDA AND SCL LINES
// const uint8_t SDA = 23;
// static const uint8_t SCL = 22;
const int LCD_Address = 0x27;
const int LCD_columns = 16;
const int LCD_rows = 2;
/* In case that we want to use the LCD we must
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(LCD_Address, LCD_columns, LCD_rows);
void setup(){
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
}
void loop(){
// set cursor to first column, first row
lcd.setCursor(0, 0);
// print message
lcd.print("Hello, World!");
delay(1000);
// clears the display to print new message
}
*/
#include <Arduino.h>
#include "commsControl.h"
//#include <LiquidCrystal.h>
#if defined(ARDUINO_FEATHER_ESP32)
#define BOARD "HUZZAH32"
#include <huzzah32_pinout.h>
#elif defined(ARDUINO_NodeMCU_32S)
#define BOARD "ESP32"
#include <nodemcu_32s_pinout.h>
#elif defined(ARDUINO_AVR_UNO)
#define BOARD "UNO"
#include <Arduino_uno_pinout.h>
#elif defined(ARDUINO_SAMD_MKRVIDOR4000)
#define BOARD "VIDOR"
#include <Arduino_MKR_4000_Vidor_pinout.h>
#elif defined(ARDUINO_SAMD_MKRWIFI1010)
#define BOARD "MKR1010"
#include <Arduino_MKR_1010_WIFI_pinout.h>
#elif defined(ARDUINO_SAM_DUE)
#define BOARD "MKR1010"
#include <Arduino_Due_pinout.h>
#elif defined(ARDUINO_AVR_YUN)
#define BOARD "MKR1010"
#include <Arduino_Yun_pinout.h>
#endif
//LiquidCrystal lcd(pin_lcd_rs, pin_lcd_en, pin_lcd_d4, pin_lcd_d5, pin_lcd_d6, pin_lcd_d7);
// input params
enum hev_modes : byte
{
HEV_MODE_PS,
HEV_MODE_CPAP,
HEV_MODE_PRVC,
HEV_MODE_TEST
};
enum valve_states : bool
{
V_OPEN = LOW,
V_CLOSED = HIGH
};
enum lab_cycle_modes : byte
{
LAB_MODE_BREATHE = 0,
LAB_MODE_PURGE = 1,
LAB_MODE_FLUSH = 2
};
int ventilation_mode = HEV_MODE_PS;
float working_pressure = 1; //?
float inspiratory_minute_volume = 6000; // ml/min
float respiratory_rate = 15; // 10-40 +-1 ;aka breaths_per_min
float inspiratory_pressure = 10; // 10-80 cmH2O +-1
//float tidal_volume = 200; // calc 200-1500ml +- 100
float inspiratory_time = 1.0; // 0.4-1.5s +-0.1
float pause_time = 1.0; // range?
//float expiratory_time ; // calc
float expiratory_minute_volume; // calc?? same as inspiratory_minute_volume?
float trigger_sensitivity;
// states
enum BS_STATES : byte
{
BS_IDLE,
BS_BUFF_PREFILL,
BS_BUFF_FILL,
BS_BUFF_LOADED,
BS_BUFF_PRE_INHALE,
BS_INHALE,
BS_WAIT,
BS_EXHALE_FILL,
BS_EXHALE,
BS_BUFF_PURGE,
BS_BUFF_FLUSH
};
int bs_state = BS_IDLE;
byte lab_cycle_mode = 0;
bool start = LOW;
// calculations
float calc_tidal_volume()
{
return inspiratory_minute_volume / respiratory_rate;
}
float calc_expiration_time()
{
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()
{
// probably need to calculate this from readings
return 0;
}
// FROM OVERLEAF DOC
// Working pressure, corresponding to the manually set and monitored input pressure to the unit
// Inspiratory Minute Volume setting
// Breaths per minute setting
// Tidal volume display, based on previous two parameters
// Inspiration time setting
// Pause time setting
// expiration time display based on previous two parameters
// expired minute volume
// Airway pressure display based on the reading of $P_2$ ??? not a setting
// PEEP setting ??? external
// Trigger sensitivity to patient initiated breath
dataFormat data;
commsControl comms;
int currentState = 0;
int previousState = 0;
void setup()
{
pinMode(pin_valve_in, OUTPUT);
pinMode(pin_valve_out, OUTPUT);
pinMode(pin_valve_scavenge, OUTPUT);
pinMode(pin_valve_purge, OUTPUT);
pinMode(pin_p_supply, INPUT);
pinMode(pin_p_regulated, INPUT);
pinMode(pin_p_buffer, INPUT);
pinMode(pin_p_inhale, INPUT);
pinMode(pin_p_patient, INPUT);
pinMode(pin_temp, INPUT);
pinMode(pin_led_0, OUTPUT);
pinMode(pin_led_1, OUTPUT);
pinMode(pin_led_2, OUTPUT);
pinMode(pin_buzzer, OUTPUT);
pinMode(pin_button_0, INPUT);
// Serial.begin(9600);
comms.beginSerial();
data.count = 0;
// lcd.begin(16, 2); // Declare number of columns and rows
}
void setValves(bool vin, bool vout, bool vscav, bool vpurge)
{
digitalWrite(pin_valve_in, vin);
digitalWrite(pin_valve_out, vout);
digitalWrite(pin_valve_scavenge, vscav);
digitalWrite(pin_valve_purge, vpurge);
}
void breath_cycle()
{
// basic cycle for testing hardware
int next_state;
switch (bs_state)
{
case BS_IDLE:
start = digitalRead(pin_button_0);
if (start == HIGH)
{
next_state = BS_BUFF_PREFILL;
}
else
{
delay(1000);
next_state = BS_IDLE;
}
setValves(V_CLOSED, V_OPEN, V_OPEN, V_CLOSED);
break;
case BS_BUFF_PREFILL:
setValves(V_CLOSED, V_CLOSED, V_OPEN, V_CLOSED);
delay(1000);
next_state = BS_BUFF_FILL;
break;
case BS_BUFF_FILL:
setValves(V_OPEN, V_CLOSED, V_OPEN, V_CLOSED);
delay(500);
next_state = BS_BUFF_LOADED;
break;
case BS_BUFF_LOADED:
setValves(V_CLOSED, V_CLOSED, V_OPEN, V_CLOSED);
switch (lab_cycle_mode)
{
case LAB_MODE_FLUSH:
delay(500);
next_state = BS_BUFF_FLUSH;
break;
case LAB_MODE_PURGE:
delay(500);
next_state = BS_BUFF_PURGE;
break;
default:
delay(1500);
next_state = BS_BUFF_PRE_INHALE;
}
break;
case BS_BUFF_PRE_INHALE:
setValves(V_CLOSED, V_CLOSED, V_CLOSED, V_CLOSED);
delay(100);
next_state = BS_INHALE;
break;
case BS_INHALE:
setValves(V_CLOSED, V_OPEN, V_CLOSED, V_CLOSED);
delay(100);
next_state = BS_WAIT;
break;
case BS_WAIT:
setValves(V_CLOSED, V_CLOSED, V_CLOSED, V_CLOSED);
delay(1000);
next_state = BS_EXHALE_FILL;
break;
case BS_EXHALE_FILL:
setValves(V_OPEN, V_CLOSED, V_OPEN, V_CLOSED);
delay(1000);
next_state = BS_EXHALE;
break;
case BS_EXHALE:
setValves(V_CLOSED, V_CLOSED, V_OPEN, V_CLOSED);
delay(10);
next_state = BS_BUFF_LOADED;
break;
case BS_BUFF_PURGE:
setValves(V_CLOSED, V_CLOSED, V_OPEN, V_OPEN);
delay(1000);
next_state = BS_BUFF_PREFILL;
break;
case BS_BUFF_FLUSH:
setValves(V_CLOSED, V_OPEN, V_OPEN, V_CLOSED);
delay(1000);
next_state = BS_IDLE;
break;
default:
next_state = bs_state;
}
bs_state = next_state;
}
void loop()
{
// put your main code here, to run repeatedly:
//Serial.println(BOARD);
// delay(1000);
// buzzer
// tone(pin, freq (Hz), duration);
breath_cycle();
// Serial.println("state: " + String(bs_state));
data.count = 1;
data.pressure = bs_state; //fake
comms.registerData(dataNormal, &data);
// per cycle sender
comms.sender();
// per cycle receiver
comms.receiver();
}
#include <Wire.h> // I2C control
// #include <LiquidCrystal_I2C.h> //LCD over I2C
// Node MCU 32s
// pwm pins
const int pin_valve_in = 6;
const int pin_valve_out = 7;
const int pin_valve_scavenge = 8;
const int pin_valve_purge = 15;
// adcs
const int pin_p_supply = A0;
const int pin_p_regulated = A3;
const int pin_p_buffer = A6;
const int pin_p_inhale = A7;
const int pin_p_patient = A4;
const int pin_temp = A5;
// leds
const int pin_led_0 = 13;
const int pin_led_1 = 9;
const int pin_led_2 = 10;
// buzzer
const int pin_buzzer = 11;
// buttons
const int pin_button_0 = 2;
// lcd Not enough GPIOs, we can use I2C if needed NOTE: This code was not tested through I2C
// constants needed
// by default static DO NOT UNCOMMENT SDA AND SCL LINES
// const uint8_t SDA = 23;
// static const uint8_t SCL = 22;
const int LCD_Address = 0x27;
const int LCD_columns = 16;
const int LCD_rows = 2;
/* In case that we want to use the LCD we must
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(LCD_Address, LCD_columns, LCD_rows);
void setup(){
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
}
void loop(){
// set cursor to first column, first row
lcd.setCursor(0, 0);
// print message
lcd.print("Hello, World!");
delay(1000);
// clears the display to print new message
}
*/
This directory is intended for PIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < https://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < https://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
#
#
# Please choose one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
#
# Template #1: General project. Test it using existing `platformio.ini`.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio run
#
# Template #2: The project is intended to be used as a library with examples.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# env:
# - PLATFORMIO_CI_SRC=path/to/test/file.c
# - PLATFORMIO_CI_SRC=examples/file.ino
# - PLATFORMIO_CI_SRC=path/to/test/directory
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment