software:firmware
MakAir Firmware
main_state_machine.cpp
Go to the documentation of this file.
1 
8 #pragma once
9 
10 // INCLUDES ===================================================================
11 
12 #include "../includes/parameters.h"
13 #include "Arduino.h"
14 #include <IWatchdog.h>
15 
16 #include "../includes/activation.h"
17 #include "../includes/battery.h"
18 #include "../includes/buzzer_control.h"
19 #include "../includes/debug.h"
20 #include "../includes/keyboard.h"
21 #include "../includes/main_controller.h"
22 #include "../includes/main_state_machine.h"
23 #include "../includes/mass_flow_meter.h"
24 #include "../includes/pressure.h"
25 #include "../includes/rpi_watchdog.h"
26 #include "../includes/screen.h"
27 #include "../includes/serial_control.h"
28 #include "../includes/telemetry.h"
29 
30 // INITIALISATION =============================================================
31 
33 
34 uint32_t clockMsmTimer = 0;
35 uint32_t lastMillis = 0;
37 HardwareTimer* msmTimer;
38 uint32_t lastMicro = 0;
39 uint32_t tick = 0;
40 
41 // cppcheck-suppress misra-c2012-12.3 ; cppcheck error
43 
46 
47 // FUNCTIONS ==================================================================
48 
49 // cppcheck-suppress misra-c2012-5.2 ; false positive
51 
53 
60  if (msmstep == STOPPED) {
62  }
63 }
64 
65 // API update since version 1.9.0 of Arduino_Core_STM32
66 #if (STM32_CORE_VERSION < 0x01090000)
67 // cppcheck-suppress misra-c2012-2.7 ; valid unused parameter
68 void millisecondTimerMSM(HardwareTimer*) // NOLINT(readability/casting)
69 #else
70 void millisecondTimerMSM(void)
71 #endif
72 {
73  IWatchdog.reload();
74  clockMsmTimer++;
75  int32_t pressure = inspiratoryPressureSensor.read();
77 
78  if ((clockMsmTimer % 10u) == 0u) {
79  // Check if some buttons have been pushed
80  keyboardLoop();
81  // Check if battery state has changed
83  // Check serial input
85 
87  // Delay will trigger the watchdog and the machine will restart with a message
88  // on screen
89  delay(10000);
90  }
92  }
93 
94  // Because this kind of LCD screen is not reliable, we need to reset it every 5 min or
95  // so
96  if ((clockMsmTimer % 300000u) == 0u) {
97  DBG_DO(Serial.println("resetting LCD screen");)
98  resetScreen();
100  }
101 
102  // Refresh screen every 300 ms, no more
103  if ((clockMsmTimer % 300u) == 0u) {
105  }
106 
107  // Check that the UI software on the Raspberry PI has sent a heartbeat in the last 60s
108  // Otherwise restart the power
109  if ((clockMsmTimer % 1000u) == 0u) {
111  }
112 
113  if (msmstep == SETUP) {
117  msmstep = STOPPED;
118  } else if (msmstep == STOPPED) {
119  // Executed just after booting, until the first start
120  if ((clockMsmTimer % 100u) == 0u) {
121  mainController.stop(millis());
123  }
124 
125  if ((clockMsmTimer % 10u) == 0u) {
126  tick++; // Also increase ticks during stop, for alarm controller
127  }
128 
132  // set patient height to default value
133  if (mainController.patientHeight() == 0) {
135  }
136  }
137 
138  } else if (msmstep == INIT_CYCLE) {
140  lastMillis = millis();
141  lastMainControllerCall = millis();
142  tick = 0;
143  msmstep = BREATH;
144 #ifdef MASS_FLOW_METER_ENABLED
145  (void)MFM_read_milliliters(true); // Reset volume integral
146 #endif
147 #ifdef MASS_FLOW_METER_ENABLED&& MASS_FLOW_METER_SENSOR_EXPI
148  (void)MFM_expi_read_milliliters(true); // Reset volume integral
149 #endif
150 
151  } else if (msmstep == BREATH) {
152  // If breathing
153  uint32_t currentMillis = millis();
154  tick = (currentMillis - lastMillis) / MAIN_CONTROLLER_COMPUTE_PERIOD_MS;
155 
157  if (tick >= mainController.ticksPerCycle()) {
158  msmstep = END_CYCLE;
159  } else {
160  uint32_t currentMicro = micros();
161  int32_t inspiratoryflow = 0;
162  int32_t expiratoryflow = 0;
163 #ifdef MASS_FLOW_METER_ENABLED
164  inspiratoryflow = MFM_read_airflow();
166 #endif
167  mainController.updateInspiratoryFlow(inspiratoryflow);
168 
169 #ifdef MASS_FLOW_METER_ENABLED&& MASS_FLOW_METER_SENSOR_EXPI
170  expiratoryflow = MFM_expi_read_airflow();
171  mainController.updateExpiratoryFlow(expiratoryflow);
173 #else
175 #endif
176  mainController.updateDt(currentMicro - lastMicro);
177  lastMicro = currentMicro;
180  lastMainControllerCall = currentMillis;
181  tick++;
182  }
183  }
184 
185  if (mainController.triggered()) {
187  }
188 
189  // Check if machine has been paused
192  msmstep = SETUP;
193  }
194  } else if (msmstep == TRIGGER_RAISED) {
196  msmstep = END_CYCLE;
197  } else {
198  msmstep = SETUP;
199  }
200  } else if (msmstep == END_CYCLE) {
207  } else {
208  msmstep = SETUP;
209  }
210  } else {
211  // Do nothing
212  }
213 
215 }
216 
218  isMsmActive = true;
219  ::clockMsmTimer = 0;
220  ::msmTimer = new HardwareTimer(TIM9);
221  // Set a 1 ms timer for the event loop
222  // Prescaler at 10 kHz; stm32f411 clock is 100 mHz
223  ::msmTimer->setPrescaleFactor((::msmTimer->getTimerClkFreq() / 10000) - 1);
224  // Set the period at 1 ms
225  ::msmTimer->setOverflow(10);
226  // priority level :
227  // https://stm32f4-discovery.net/2014/05/stm32f4-stm32f429-nvic-or-nested-vector-interrupt-controller/
228  ::msmTimer->setInterruptPriority(6, 0);
229  ::msmTimer->setMode(1, TIMER_OUTPUT_COMPARE, NC);
230  ::msmTimer->attachInterrupt(millisecondTimerMSM);
231  ::msmTimer->resume();
232 }
ActivationController activationController
Instance of the activation controller.
Definition: activation.cpp:21
AlarmController alarmController
Instance of the alarm controller.
bool isBatteryDeepDischarged()
Check if battery is deeply discharged.
Definition: battery.cpp:136
void batteryLoop(uint32_t p_cycleNumber)
Handle battery events.
Definition: battery.cpp:117
bool isRunning() const
Return if breathing is activated or not.
Definition: activation.h:32
void refreshState()
Refresh the current state.
Definition: activation.cpp:49
void runAlarmEffects(uint32_t p_tick)
Run effects (buzzer, LCD message, LED) according to the currently triggered alarms.
const bool triggered() const
Get the state of the inspiratory trigger.
void updateFakeExpiratoryFlow()
Calculate expiratory flow from pressure and valve angle.
uint16_t tidalVolumeMeasure() const
Get the measured Tidal Volume. Updated only at the end of inspiration.
int16_t peepNextCommand() const
Get the desired PEEP for the next cycle.
int16_t plateauPressureNextCommand() const
Get the desired plateau pressure for the next cycle.
int32_t patientHeight() const
int16_t peakPressureNextCommand() const
Get the desired max peak for the next cycle.
void endRespiratoryCycle(uint32_t p_currentMillis)
End a respiratory cycle.
uint16_t ticksPerCycle() const
Get the duration of a cycle in ticks.
uint16_t cyclesPerMinuteNextCommand() const
Get the desired number of cycles per minute for the next cycle.
void updateDt(int32_t p_dt)
Input the real duration since the last pressure controller computation.
void updateExpiratoryFlow(int32_t p_currentExpiratoryFlow)
Input an expiratory flow reading.
void updateCurrentExpiratoryVolume(int32_t p_expiratoryVolume)
void updateCurrentDeliveredVolume(int32_t p_currentDeliveredVolume)
Input the current delivered volume in inspiratory branch since beginning of the respiratory cycle.
int16_t peakPressureMeasure() const
Get the measured peak pressure.
void updatePressure(int16_t p_currentPressure)
Input a pressure reading.
int16_t peepMeasure() const
Get the measured PEEP.
void setup()
Initialize actuators.
void initRespiratoryCycle()
Begin a respiratory cycle.
void onPatientHeight(int16_t p_patientHeight)
Set the desired patient height.
void stop(uint32_t p_currentMillis)
Stop the breathing.
void compute()
Perform the pressure control.
int16_t plateauPressureMeasure() const
Get the measured plateau pressure.
void updateTick(uint32_t p_tick)
Input a tick number.
void updateInspiratoryFlow(int32_t p_currentInspiratoryFlow)
Input an inspiratory flow reading.
uint32_t cycleNumber() const
Get the number of past cycles since the beginning.
Main state machine.
void setupAndStart()
Run the state machine.
MainStateMachine()
Default constructor.
void ScreenUpdate()
Display information on screen.
bool isRunning()
Check if the state machine is enabled.
bool isMsmActive
Main state machine activation state.
int32_t read()
Read the current pressure for the feedback control.
Definition: pressure.cpp:29
void update()
This should be called by the main state machine every 1s.
#define DBG_DO(statement)
Expand arbitrary code only when in debug mode.
Definition: debug.h:24
void keyboardLoop()
Handle button events.
Definition: keyboard.cpp:223
MainController mainController
Step msmstep
HardwareTimer * msmTimer
uint32_t clockMsmTimer
uint32_t lastMicro
MainStateMachine mainStateMachine
uint32_t tick
Step previousmsmstep
uint32_t lastMillis
uint32_t lastMainControllerCall
@ END_CYCLE
@ TRIGGER_RAISED
@ INIT_CYCLE
void millisecondTimerMSM(HardwareTimer *)
int32_t MFM_read_airflow(void)
Read instant air flow.
int32_t MFM_expi_read_airflow(void)
Read instant air flow.
int32_t MFM_read_milliliters(bool reset_after_read)
Get the number of milliliters since last reset.
int32_t MFM_expi_read_milliliters(bool reset_after_read)
Get the number of milliliters since last reset for expiratory sensor.
#define MAIN_CONTROLLER_COMPUTE_PERIOD_MS
Definition: parameters.h:28
#define DEFAULT_PATIENT_HEIGHT
Definition: parameters.h:111
PressureSensor inspiratoryPressureSensor
Definition: pressure.cpp:23
RpiWatchdog rpiWatchdog
void displayMachineStopped()
Display a message when the machine is stopped.
Definition: screen.cpp:270
void displayCurrentSettings(uint16_t peakPressureMax, uint16_t plateauPressureMax, uint16_t peepMin)
Display the current settings.
Definition: screen.cpp:76
void clearAlarmDisplayCache()
Force clear the alarm display cache.
Definition: screen.cpp:144
void displayCurrentVolume(int32_t volumeMassFlow, uint16_t cyclesPerMinute)
Display the current injected air volume.
Definition: screen.cpp:53
void resetScreen()
Erase everything that is on the screen.
Definition: screen.cpp:50
void displayCurrentInformation(uint16_t peakPressure, uint16_t plateauPressure, uint16_t peep)
Display relevant values from the ongoing cycle.
Definition: screen.cpp:91
void serialControlLoop()
Parse input and handle changes of settings.