software:firmware
MakAir Firmware
serial_control.cpp
Go to the documentation of this file.
1 
8 #pragma once
9 
10 #include "../includes/config.h"
11 
12 // INCLUDES ===================================================================
13 
14 // Associated header
15 #include "../includes/serial_control.h"
16 
17 // Externals
18 #include "Arduino.h"
19 #include "CRC32.h"
20 
22 #include "../includes/activation.h"
23 #include "../includes/alarm_controller.h"
24 #include "../includes/main_controller.h"
25 #include "../includes/rpi_watchdog.h"
26 
27 // INITIALISATION =============================================================
28 
29 #define CONTROL_HEADER_SIZE 2
30 static const uint8_t header[CONTROL_HEADER_SIZE] = {0x05, 0x0A};
31 #define CONTROL_FOOTER_SIZE 2
32 static const uint8_t footer[CONTROL_FOOTER_SIZE] = {0x50, 0xA0};
33 
34 // FUNCTIONS ==================================================================
35 
42 // cppcheck-suppress unusedFunction
43 uint16_t toU16(byte bytes[]) {
44  uint16_t num = (bytes[0] << 8) + bytes[1];
45  return num;
46 }
47 
54 // cppcheck-suppress unusedFunction
55 uint32_t toU32(byte bytes[]) {
56  uint32_t num = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
57  return num;
58 }
59 
60 // cppcheck-suppress unusedFunction
62  // Let's note this current time to avoid blocking too long here
63  int time = millis();
64 
65  // We need to ensure we received the whole message
66  while (((time + 2) >= millis()) && (Serial6.available() >= 11)) {
67  // Let's check the first header byte
68  if (Serial6.peek() == header[0]) {
69  // If it is correct, we discard it and continue
70  (void)Serial6.read();
71 
72  // Let's check the second header byte
73  if (Serial6.peek() == header[1]) {
74  // If it is correct, we discard it and continue
75  (void)Serial6.read();
76 
77  // Let's prepare to compute a CRC
78  CRC32 computedCRC;
79 
80  byte setting = Serial6.read();
81  computedCRC.update(setting);
82 
83  byte rawValue[2];
84  Serial6.readBytes(rawValue, 2);
85  computedCRC.update(rawValue, 2);
86  uint16_t value = toU16(rawValue);
87 
88  byte rawExpectedCRC[4];
89  Serial6.readBytes(rawExpectedCRC, 4);
90  uint32_t expectedCRC = toU32(rawExpectedCRC);
91 
92  // Let's check that the 2 bytes footer is correct
93  if ((Serial6.read() != footer[0]) || (Serial6.read() != footer[1])) {
94  DBG_DO(Serial.println(
95  "Invalid footer for control message; discarding whole message"));
96  continue;
97  }
98 
99  // The computed CRC must be the same as the one included with the message
100  if (expectedCRC != computedCRC.finalize()) {
101  DBG_DO(Serial.println(
102  "Invalid CRC for control message; discarding whole message"));
103  continue;
104  }
105 
106  DBG_DO({
107  Serial.print("Serial control message: setting = ");
108  Serial.print(setting);
109  Serial.print(", value = ");
110  Serial.print(value);
111  Serial.println();
112  });
113 
114  switch (setting) {
115  case Heartbeat:
116  if (value == DISABLE_RPI_WATCHDOG) {
118  } else {
120  }
121  break;
122 
123  case VentilationMode:
125  break;
126 
127  case PlateauPressure:
129  break;
130 
131  case PEEP:
132  mainController.onPeepSet(value);
133  break;
134 
135  case CyclesPerMinute:
136  mainController.onCycleSet(value);
137  break;
138 
139  case ExpiratoryTerm:
141  break;
142 
143  case TriggerEnabled:
145  break;
146 
147  case TriggerOffset:
149  break;
150 
151  case RespirationEnabled:
153  break;
154 
155  case AlarmSnooze:
157  break;
158 
161  break;
162 
165  break;
166 
167  case TiMin:
168  mainController.onTiMinSet(value);
169  break;
170 
171  case TiMax:
172  mainController.onTiMaxSet(value);
173  break;
174 
177  break;
178 
181  break;
182 
185  break;
186 
189  break;
190 
193  break;
194 
197  break;
198 
199  case TargetTidalVolume:
201  break;
202 
205  break;
206 
209  break;
210 
211  case PlateauDuration:
213  break;
214 
215  case LeakAlarmThreshold:
217  break;
218 
221  break;
222 
223  case InspiratoryDuration:
225  break;
226 
227  case Locale:
228  // TODO
229  break;
230 
231  case PatientHeight:
233  break;
234 
235  case PatientGender:
237  break;
238 
241  break;
242 
243  case EolConfirm:
244  eolTest.onConfirm();
245  break;
246 
247  default:
248  DBG_DO({
249  Serial.print("Unknown control setting: ");
250  Serial.print(setting);
251  Serial.println();
252  });
253  break;
254  }
255  } else {
256  // This is not the begining of a message, let's discard it
257  (void)Serial6.read();
258  DBG_DO(Serial.println("Invalid header for control message; discarding a byte"));
259  }
260  } else {
261  // This is not the begining of a message, let's discard it
262  (void)Serial6.read();
263  DBG_DO(Serial.println("Invalid header for control message; discarding a byte"));
264  }
265  }
266 }
ActivationController activationController
Instance of the activation controller.
Definition: activation.cpp:21
AlarmController alarmController
Instance of the alarm controller.
void changeState(uint16_t state)
Change the current state.
Definition: activation.cpp:29
void snooze()
Snooze alarm for 2 minutes.
void onConfirm()
Handle EOL confirm control setting from telemetry.
void onTargetInspiratoryFlow(uint16_t p_targetInspiratoryFlow)
Set the inspiratory flow target.
void onTriggerOffsetSet(uint16_t p_triggerOffset)
Set the desired offset for expiratory trigger.
void onInspiratoryDuration(uint16_t p_inspiratoryDuration)
Set the inspiration duration.
void onCycleSet(uint16_t p_cpm)
Set the desired number of cycles per minute.
void onLowTidalVolumeAlarmThresholdSet(uint16_t p_lowTidalVolumeAlarmThreshold)
Set threshold on tidal volume below which an alarm is raised.
void onlowRespiratoryRateAlarmThresholdSet(uint16_t p_lowRespiratoryRateAlarmThreshold)
Set alarm threshold for low respiratory rate.
void onLeakAlarmThresholdSet(uint16_t p_leakAlarmThreshold)
Set the threshold for leak that raise the alarm.
void onExpiratoryTermSet(uint16_t p_expiratoryTerm)
Set the desired expiratory term.
void onhighRespiratoryRateAlarmThresholdSet(uint16_t p_highRespiratoryRateAlarmThreshold)
Set alarm threshold for high respiratory rate.
void onTiMinSet(uint16_t p_tiMin)
Set min inspiratory time.
void onInspiratoryTriggerFlowSet(uint16_t p_inspiratoryTriggerFlow)
Set inspiratory trigger flow.
void onTiMaxSet(uint16_t p_tiMax)
Set max inspiratory time.
void onPeepSet(int16_t p_peep)
Set the desired PEEP.
void onPeakPressureAlarmThreshold(int16_t p_peakPressureAlarmThreshold)
Set the desired threshold for max peak pressure.
void onLowExpiratoryMinuteVolumeAlarmThresholdSet(uint16_t p_lowExpiratoryMinuteVolumeAlarmThreshold)
Set alarm threshold for low expiratory minute volume.
void onPlateauPressureSet(int16_t p_plateauPressure)
Set the desired plateau pressure.
void onPatientHeight(int16_t p_patientHeight)
Set the desired patient height.
void onPatientGender(int16_t p_patientGender)
Set the desired patient gender.
void onLowInspiratoryMinuteVolumeAlarmThresholdSet(uint16_t p_lowInspiratoryMinuteVolumeAlarmThreshold)
Set alarm threshold for low inspiratory minute volume.
void onHighInspiratoryMinuteVolumeAlarmThresholdSet(uint16_t p_highInspiratoryMinuteVolumeAlarmThreshold)
Set alarm threshold for high inspiratory minute volume.
void onVentilationModeSet(uint16_t p_ventilationControllerMode)
Set ventilation mode.
void onTargetTidalVolumeSet(uint16_t p_targetTidalVolume)
Set target tidal volume (used in VC modes)
void onHighExpiratoryMinuteVolumeAlarmThresholdSet(uint16_t p_highExpiratoryMinuteVolumeAlarmThreshold)
Set alarm threshold for high expiratory minute volume.
void onPlateauDurationSet(uint16_t p_plateauDuration)
Set the duration of Pause at the end of expiration in VC modes.
void onExpiratoryTriggerFlowSet(uint16_t p_expiratoryTriggerFlow)
Set expiratory trigger flow.
void onTriggerModeEnabledSet(uint16_t p_triggerEnabled)
Enable or disable expiratory trigger mode.
void onHighTidalVolumeAlarmThresholdSet(uint16_t p_highTidalVolumeAlarmThreshold)
Set threshold on tidal volume for which an alarm is raised.
void disable()
Disable countdown mode (used for debug)
void resetCountDown()
When the UI software on the Raspberry PI sends a heartbeat, reset countdown.
#define DBG_DO(statement)
Expand arbitrary code only when in debug mode.
Definition: debug.h:24
EolTest eolTest
MainController mainController
HardwareSerial Serial6(PIN_TELEMETRY_SERIAL_RX, PIN_TELEMETRY_SERIAL_TX)
RpiWatchdog rpiWatchdog
void serialControlLoop()
Parse input and handle changes of settings.
#define CONTROL_HEADER_SIZE
Internals.
static const uint8_t header[CONTROL_HEADER_SIZE]
#define CONTROL_FOOTER_SIZE
uint16_t toU16(byte bytes[])
Convert an array of 2 bytes to a u16.
static const uint8_t footer[CONTROL_FOOTER_SIZE]
uint32_t toU32(byte bytes[])
Convert an array of 4 bytes to a u32.
#define DISABLE_RPI_WATCHDOG
Special value that can be used in a heartbeat control message to disable RPi watchdog.
@ PatientHeight
Patient's height in centimeters.
@ Heartbeat
Heartbeat used for the RPi watchdog feature (value is ignored except for the special value DISABLE_RP...
@ CyclesPerMinute
Number of cycles per minute (value bounds must be between 5 and 35)
@ TiMin
Minimum duration of inhalation in ms (value bounds must be between 100 and 3000)
@ HighInspiratoryMinuteVolumeAlarmThreshold
Threshold for high inspiratory minute volume alarm in L/min (value bounds must be between 10 and 40)
@ RespirationEnabled
State of the respiration (value must be 1 if enabled and 0 if disabled)
@ ExpiratoryTriggerFlow
Expiratory trigger flow in percent.
@ LowTidalVolumeAlarmThreshold
Threshold for low tidal volume in mL (value bounds must be between 0 and 1000)
@ TriggerEnabled
State of the trigger (value must be 1 if enabled and 0 if disabled)
@ PatientGender
Patient's gender (0 = male, 1 = female)
@ EolConfirm
Confirm end-of-line test step (value bounds must be between 0 and 0)
@ HighRespiratoryRateAlarmThreshold
Threshold for high respiratory rate alarm in cycle per minute (value bounds must be between 15 and 35...
@ LowExpiratoryMinuteVolumeAlarmThreshold
Threshold for low expiratory minute volume alarm in L/min (value bounds must be between 0 and 20)
@ LowInspiratoryMinuteVolumeAlarmThreshold
Threshold for low inspiratory minute volume alarm in L/min (value bounds must be between 0 and 20)
@ TargetTidalVolume
Target tidal volume in mL (value bounds must be between 50 and 2000)
@ LeakAlarmThreshold
Threshold for leak alarm in cL/min (value bounds must be between 0 and 10000)
@ InspiratoryDuration
Duration of inspiration in ms (value bounds must be between 200 and 3000)
@ HighTidalVolumeAlarmThreshold
Threshold for high tidal volume in mL (value bounds must be between 50 and 2000)
@ TargetInspiratoryFlow
Target flow during inspiration in L/min (value bounds must be between 5 and 80)
@ HighExpiratoryMinuteVolumeAlarmThreshold
Threshold for high expiratory minute volume alarm in L/min (value bounds must be between 10 and 40)
@ InspiratoryTriggerFlow
Inspiratory trigger flow in percent.
@ LowRespiratoryRateAlarmThreshold
Threshold for low respiratory rate alarm in cycle per minute (value bounds must be between 5 and 25)
@ Locale
Language of the system; this should be two letters (see ISO 639-1) in ASCII representation as two u8.
@ ExpiratoryTerm
Expiration term in the "Inspiration/Expiration" ratio given that Inspiration = 10 (value bounds must ...
@ PlateauPressure
Plateau pressure in mmH2O (value bounds must be between 100 and 400)
@ TiMax
Maximum duration of inhalation in ms (value bounds must be between 200 and 5000)
@ TriggerOffset
Trigger offset in mmH2O (value bounds must be between 0 and 100)
@ PEEP
PEEP in mmH2O (value bounds must be between 0 and 300)
@ AlarmSnooze
Alarm snooze (value must be 1 to snooze and 0 to unsnooze)
@ VentilationMode
Ventilation mode, must be one of the following:
@ PeakPressureAlarmThreshold
Threshold for peak pressure alarm in mmH2O (value bounds must be between 50 and 700)
@ PlateauDuration
Duration in ms of closing both valves to effectively measure plateau pressure in volume control modes...