software:firmware
MakAir Firmware
mass_flow_meter.cpp
Go to the documentation of this file.
1 
11 // INCLUDES ===================================================================
12 
13 // Associated header
14 #include "../includes/mass_flow_meter.h"
15 
16 // External
17 #include <Arduino.h>
18 #include <HardwareSerial.h>
19 #include <IWatchdog.h>
20 #include <OneButton.h>
21 #include <Wire.h>
22 #include <math.h>
23 
24 // Internal
25 #include "../includes/buzzer_control.h"
26 #include "../includes/config.h"
27 #include "../includes/parameters.h"
28 #include "../includes/screen.h"
29 
30 // INITIALISATION =============================================================
31 
33 
34 // Hardware is ensured to be at least v2
35 #ifdef MASS_FLOW_METER_ENABLED
36 
37 // 2 kHz => prescaler = 50000 => still OK for a 16 bit timer. it cannnot be slower
38 // 10 kHz => nice
39 #define MASS_FLOW_TIMER_FREQ 10000
40 
41 // The timer period in 100 us multiple (because 10 kHz prescale)
42 #define MASS_FLOW_PERIOD 100
43 
45 
48 HardwareTimer* massFlowTimer = NULL;
49 
50 volatile bool mfmFaultCondition = false;
51 
52 // Calibration offset is substracted to MFM instant flow:
53 // - before volume integral
54 // - before sending MFM_read_airflow result
55 volatile int32_t mfmInspiratoryCalibrationOffset = 0;
57 volatile int32_t mfmInspiratorySensorDetected = 0;
58 volatile int32_t mfmInspiratoryInstantAirFlow = 0;
59 
60 volatile int32_t mfmExpiratoryCalibrationOffset = 0;
62 volatile int32_t mfmExpiratorySensorDetected = 0;
63 volatile int32_t mfmExpiratoryInstantAirFlow = 0;
64 
65 // Size of the table used to compute average
66 #define MFM_MEAN_SAMPLES 40
67 volatile bool mfmInspiratoryInstantAirFlowRecord = false;
69 // cppcheck-suppress misra-c2012-5.1
71 
73 volatile int32_t mfmInspiratoryLastValueFixedFloat = 0;
74 
75 volatile int32_t mfmExpiratoryLastValueFixedFloat = 0;
76 
77 // Time to reset the sensor after I2C restart, in periods => 100 ms
78 // the restart time is 50 ms (warm up time in the datasheet)
79 // the power off time is 50 ms. enough to discharge capacitors
80 #define MFM_WAIT_RESET_PERIODS 13
81 #define MFM_WAIT_WARMUP_PERIODS 8
82 #define MFM_WAIT_SOFTRESET_PERIODS 3
83 #define MFM_WAIT_READSERIALR1_PERIODS 1
84 
86 
88 
89 // cppcheck-suppress misra-c2012-19.2 ; union correctly used
90 union {
91  uint16_t i;
92  int16_t si;
93  unsigned char c[2];
94  // cppcheck-suppress misra-c2012-19.2 ; union correctly used
96 
97 // FUNCTIONS ==================================================================
98 
99 // API update since version 1.9.0 of Arduino_Core_STM32
100 #if (STM32_CORE_VERSION < 0x01090000)
101 // cppcheck-suppress misra-c2012-2.7 ; valid unused parameter
102 void MFM_Timer_Callback(HardwareTimer*) // NOLINT(readability/casting)
103 #else
104 void MFM_Timer_Callback(void)
105 #endif
106 {
107 #if MODE == MODE_MFM_TESTS
108  // cppcheck-suppress misra-c2012-12.3
109  digitalWrite(PIN_LED_START, HIGH);
110  // it takes typically 350 µs to read the value.
111 #endif
112  if (MFM_force_release_I2C != static_cast<uint16_t>(MFM_FORCE_RELEASE_I2C_TRUE)) {
113  if (!mfmFaultCondition) {
114 #if MASS_FLOW_METER_SENSOR == MFM_SFM3019
115  Wire.begin();
116  uint8_t readCountbis = Wire.requestFrom(MFM_SFM3019_I2C_ADDRESS, 3);
117  mfmLastData.c[1] = Wire.read();
118  mfmLastData.c[0] = Wire.read();
119  Wire.end();
120  // Hardware reset if not able to read two bytes.
121  if (readCountbis != 3u) {
122  mfmFaultCondition = true;
124  mfmInspiratoryAirVolumeSumMilliliters = 1000000000; // 1e9
125  }
126  mfmInspiratoryLastValueFixedFloat = (1000 * (mfmLastData.si + 24576)) / 170;
127 
128 #endif
129 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
130 
131  // begin() and end() everytime you read... the lib never free buffers if you don't do
132  // this.
133  Wire.begin();
134  uint8_t readCount = Wire.requestFrom(MFM_HONEYWELL_HAF_I2C_ADDRESS, 2);
135  mfmLastData.c[0] = Wire.read();
136  mfmLastData.c[1] = Wire.read();
137  // Wire.endTransmission() send a new write order followed by a stop. Useless and the
138  // sensor often nack it.
139  Wire.end();
140 
141  // Hardware reset if not able to read two bytes.
142  if (readCount != 2u) {
143  mfmFaultCondition = true;
145  mfmInspiratoryAirVolumeSumMilliliters = 1000000000; // 1e9
146  }
147 
148  mfmInspiratoryLastValue = (uint32_t)(mfmLastData.c[1] & 0xFFu);
149  mfmInspiratoryLastValue |= (((uint32_t)mfmLastData.c[0]) << 8) & 0x0000FF00u;
150 
151  // Theorical formula: Flow(slpm) = 200*((rawvalue/16384)-0.1)/0.8
152  // float implementation, 1 liter per minute unit
153  // mfmLastValueFloat =
154  // MFM_RANGE * (((uint32_t)mfmInspiratoryLastValue / 16384.0) - 0.1) / 0.8;
155  // (Output value in SLPM)
156 
157  // fixed float implementation, 1 milliliter per minute unit
159  (((10 * mfmInspiratoryLastValue) - 16384) * 1526) / 1000;
160 
161  // 100 value per second, 100 slpm during 10 minutes: sum will be 1.2e9. it fits in a
162  // int32 int32 max with milliliters = 2e6 liters.
163 
164 #endif
165 
166 #if MASS_FLOW_METER_SENSOR == MFM_SFM3019 || MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
167  // The sensor (100 SPLM version anyway) tends to output spurrious values located at
168  // around 500 SLM, which are obviously not correct. Let's filter them out based on the
169  // range of the sensor + 10%.
172  if (mfmInspiratoryLastValueFixedFloat > 500) { // less than 0.5 SPLM is noise
175  }
176  // also fill the last values table used to compute average, and update the index
184  // table full, stops
186  }
187  }
188  }
189 #endif
190 
191 #if MASS_FLOW_METER_SENSOR_EXPI == MFM_SFM_3300D
192  // begin() and end() everytime you read... the lib never free buffers if you don't do
193  // this.
194  Wire.begin();
195  // do not request crc, only two bytes
196  uint8_t readCountExpi = Wire.requestFrom(MFM_SFM_3300D_I2C_ADDRESS, 2);
197  mfmLastData.c[1] = Wire.read();
198  mfmLastData.c[0] = Wire.read();
199  Wire.end();
200 
201  // conversion in milliter per minute flow: ((int32_t)(mfmLastData.i) - 32768) * 1000 /
202  // 120 but 1000/120 = 8.333. So *8 and *1/3
204  (((int32_t)(mfmLastData.i) - 32768) * 8) + (((int32_t)(mfmLastData.i) - 32768) / 3);
205 
206  if (readCountExpi != 2u) {
208  // sfm 3300d needs 100ms after start of measurement before sending data.
209  // in case of bus failure, mfmFaultCondition is already true at this point
211  mfmFaultCondition = true;
213  mfmExpiratoryAirVolumeSumMilliliters = 1000000000; // 1e9
214  }
215  } else {
216  // valid data
219  || (mfmExpiratoryLastValueFixedFloat < -500)) { // less than 0.5 SPLM is noise
222  }
223  }
224 
225 #endif
226  } else {
228  // Reset attempt
229  // I2C sensors
230  Wire.flush();
231  Wire.end();
232 
233  // Set power off (available since hw3)
234  digitalWrite(MFM_POWER_CONTROL, MFM_POWER_OFF);
235  // also set SDA and SCL to 0 to avoid sensor to be powered by I2C bus.
236  pinMode(PIN_I2C_SDA, OUTPUT);
237  pinMode(PIN_I2C_SCL, OUTPUT);
238  digitalWrite(PIN_I2C_SCL, LOW);
239  __NOP();
240  digitalWrite(PIN_I2C_SDA, LOW);
241  }
242 
244 
245  // x period before end of reset cycle, power on again
247  // Set power on (available since hw v3)
248  digitalWrite(MFM_POWER_CONTROL, MFM_POWER_ON);
249  pinMode(PIN_I2C_SDA, INPUT);
250  pinMode(PIN_I2C_SCL, INPUT);
251  }
252 
253 #if MASS_FLOW_METER_SENSOR == MFM_SFM3019
255  // start air continuous measurement
256  Wire.begin();
257  Wire.beginTransmission(MFM_SFM3019_I2C_ADDRESS);
258  Wire.write(0x36);
259  Wire.write(0x08);
260  mfmFaultCondition = (0 != Wire.endTransmission()) || mfmFaultCondition;
261  Wire.end();
262  }
263 
264 #endif
265 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
267  Wire.begin();
268  Wire.beginTransmission(MFM_HONEYWELL_HAF_I2C_ADDRESS);
269  Wire.write(0x02); // Force reset
270  uint8_t status = Wire.endTransmission(); // actually send the data
271  Wire.end();
272  if (status != 0u) { // still a problem
274  }
275  }
277  Wire.begin();
278  // read first serial number register
279  uint8_t rxcount = Wire.requestFrom(MFM_HONEYWELL_HAF_I2C_ADDRESS, 2);
280  Wire.end();
281  if (rxcount != 2u) { // still a problem
283  }
284  }
285 #endif
286 
287  if (mfmResetStateMachine == 0) {
288  mfmFaultCondition = false;
289  // MFM_WAIT_RESET_PERIODS cycles later, try again to init the sensor
290 
291 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
292  Wire.begin();
293  // read second serial number register
294  uint8_t rxcount = Wire.requestFrom(MFM_HONEYWELL_HAF_I2C_ADDRESS, 2);
295  Wire.end();
296  mfmFaultCondition = (rxcount != 2u) || mfmFaultCondition;
297 #endif
298 
299 #if MASS_FLOW_METER_SENSOR_EXPI == MFM_SFM_3300D
300  Wire.begin();
301  Wire.beginTransmission(MFM_SFM_3300D_I2C_ADDRESS);
302  Wire.write(0x10);
303  Wire.write(0x00);
304  mfmFaultCondition = (0 != Wire.endTransmission()) || mfmFaultCondition;
306  Wire.end();
307 #endif
308 
309  if (mfmFaultCondition) {
311  }
312  }
313  }
314  }
315 #if MODE == MODE_MFM_TESTS
316  digitalWrite(PIN_LED_START, LOW);
317  digitalWrite(PIN_LED_GREEN, mfmFaultCondition ? HIGH : LOW);
318 #endif
319 }
320 
321 bool MFM_init(void) {
323  // cppcheck-suppress unreadVariable
324  uint32_t errorCount = 0;
325  // Set power on (hardware v3)
326  pinMode(MFM_POWER_CONTROL, OUTPUT);
327  digitalWrite(MFM_POWER_CONTROL, MFM_POWER_ON);
328  delay(100); // sfm3300 worst case boot time.
329 
330  // Set the timer
331  massFlowTimer = new HardwareTimer(MASS_FLOW_TIMER);
332 
333  // Prescaler; stm32f411 clock is 100 mHz
334  massFlowTimer->setPrescaleFactor((massFlowTimer->getTimerClkFreq() / MASS_FLOW_TIMER_FREQ) - 1);
335 
336  // Set the period
337  massFlowTimer->setOverflow(MASS_FLOW_PERIOD);
338  massFlowTimer->setMode(MASS_FLOW_CHANNEL, TIMER_OUTPUT_COMPARE, NC);
339  massFlowTimer->attachInterrupt(MFM_Timer_Callback);
340 
341  // Interrupt priority is documented here:
342  // https://stm32f4-discovery.net/2014/05/stm32f4-stm32f429-nvic-or-nested-vector-interrupt-controller/
343  // WARNING : since 1.9.0 lib, I2C is on level 2. must be under...
344  massFlowTimer->setInterruptPriority(3, 0);
345 
346  // default Wire instance is on PB8 BP9, anyway
347  Wire.setSDA(PIN_I2C_SDA);
348  Wire.setSCL(PIN_I2C_SCL);
349  // Wire.setClock(400000); // honeywell do support, but no information about sfm3300d
350 
351 #if MASS_FLOW_METER_SENSOR == MFM_SFM3019
352  Wire.begin();
353  Wire.beginTransmission(0x00);
354  Wire.write(0x06);
355  Wire.endTransmission();
356  Wire.end();
357  delay(4);
358 
359  // // start air continuous measurement
360  // Wire.begin();
361  // Wire.beginTransmission(MFM_SFM3019_I2C_ADDRESS);
362  // Wire.write(0x36);
363  // Wire.write(0x08);
364  // errorCount += Wire.endTransmission();
365  // Wire.end();
366 
367  // delay(2);
368  // //Stop continuous measurement 0x3FF9
369  // Wire.begin();
370  // Wire.beginTransmission(0x2E);
371  // Wire.write(0x3F);
372  // Wire.write(0xF9);
373  // Wire.endTransmission();
374  // Wire.end();
375 
376  // delay(2);
377  // //Read Scale Factor, Offset, and Flow Unit 0x3661
378  // Wire.begin();
379  // Wire.beginTransmission(0x2E);
380  // Wire.write(0x36);
381  // Wire.write(0x61);
382  // Wire.endTransmission();
383  // Wire.end();
384  // delay(2);
385  // Wire.begin();
386  // int ccc = Wire.requestFrom(0x2E, 8);
387  // Serial.print(ccc);
388  // Serial.print(" ");
389  // Serial.print(Wire.read()); Serial.print(",");
390  // Serial.print(Wire.read()); Serial.print(",");
391  // Serial.print(Wire.read()); Serial.print(",");
392  // Serial.print(Wire.read()); Serial.print(",");
393  // Serial.print(Wire.read()); Serial.print(",");
394  // Serial.print(Wire.read()); Serial.print(",");
395  // Serial.print(Wire.read()); Serial.print(",");
396  // Serial.print(Wire.read()); Serial.print(",");
397 
398  // Wire.end();
399 
400  delay(5);
401  // Read serial number
402  Wire.begin();
403  Wire.beginTransmission(MFM_SFM3019_I2C_ADDRESS);
404  Wire.write(0xE1);
405  Wire.write(0x02);
406  errorCount = Wire.endTransmission();
407 
408  delay(1);
409  errorCount += ((18u == Wire.requestFrom(MFM_SFM3019_I2C_ADDRESS, 18)) ? 0u : 1u);
410  if (errorCount == 0u) {
411  // the serial number is 64 bits wide, but it will never be used until year 2042.
412  // The serial number can be converted from binary into decimal,
413  // whereby in decimal it has the following format::
414  // yywwxxxxxx, where: yy: last to digits of calibration year, ww:
415  // calibration week, xxxxxx: unique 6-digit sequential number
416  // within the calibration week.
417  uint32_t sn_inspi = 0;
418  Wire.read();
419  Wire.read(); // product number part 1
420  Wire.read(); // crc
421  Wire.read();
422  Wire.read(); // product number part 2
423  Wire.read(); // crc
424 
425  Wire.read();
426  Wire.read(); // ignore this part of serial
427  Wire.read(); // ignore inlined crc
428  Wire.read();
429  Wire.read(); // ignore this part of serial
430  Wire.read(); // ignore inlined crc
431  sn_inspi |= Wire.read();
432  sn_inspi <<= 8;
433  sn_inspi |= Wire.read();
434  sn_inspi <<= 8;
435  Wire.read(); // ignore inlined crc
436  sn_inspi |= Wire.read();
437  sn_inspi <<= 8;
438  sn_inspi |= Wire.read();
439  Wire.read(); // ignore inlined crc
440  mfmSfm3019SerialNumber = sn_inspi;
441  }
442  delay(1);
443 
444  // start air continuous measurement
445  Wire.begin();
446  Wire.beginTransmission(MFM_SFM3019_I2C_ADDRESS);
447  Wire.write(0x36);
448  Wire.write(0x08);
449  errorCount += Wire.endTransmission();
450  Wire.end();
451 
452  delay(40); // the first measurement result will be available after 12ms
453  // small accuracy deviations (few % of reading) can occur during the first 30ms
454 
455  // delay(10000);
456  if (errorCount != 0u) {
457  mfmFaultCondition = true;
459  }
460 #endif
461 
462 #if MASS_FLOW_METER_SENSOR_EXPI == MFM_SFM_3300D
463  Wire.begin(); // Join I2C bus (address is optional for master)
464  Wire.beginTransmission(MFM_SFM_3300D_I2C_ADDRESS);
465  Wire.write(0x20); // 0x2000 soft reset
466  Wire.write(0x00);
467  errorCount = Wire.endTransmission();
468  delay(5); // end of reset
469 
470  Wire.beginTransmission(MFM_SFM_3300D_I2C_ADDRESS);
471  Wire.write(0x31); // 0x31AE read serial
472  Wire.write(0xAE);
473  errorCount += Wire.endTransmission();
474 
475  errorCount += ((6u == Wire.requestFrom(MFM_SFM_3300D_I2C_ADDRESS, 6)) ? 0u : 1u);
476  if (errorCount == 0u) {
477  u_int32_t sn_expi = 0;
478  sn_expi = Wire.read();
479  sn_expi <<= 8;
480  sn_expi |= Wire.read();
481  sn_expi <<= 8;
482  Wire.read(); // ignore inlined crc
483  sn_expi |= Wire.read();
484  sn_expi <<= 8;
485  sn_expi |= Wire.read();
486  Wire.read(); // ignore inlined crc
487  mfmSfm3300SerialNumberExpi = sn_expi;
488  }
489  delay(10);
490  Wire.beginTransmission(MFM_SFM_3300D_I2C_ADDRESS);
491  Wire.write(0x10); // 0x1000 start measurement
492  Wire.write(0x00);
493  errorCount += Wire.endTransmission();
494  Wire.end();
495  delay(100); // wait 100ms before having available data.
496 
497  if (errorCount != 0u) {
498  mfmFaultCondition = true;
500  }
501 #endif
502 
503 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
504 
505  /*
506  Init sequence for Honeywell Zephyr mass flow sensor:
507  1st read operation: the sensor will send 0x0000
508  2nd read operation: the sensor will send the first part of the serial number
509  3rd read operation: the sensor will send the second part of the serial number
510  Subsequent read operations: the sensor will send calibrated mass air flow values with two
511  leading 0
512  */
513  Wire.begin();
514  Wire.beginTransmission(MFM_HONEYWELL_HAF_I2C_ADDRESS);
515  Wire.write(0x02); // Force reset
516  uint8_t txOk = Wire.endTransmission();
517  Wire.end();
518  delay(30);
519 
520  u_int32_t sn = 0;
521  Wire.begin();
522  Wire.beginTransmission(MFM_HONEYWELL_HAF_I2C_ADDRESS);
523  uint8_t rxcount = Wire.requestFrom(MFM_HONEYWELL_HAF_I2C_ADDRESS, 2);
524  sn = Wire.read();
525  sn <<= 8;
526  sn |= Wire.read(); // first transmission is serial number register 0
527  sn <<= 8;
528  delay(2); // if you do not wait, sensor will send again register 0
529  rxcount += Wire.requestFrom(MFM_HONEYWELL_HAF_I2C_ADDRESS, 2);
530  sn |= Wire.read();
531  sn <<= 8;
532  sn |= Wire.read(); // second transmission is serial number register 1
533 
534  if ((txOk != 0u) || (rxcount != 4u)) { // If transmission failed
535  mfmFaultCondition = true;
537  } else {
539  }
540  Wire.end();
541 
542 #if MODE == MODE_MFM_TESTS
543  Serial.println("Read 1");
544  Serial.println(mfmLastData.i);
545  Serial.println("fault condition:");
546  Serial.println(mfmFaultCondition ? "failure" : "no failure");
547 #endif
548  delay(100);
549 #endif
550 
551  massFlowTimer->resume();
552  return !mfmFaultCondition;
553 }
554 
555 int32_t MFM_read_airflow(void) {
556  int32_t r;
557  if (mfmFaultCondition) {
559  } else {
561  }
562  return r;
563 }
564 
565 // cppcheck-suppress unusedFunction
566 int32_t MFM_expi_read_airflow(void) {
567  int32_t r;
568  if (mfmFaultCondition) {
570  } else {
572  }
573  return r;
574 }
575 
577 
579 
580 // cppcheck-suppress unusedFunction
581 uint32_t MFM_read_serial_number(void) {
582 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
584 #elif MASS_FLOW_METER_SENSOR == MFM_SFM3019
585  return mfmSfm3019SerialNumber;
586 #endif
587  return 0;
588 }
589 
590 #if MASS_FLOW_METER_SENSOR_EXPI == MFM_SFM_3300D
596 // cppcheck-suppress unusedFunction
598 
599 #endif
600 
604 int8_t MFM_calibrateZero(void) {
605  int8_t ret = MFM_CALIBRATION_OK;
606  // activate table fill with last valid value
609  // wait for the table to fill in
610  delay(2 + (MFM_MEAN_SAMPLES * (MASS_FLOW_PERIOD / 10)));
611  // Check that table is full (record must be false)
612  // If it is not, there is a sensor problem
613  // In case of problem, do not update mfmInspiratoryCalibrationOffset
615  int32_t zeroFlow = 0;
616  for (int16_t i = 0; i < MFM_MEAN_SAMPLES; i++) {
618  }
619  zeroFlow /= MFM_MEAN_SAMPLES;
620  // check that value is credible: [-10 10] SLPM
621  if ((zeroFlow < 10000) && (zeroFlow > -10000)) {
623  } else {
625  }
626  } else {
628  }
629  return ret;
630 }
631 
636 
637 int32_t MFM_read_milliliters(bool reset_after_read) {
638  int32_t result = MASS_FLOW_ERROR_VALUE;
639 
640 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF || MASS_FLOW_METER_SENSOR == MFM_SFM3019
641  // period is MASS_FLOW_PERIOD / 10000 (100 µs prescaler)
642  result = mfmFaultCondition
645 #endif
646 
647  if (reset_after_read) {
648  MFM_reset();
649  }
650 
651  return result;
652 }
653 // cppcheck-suppress unusedFunction
654 int32_t MFM_expi_read_milliliters(bool reset_after_read) {
655  int32_t result = MASS_FLOW_ERROR_VALUE;
656 
657 #if MASS_FLOW_METER_SENSOR_EXPI == MFM_SFM_3300D
658  result = mfmFaultCondition
661 #endif
662  if (reset_after_read) {
663  MFM_expi_reset();
664  }
665 
666  return result;
667 }
668 
669 #if MODE == MODE_MFM_TESTS
670 
671 void onStartClick() {
672  MFM_reset();
673  MFM_expi_reset();
674 }
675 void onPauseClick() { MFM_calibrateZero(); }
676 char buffer[30];
677 
678 OneButton btn_alarmoff(PIN_BTN_ALARM_OFF, false, false);
679 OneButton btn_pause(PIN_BTN_STOP, false, false);
680 
681 void setup(void) {
682  Serial.begin(115200);
683  Serial.println("init mass flow meter");
684  pinMode(PIN_LED_START, OUTPUT);
685  pinMode(PIN_LED_GREEN, OUTPUT);
686 
687  boolean ok = MFM_init();
688  int calib = MFM_calibrateZero();
689 
690  startScreen();
691  resetScreen();
692  screen.setCursor(0, 0);
693  screen.print("debug prog");
694  screen.setCursor(0, 1);
695  screen.print("mass flow sensor");
696  screen.setCursor(0, 2);
697  screen.print(ok ? "sensor OK" : "sensor not OK");
698  screen.setCursor(0, 3);
699  screen.print(calib == MFM_CALIBRATION_OK ? "calib OK" : "calibration error");
700 
701 #if MASS_FLOW_METER_SENSOR == MFM_HONEYWELL_HAF
702  (void)snprintf(buffer, sizeof(buffer), "serial=%08x ", MFM_read_serial_number());
703 #elif MASS_FLOW_METER_SENSOR == MFM_SFM3019
704  (void)snprintf(buffer, sizeof(buffer), "serial=%d ", MFM_read_serial_number());
705 #endif
706  Serial.println(buffer);
707 
708 #ifdef MASS_FLOW_METER_SENSOR_EXPI
709  (void)snprintf(buffer, sizeof(buffer), "serial expi=%08d ", MFM_expi_read_serial_number());
710  Serial.println(buffer);
711 #endif
712 
713  Serial.print("calibration status=");
714  Serial.println(calib);
715  Serial.print("offset calibration=");
716  Serial.println(mfmInspiratoryCalibrationOffset);
717 
718  btn_alarmoff.attachClick(onStartClick);
719  btn_alarmoff.setDebounceTicks(0);
720  btn_pause.attachClick(onPauseClick);
721  btn_pause.setDebounceTicks(0);
723  Serial.println("init done");
724 }
725 
726 int loopcounter = 0;
727 
728 void loop(void) {
729  delay(10);
730  loopcounter++;
731  if (loopcounter == 50) {
732  loopcounter = 0;
733 
734  int32_t volume = MFM_read_milliliters(false);
735  int32_t volumeExpi = MFM_expi_read_milliliters(false);
736 
737  resetScreen();
738  screen.setCursor(0, 0);
739  screen.print("mass flow sensor");
740  screen.setCursor(0, 1);
741 
742  if (volume == MASS_FLOW_ERROR_VALUE) {
743  screen.print("sensor not OK");
744  } else {
745  screen.print("sensor OK");
746  }
747  // screen.print(mfmInspiratoryLastValue);
748  screen.setCursor(0, 2);
749  (void)snprintf(buffer, sizeof(buffer), "->vol=%dmL %dmLpm ", volume, MFM_read_airflow());
750  screen.print(buffer);
751 
752  screen.setCursor(0, 3);
753  (void)snprintf(buffer, sizeof(buffer), "<-vol=%dmL %dmLpm ", volumeExpi,
755  screen.print(buffer);
756 
757  // Serial.print(mfmLastValueFloat*1000);
758  // Serial.print(",");
759 
760  // Serial.print("volume = ");
761  // Serial.print(volume);
762  // Serial.println("mL");
763  }
764  Serial.print(MFM_read_airflow());
765  Serial.print(",");
766  Serial.println(MFM_expi_read_airflow());
767 
768  btn_alarmoff.tick();
769  btn_pause.tick();
770 }
771 #endif
772 
773 #endif
#define MFM_RANGE
Defines the range of the Mass Flow Meter in SLM (standard liter per minute)
Definition: config.h:48
void MFM_reset(void)
Reset the volume counter.
volatile int32_t mfmExpiratorySensorDetected
uint32_t mfmSfm3019SerialNumber
int32_t MFM_getOffset(void)
Get massflow meter offset.
volatile int32_t mfmInspiratoryAirVolumeSumMilliliters
volatile int32_t mfmInspiratoryInstantAirFlow
union @0 mfmLastData
int32_t mfmInspiratoryLastValue
volatile int32_t mfmExpiratoryAirVolumeSumMilliliters
#define MFM_WAIT_SOFTRESET_PERIODS
volatile int32_t mfmInspiratoryInstantAirFlowLastValues[MFM_MEAN_SAMPLES]
volatile int32_t mfmInspiratoryCalibrationOffset
unsigned char c[2]
volatile int32_t mfmExpiratoryInstantAirFlow
HardwareTimer * massFlowTimer
volatile int32_t mfmExpiratoryCalibrationOffset
uint32_t MFM_expi_read_serial_number(void)
return the serial number of the expiratory flow meter
volatile int32_t mfmInspiratoryLastValueFixedFloat
uint16_t i
volatile int32_t mfmExpiratoryLastValueFixedFloat
int8_t MFM_calibrateZero(void)
If the massflow meter needs to be calibrated, this function will be usefull.
#define MASS_FLOW_PERIOD
int32_t MFM_read_airflow(void)
Read instant air flow.
int32_t mfmResetStateMachine
uint32_t MFM_read_serial_number(void)
Get the serial number of the inspiratory flow meter.
#define MASS_FLOW_TIMER_FREQ
volatile int16_t mfmInspiratoryInstantAirFlowLastValuesIndex
int16_t si
int32_t MFM_expi_read_airflow(void)
Read instant air flow.
volatile uint16_t MFM_force_release_I2C
void MFM_expi_reset(void)
int32_t MFM_read_milliliters(bool reset_after_read)
Get the number of milliliters since last reset.
volatile bool mfmFaultCondition
void MFM_Timer_Callback(HardwareTimer *)
#define MFM_WAIT_RESET_PERIODS
int32_t MFM_expi_read_milliliters(bool reset_after_read)
Get the number of milliliters since last reset for expiratory sensor.
volatile int32_t mfmInspiratorySensorDetected
#define MFM_WAIT_WARMUP_PERIODS
uint32_t mfmSfm3300SerialNumberExpi
#define MFM_MEAN_SAMPLES
uint16_t mfmExpiSFM3300FailCounter
volatile bool mfmInspiratoryInstantAirFlowRecord
uint32_t mfmHoneywellHafSerialNumber
#define MFM_WAIT_READSERIALR1_PERIODS
bool MFM_init(void)
Initialize Mass Flow Meter.
#define MFM_CALIBRATION_IMPOSSIBLE
#define MFM_SFM_3300D_I2C_ADDRESS
#define MFM_SFM3019_I2C_ADDRESS
#define MFM_CALIBRATION_OUT_OF_RANGE
#define MFM_CALIBRATION_OK
#define MFM_HONEYWELL_HAF_I2C_ADDRESS
#define MFM_FORCE_RELEASE_I2C_TRUE
#define MFM_FORCE_RELEASE_I2C_FALSE
#define PIN_LED_GREEN
Definition: parameters.h:253
#define PIN_LED_START
Definition: parameters.h:252
#define MASS_FLOW_CHANNEL
Definition: parameters.h:294
#define MASS_FLOW_TIMER
Definition: parameters.h:293
#define PIN_I2C_SCL
Definition: parameters.h:296
#define MFM_POWER_ON
Definition: parameters.h:300
#define MFM_POWER_CONTROL
Definition: parameters.h:298
#define MASS_FLOW_ERROR_VALUE
Definition: parameters.h:302
#define PIN_BTN_STOP
Definition: parameters.h:233
#define PIN_BTN_ALARM_OFF
Definition: parameters.h:231
#define MFM_POWER_OFF
Definition: parameters.h:299
#define PIN_I2C_SDA
Definition: parameters.h:295
void loop(void)
Definition: respirator.cpp:161
void setup(void)
Definition: respirator.cpp:49
void resetScreen()
Erase everything that is on the screen.
Definition: screen.cpp:50
void startScreen()
Start the screen.
Definition: screen.cpp:42
LiquidCrystal screen
Instance of the screen controller.