Flying Silicon Sensor
fsSensor.cpp
Go to the documentation of this file.
1
24// -----------------------------------------------------------------------------
25// Library headers
26// -----------------------------------------------------------------------------
27
28#include <Arduino.h> // Added by Arduino in build process
29
30#include <Wire.h> // For I2C comms
31#include <sdpsensor.h> // Sensirion SDP3x library
32#include <SensirionI2CSht4x.h> // Sensirion SHT4x library
33#include <Adafruit_DPS310.h> // Adafruit DPS310 library
34
35// Local modules
36#include "pindefs.h"
37#include "sounds.h"
38#include "debug.h"
39#include "ptvBleInterface.h"
40#include "deepSleep.h"
41#include "pwrSupply.h"
42
43// -----------------------------------------------------------------------------
44// Settings
45// -----------------------------------------------------------------------------
46
48#define DEVICE_MANUFACTURER "Flying Silicon"
50#define DEVICE_NAME "FS-SP4"
52#define DEVICE_SERIAL "23-001"
53
55#define ACTIVE_WITH_USB 0
56
58#define FLASH_ALWAYS 1
59
61#define SEND_LONG 0
62
64#define DEEP_SLEEP 1
65
66// -----------------------------------------------------------------------------
67
68// Caution: buggy/immediate deep sleep can prevent flashing via serial!
70#define AUTO_OFF_MS 3600000
71
73#define META_REPEAT 16
74
76#define PATCH_LEDR digitalWrite(LEDR, HIGH)
77
78// -----------------------------------------------------------------------------
79// Constants
80// -----------------------------------------------------------------------------
81
83#define IntervalMSG 125
85#define IntervalSDP IntervalMSG
87#define IntervalDPS IntervalMSG
89#define IntervalSHT 1000
91#define IntervalPWR 1000
93#define IntervalPOL IntervalMSG
94
96#define LoopPassiveMs 125
98#define LoopIdleMs 125
100#define NopDelayMs 10
101
103#define IdleIntervalLED 1250
105#define IdleLightLED 625
106
108#define IntervalLED 2500
110#define LightLED 125
111
112
114static const int Melody[] = {
115 NOTE_C3, 16,
116 NOTE_G3, 16,
117 NOTE_E3, 16,
118 NOTE_C3, 32,
119 NOTE_G3, -16,
120 NOTE_E3, 8,
122};
123
124
125// -----------------------------------------------------------------------------
126// Global singleton objects
127// -----------------------------------------------------------------------------
128
131
133static SDP3XSensor sdp;
134
136static SensirionI2CSht4x sht;
137
139static Adafruit_DPS310 dps;
140
143
144
145// -----------------------------------------------------------------------------
146// Global status variables
147// -----------------------------------------------------------------------------
148
150static int isBlueLedOn = 0;
152static int isEnabled = 0;
154static int isConnected = 0;
155
157static unsigned int sentMeta = 0;
158
160static unsigned long timeMs = 0;
161
163static unsigned long lastActiveMs;
164
165static unsigned long lastSHTMs;
166static unsigned long lastSDPMs;
167static unsigned long lastDPSMs;
168static unsigned long lastMSGMs;
169static unsigned long lastPOLMs;
170static unsigned long lastLEDMs;
171static unsigned long lastPWRMs;
172
173
177static void resetStatus(void) {
178
179 sensorData.diffPa = 0.0;
180 sensorData.absHpa = 1013.25;
181
182 sensorData.batVolt = 0.0;
183 sensorData.batPct = 0.0;
184
185 sensorData.tempC = 0.0;
186 sensorData.humPct = 0.0;
187
188 isBlueLedOn = 0;
189 isConnected = 0;
190 isEnabled = 0;
191
192 sentMeta = 0;
193
195}
196
200static void resetTimers(void) {
201
202 timeMs = millis();
203
204 // initialise auto off timer
206
207 // let all functions execute at next loop
214
215 lastLEDMs = timeMs; // for clean start of flashing
216}
217
221static void clearLEDs(void) {
222
223 pinMode(LEDB, OUTPUT); // paranoia
224 digitalWrite(LEDB, HIGH);
225
226 pinMode(LEDG, OUTPUT); // paranoia
227 digitalWrite(LEDG, HIGH);
228
229 pinMode(LEDR, OUTPUT); // paranoia
230 digitalWrite(LEDR, HIGH);
231}
232
236static void readSDP(void) {
237
238 const int ret = sdp.readSample();
239 if (ret) {
240 LOGL("No data from SDP")
241 return;
242 }
243
244 // correction of presssure differential wrt altitude/QNH
245 sensorData.diffPa = sdp.getDifferentialPressure() * (966.00 / sensorData.absHpa);
246
247 // NOTE: forward also negative values so that data processing
248 // by filter around zero can work
249 LOG("SDP ")
251 LOGL(" Pa")
252}
253
257static void readDPS(void) {
258
259 // always read pressure and temperature
260 // pressure needs temperature for compensation formula
261 if (!dps.temperatureAvailable())
262 return; // wait until there's something to read
263 if (!dps.pressureAvailable())
264 return; // wait until there's something to read
265
266 sensors_event_t temp_event, pressure_event;
267 dps.getEvents(&temp_event, &pressure_event);
268
269 sensorData.absHpa = pressure_event.pressure;
270
271 LOG("DPS ")
273 LOGL(" hPa")
274}
275
279static void readSHT(void) {
280
281 float t, h;
282 sht.measureHighPrecision(t, h);
283 sensorData.tempC = t;
284 sensorData.humPct = h;
285
286 LOG("SHT ")
288 LOG(" C ")
290 LOGL(" RH")
291}
292
293
300static void flashBlueLED(int active, unsigned int intervalMs, unsigned int lightMs) {
301
302 if (!isBlueLedOn) {
303 // wait for the interval to expire before turning it on
304 if (timeMs - lastLEDMs >= intervalMs) {
305 lastLEDMs += intervalMs;
306
307 if (active) {
308 digitalWrite(LEDB, LOW); // switch on
309 isBlueLedOn = 1;
310 }
311 }
312 }
313 else {
314 // wait for the duration to expire before turning LED off
315 if (timeMs - lastLEDMs >= lightMs) {
316 lastLEDMs += lightMs;
317
318 digitalWrite(LEDB, HIGH); // switch off
319 isBlueLedOn = 0;
320 }
321 }
322}
323
327static void managePower() {
328
330
331 // data needed to send
335
336 // disable buzzer if running with USB only
339 else
341}
342
347static void processCmd(const String &cmd) {
348 // nothing so far
349 LOGL(cmd)
350}
351
355static void enable(void) {
356
357 isEnabled = 1;
358
359 // clear receive buffer
361 // start advertising again
363
364 // Play melody
366 delay(500);
367
368 // Play battery / power status
371 else
373 delay(500);
374
375 resetTimers();
376 LOGL("Switched on")
377}
378
382static void disable(void) {
383
384 isEnabled = 0;
387 LOGL("Disabled")
388}
389
395static void suspend(void) {
396
397 LOGL("Switched off")
398 clearLEDs();
399
400 // try a clean BLE disconnect
402 delay(1000);
403
404 // test if pin state is kept in sleep mode (important)
405 // digitalWrite(LEDR, LOW);
406
407#if DEEP_SLEEP
409 // should never return
410#else
412 // suspend the RTOS loop task
413 // immediately effective, does not return
414 suspendLoop();
415#endif
416 // MUST NOT BE REACHED
418}
419
423static void loopIdle(void) {
424
425 // Blink slowly (also when running on battery)
427
429 delay(LoopIdleMs);
430}
431
435static void loopConnected(void) {
436
437 if (timeMs >= lastDPSMs + IntervalDPS) {
439 readDPS();
440 }
441
442 if (timeMs >= lastSHTMs + IntervalSHT) {
444 readSHT();
445 }
446
447 if (timeMs >= lastSDPMs + IntervalSDP) {
449 readSDP();
450 }
451
452 if (timeMs >= lastMSGMs + IntervalMSG) {
454
455 if (sentMeta < META_REPEAT) {
457 sentMeta ++;
458 }
459 else if (SEND_LONG) {
461 }
462 else {
464 }
465
467 }
468 else {
469 // if no message sent, sleep some ms
470 delay(NopDelayMs);
471 }
472
473 if (timeMs >= lastPOLMs + IntervalPOL) {
475 String cmd;
476 if (Remote.getReceived(cmd)) {
477 processCmd(cmd);
478 }
479 }
480
481 // Short flashes when BLE connection established
483}
484
488static void loopPassive(void) {
489
491 // constant LED on when inactive and charging
492 digitalWrite(LEDB, sensorData.isCharging ? LOW : HIGH);
493
494 delay(LoopPassiveMs);
495}
496
497
501void appLoop(void) {
502
503 timeMs = millis();
504
505 if (timeMs >= lastPWRMs + IntervalPWR) {
507 managePower();
508 }
509
511 // silent power off
512 suspend();
513 return;
514 }
515
517 // power off with sound
519 suspend();
520 return;
521 }
522
524
525 // battery connected or run with USB set
526 if (! isEnabled)
527 enable();
528
529 if (! Remote.isConnected()) {
530 // idle, no sensor data needed
531
532 // play disconnect sound when connected before
533 if (isConnected > 0) {
534 LOGL("Disconnected")
536 }
537 isConnected = 0;
538 sentMeta = 0;
539
540 // prevent auto off if running on USB
541 // if (! isBattPowered())
542 // lastActiveMs = timeMs;
543 loopIdle();
544 }
545 else {
546 // full ooperation
547 // NOTE: we get also a temporary connection when the device
548 // is being paired, without any data transmission
549
550 if (! isConnected) {
551 LOGL("Connected")
553 }
554 isConnected = 1;
555
556 // prevent auto off
559 }
560 }
561 else {
562 // stop sensor processing when battery switch is off
563 // never trigger auto off
564 if (isEnabled)
565 disable();
566
567 // prevent auto off
569 // device inactive except for charging
570 loopPassive();
571 }
572}
573
577static void configure(void) {
578
579 clearLEDs();
580
581 // Battery Monitoring
582 pinMode(PIN_BATTV_ENABLE, OUTPUT);
583 digitalWrite(PIN_BATTV_ENABLE, LOW);
584 pinMode(PIN_BATTV, INPUT);
585 analogReference(ANALOG_REFV); // 2.4 V reference
586 analogReadResolution(12);
587
588 // USB / Charging Monitoring
589 // USB Voltage divided, Low <= 0.99V, High >= 2.31V
590 pinMode(PIN_USB, INPUT);
591
592 // Charging Rate
593 // Slow = HIGH = Charge current 50mA
594 // Fast = LOW = Charge current 100mA
595 // always slow at beginning
596 pinMode(PIN_HICHG, OUTPUT);
597 digitalWrite(PIN_HICHG, HIGH);
598
599 // Charging status
600 pinMode(PIN_CHG, INPUT);
601
602 // Setup Buzzer LOW = no current
603 pinMode(PIN_BUZZER, OUTPUT);
604 digitalWrite(PIN_BUZZER, LOW);
605}
606
610void appSetup(void) {
611
612 configure();
613
614 // Initialise Serial Monitor
615 if (DEBUG) {
616 Serial.begin(115200);
617 while (! Serial) {
618 delay(500);
619 }
620 }
621
622 // Start I2C
623 Wire.begin();
624
625 // Initialise Sensirion SDP
626 while (sdp.init() != 0) {
627 LOGL("Wait for SDP")
628 delay(500);
629 }
630
631 // Initialise Sensirion SHT
632 sht.begin(Wire);
633
634 // Initialise Infineon DPS sensor
635 while (!dps.begin_I2C()) {
636 LOGL("Wait for DPS")
637 delay(500);
638 }
639
640 // Take 64 samples/sec and use average of last 8 samples
641 // Temperature compensation is more accurate when measurements
642 // are taken together
643 dps.configurePressure(DPS310_64HZ, DPS310_8SAMPLES);
644 dps.configureTemperature(DPS310_64HZ, DPS310_8SAMPLES);
645
646 // initialise status and start timers
647 resetStatus();
648 resetTimers();
649
650 // Get initial battery and USB power state
651 managePower();
652
654 suspend();
655 return;
656 }
657
658 // Prepare BLE service
660
661 // Set initial on/off status
663 enable();
664 else
665 disable();
666}
void init(const char *deviceName)
int isConnected(void)
void startAdv(void)
void shutdown(void)
void sendMetaMsg(const String &mna, const String &mmo, const String &msn)
void sendShortMsg(const SensorData &data)
void sendLongMsg(const SensorData &data)
int getReceived(String &cmd)
void clrReceived()
Clear anything received so far.
Debug log macros.
#define LOG(s)
Debug log inactive.
Definition debug.h:37
#define DEBUG
Enable/disable debugging.
Definition debug.h:27
#define LOGL(s)
Debug log inactive.
Definition debug.h:39
Support for nrf52 deep sleep / low power modes.
void enterDeepSleep(void)
int setLowPowerMode(void)
#define AUTO_OFF_MS
Delay before auto power off (without BLE connection)
Definition fsSensor.cpp:70
static void loopConnected(void)
Definition fsSensor.cpp:435
#define LoopPassiveMs
Loop interval ms when disabled.
Definition fsSensor.cpp:96
static void suspend(void)
Definition fsSensor.cpp:395
static void flashBlueLED(int active, unsigned int intervalMs, unsigned int lightMs)
Definition fsSensor.cpp:300
#define ACTIVE_WITH_USB
Run or stay passive (and charge) when USB is connected.
Definition fsSensor.cpp:55
#define IntervalSDP
SDP read interval ms.
Definition fsSensor.cpp:85
static void disable(void)
Definition fsSensor.cpp:382
static unsigned long lastSHTMs
Last read SHT ambient temperature/humidity.
Definition fsSensor.cpp:165
static Adafruit_DPS310 dps
Infineon DPS310 for barometric pressure.
Definition fsSensor.cpp:139
static void configure(void)
Definition fsSensor.cpp:577
static void readSHT(void)
Definition fsSensor.cpp:279
static void readSDP(void)
Definition fsSensor.cpp:236
#define IntervalPOL
Time ms before BLE receive repeats.
Definition fsSensor.cpp:93
#define IntervalSHT
SHT read interval ms.
Definition fsSensor.cpp:89
#define IntervalMSG
Message send interval ms (critical)
Definition fsSensor.cpp:83
void appLoop(void)
Definition fsSensor.cpp:501
static SensirionI2CSht4x sht
Sensirion SHT for temperature / humidity.
Definition fsSensor.cpp:136
static PtvBleInterface::SensorData sensorData
Sensor data to work with.
Definition fsSensor.cpp:142
static unsigned long lastMSGMs
Last time message sent.
Definition fsSensor.cpp:168
static PtvBleInterface Remote
Singleton connection to be used (all BLE stuff is singleton)
Definition fsSensor.cpp:130
#define FLASH_ALWAYS
Flash blue LED (when BLE connected) also when running on battery.
Definition fsSensor.cpp:58
static int isEnabled
Operating mode 0/1.
Definition fsSensor.cpp:152
#define DEVICE_NAME
Device name meta data (also sent in BLE advertising, truncated to 31)
Definition fsSensor.cpp:50
#define DEVICE_SERIAL
Serial number meta data.
Definition fsSensor.cpp:52
static void readDPS(void)
Definition fsSensor.cpp:257
#define IdleLightLED
Time LED is on.
Definition fsSensor.cpp:105
static void processCmd(const String &cmd)
Definition fsSensor.cpp:347
#define PATCH_LEDR
Patch the red LED which is going on when BLE device is bonded.
Definition fsSensor.cpp:76
static unsigned long lastActiveMs
Definition fsSensor.cpp:163
static unsigned long lastLEDMs
Last LED state change.
Definition fsSensor.cpp:170
#define LoopIdleMs
Loop interval when not connected.
Definition fsSensor.cpp:98
#define LightLED
Time LED is on.
Definition fsSensor.cpp:110
#define NopDelayMs
Delay ms when no message needs to be sent.
Definition fsSensor.cpp:100
#define IntervalDPS
DPS read interval ms.
Definition fsSensor.cpp:87
static void loopIdle(void)
Definition fsSensor.cpp:423
static int isConnected
Connection state 0/1.
Definition fsSensor.cpp:154
static void resetStatus(void)
Definition fsSensor.cpp:177
static void resetTimers(void)
Definition fsSensor.cpp:200
#define SEND_LONG
Use the long PTVSOAR message format also for data.
Definition fsSensor.cpp:61
#define IdleIntervalLED
LED flashing interval when BLE is active but disconnected.
Definition fsSensor.cpp:103
#define DEVICE_MANUFACTURER
Manufacturer meta data.
Definition fsSensor.cpp:48
static unsigned long timeMs
Current loop time ms.
Definition fsSensor.cpp:160
#define IntervalLED
LED flashing interval when BLE is active and connected.
Definition fsSensor.cpp:108
static void clearLEDs(void)
Definition fsSensor.cpp:221
static unsigned int sentMeta
Meta data repetition counter.
Definition fsSensor.cpp:157
static unsigned long lastPWRMs
Last read of battery/voltage status.
Definition fsSensor.cpp:171
static unsigned long lastDPSMs
Last read DPS atmospheric pressure.
Definition fsSensor.cpp:167
void appSetup(void)
Definition fsSensor.cpp:610
static void loopPassive(void)
Definition fsSensor.cpp:488
#define IntervalPWR
Power state update interval ms.
Definition fsSensor.cpp:91
static int isBlueLedOn
LED blinking state 0/1.
Definition fsSensor.cpp:150
static void managePower()
Definition fsSensor.cpp:327
static SDP3XSensor sdp
Sensirion SDP31 for Pitot.
Definition fsSensor.cpp:133
static void enable(void)
Definition fsSensor.cpp:355
static unsigned long lastPOLMs
Last BLE receive poll.
Definition fsSensor.cpp:169
static unsigned long lastSDPMs
Last read SDP differential pressure.
Definition fsSensor.cpp:166
static const int Melody[]
Startup melody.
Definition fsSensor.cpp:114
#define META_REPEAT
Number of meta headers to send on (re)connect.
Definition fsSensor.cpp:73
float getBatPct(void)
Definition pwrSupply.cpp:69
int isCharging(void)
Definition pwrSupply.cpp:62
int isBatPowered(void)
void updateState(void)
int isUsbConnected(void)
Definition pwrSupply.cpp:85
void reset(void)
float getBatVolt(void)
Definition pwrSupply.cpp:77
int isBatDrained(void)
void playConnect(void)
Definition sounds.cpp:197
void playDisconnect(void)
Definition sounds.cpp:207
void playSwitchOff(void)
Definition sounds.cpp:219
void playMelody(const int melody[])
Definition sounds.cpp:105
void playCharging(void)
Definition sounds.cpp:135
void playBattery(float batPct)
Definition sounds.cpp:146
void setBuzzer(int pin)
Definition sounds.cpp:44
Pin definitions for Seeed XIAO nRF52840 2.9.2 with Adafruit bluefruit library.
#define PIN_HICHG
Definition pindefs.h:31
#define PIN_BUZZER
Definition pindefs.h:27
#define ANALOG_REFV
Definition pindefs.h:39
#define PIN_USB
Definition pindefs.h:29
#define PIN_CHG
Definition pindefs.h:37
#define LEDG
Definition pindefs.h:43
#define PIN_BATTV
Definition pindefs.h:35
#define LEDR
Definition pindefs.h:42
#define PIN_BATTV_ENABLE
Definition pindefs.h:33
#define LEDB
Definition pindefs.h:44
Extension of BleInterface providing the PTV / PTVSOAR protocol formats.
Manage power supply status of the device.
Varios methods to produce the buzzer sounds.
#define NOTE_E3
Definition sounds.h:61
#define NOTE_G3
Definition sounds.h:58
#define MELODY_END
Definition sounds.h:114
#define NOTE_C3
Definition sounds.h:65
Sensor data structure.
int isCharging
Charging state.
float batPct
Battery charge %.
float batVolt
Battery Voltage.
float diffPa
SDP31 differential pressure Pa.
float humPct
SHT humidity %.
float tempC
SHT temperature °C.
float absHpa
DPS310 barometric pressure hPa.