From 084cf507925eacc4eccb89e35c82cb2613d92397 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 1 Apr 2019 18:01:52 +0200 Subject: [PATCH 1/2] New feature display pages added (issue #278) --- include/button.h | 1 + include/display.h | 4 +- src/button.cpp | 12 ++++-- src/display.cpp | 105 +++++++++++++++++++++++++++++++++++++++------- src/main.cpp | 2 +- 5 files changed, 104 insertions(+), 20 deletions(-) diff --git a/include/button.h b/include/button.h index a7555c0a..da168520 100644 --- a/include/button.h +++ b/include/button.h @@ -1,6 +1,7 @@ #ifndef _BUTTON_H #define _BUTTON_H +#include "display.h" #include "senddata.h" void readButton(); diff --git a/include/display.h b/include/display.h index 38d503a9..43d58efa 100644 --- a/include/display.h +++ b/include/display.h @@ -4,12 +4,14 @@ #include #include "cyclic.h" -extern uint8_t DisplayState; +extern uint8_t DisplayIsOn; extern HAS_DISPLAY u8x8; void init_display(const char *Productname, const char *Version); void refreshtheDisplay(void); +void refreshtheDisplay(bool nextPage); +void draw_page(time_t t, uint8_t page); void DisplayKey(const uint8_t *key, uint8_t len, bool lsb); #endif \ No newline at end of file diff --git a/src/button.cpp b/src/button.cpp index 93201580..68e29d4e 100644 --- a/src/button.cpp +++ b/src/button.cpp @@ -7,9 +7,13 @@ static const char TAG[] = __FILE__; void readButton() { - ESP_LOGI(TAG, "Button pressed"); - payload.reset(); - payload.addButton(0x01); - SendPayload(BUTTONPORT, prio_normal); + ESP_LOGI(TAG, "Button pressed"); +#ifdef HAS_DISPLAY + refreshtheDisplay(true); // switch to next display page +#else + payload.reset(); + payload.addButton(0x01); + SendPayload(BUTTONPORT, prio_normal); +#endif } #endif \ No newline at end of file diff --git a/src/display.cpp b/src/display.cpp index 225bbf0d..aa7b5ffc 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -26,6 +26,8 @@ line 7: y = Text for LMIC status; ab = payload queue #include "globals.h" #include // needed for reading ESP32 chip attributes +#define DISPLAY_PAGES (3) // number of display pages + HAS_DISPLAY u8x8(MY_OLED_RST, MY_OLED_SCL, MY_OLED_SDA); // helper string for converting LoRa spread factor values @@ -45,7 +47,7 @@ const char lora_datarate[] = {"121110090807FSNA"}; const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -uint8_t DisplayState = 0; +uint8_t DisplayIsOn = 0; // helper function, prints a hex key on display void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) { @@ -127,28 +129,52 @@ void init_display(const char *Productname, const char *Version) { } // mutex } // init_display -void refreshtheDisplay() { +void refreshtheDisplay(bool nextPage) { - uint8_t msgWaiting; - char timeState, buff[16]; + static uint8_t DisplayPage = 0; const time_t t = myTZ.toLocal(now()); // note: call now() here *before* locking mutex! + // if display is switched off we don't refresh it to relax cpu + if (!DisplayIsOn && (DisplayIsOn == cfg.screenon)) + return; + // block i2c bus access if (I2C_MUTEX_LOCK()) { // set display on/off according to current device configuration - if (DisplayState != cfg.screenon) { - DisplayState = cfg.screenon; + if (DisplayIsOn != cfg.screenon) { + DisplayIsOn = cfg.screenon; u8x8.setPowerSave(!cfg.screenon); } - // if display is switched off we don't refresh it to relax cpu - if (!DisplayState) { - I2C_MUTEX_UNLOCK(); // release i2c bus access - return; + if (nextPage) { + DisplayPage = (DisplayPage >= DISPLAY_PAGES - 1) ? 0 : (DisplayPage + 1); + u8x8.clear(); } + draw_page(t, DisplayPage); + + I2C_MUTEX_UNLOCK(); // release i2c bus access + + } // mutex +} // refreshDisplay() + +void refreshtheDisplay() { refreshtheDisplay(false); } + +void draw_page(time_t t, uint8_t page) { + + char timeState, buff[16]; + uint8_t msgWaiting; + + switch (page % DISPLAY_PAGES) { + + // page 0: parameters overview + // page 1: time + // page 2: GPS + // page 3: BME280/680 + + case 0: // update counter (lines 0-1) snprintf( buff, sizeof(buff), "PAX:%-4d", @@ -218,7 +244,7 @@ void refreshtheDisplay() { TimePulseTick = false; // display inverse timeState if clock controller is enabled #if (defined HAS_DCF77) || (defined HAS_IF482) - u8x8.printf("%02d:%02d:%02d", hour(t), minute(t), second(t), timeState); + u8x8.printf("%02d:%02d:%02d", hour(t), minute(t), second(t)); u8x8.setInverseFont(1); u8x8.printf("%c", timeState); u8x8.setInverseFont(0); @@ -251,8 +277,59 @@ void refreshtheDisplay() { #endif // HAS_LORA - I2C_MUTEX_UNLOCK(); // release i2c bus access - } // mutex -} // refreshDisplay() + break; // page0 + + case 1: + // update counter (lines 0-1) + snprintf( + buff, sizeof(buff), "PAX:%-4d", + (int) + macs.size()); // convert 16-bit MAC counter to decimal counter value + u8x8.draw2x2String(0, 0, + buff); // display number on unique macs total Wifi + BLE + + // line 4-5: update time-of-day + snprintf(buff, sizeof(buff), "%02d:%02d:%02d", hour(t), minute(t), + second(t)); + u8x8.draw2x2String(0, 4, buff); + + break; // page1 + + case 2: + // update counter (lines 0-1) + snprintf( + buff, sizeof(buff), "PAX:%-4d", + (int) + macs.size()); // convert 16-bit MAC counter to decimal counter value + u8x8.draw2x2String(0, 0, + buff); // display number on unique macs total Wifi + BLE + +#if (HAS_GPS) + if (gps.location.age() < 1500) { + // line 3-4: GPS latitude + snprintf(buff, sizeof(buff), "%-02.4f", gps.location.lat()); + u8x8.draw2x2String(0, 3, buff); + + // line 6-7: GPS longitude + snprintf(buff, sizeof(buff), "%-03.4f", gps.location.lng()); + u8x8.draw2x2String(0, 6, buff); + } else { + snprintf(buff, sizeof(buff), "No fix"); + u8x8.draw2x2String(2, 5, buff); + } + +#else + snprintf(buff, sizeof(buff), "No GPS"); + u8x8.draw2x2String(2, 5, buff); +#endif + + break; // page2 + + default: + break; // default + + } // switch + +} // draw_page #endif // HAS_DISPLAY \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index dd6fe4e9..594d299f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -314,7 +314,7 @@ void setup() { // initialize display #ifdef HAS_DISPLAY strcat_P(features, " OLED"); - DisplayState = cfg.screenon; + DisplayIsOn = cfg.screenon; init_display(PRODUCTNAME, PROGVERSION); // note: blocking call #endif From 41db662627398fa72eed502700f6eba1e96845e5 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Mon, 1 Apr 2019 18:34:57 +0200 Subject: [PATCH 2/2] New display pages feature added --- README.md | 6 +++++- src/display.cpp | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 563be004..5d50dc5d 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Depending on board hardware following features are supported: - LED (shows power & status) - OLED Display (shows detailed status) - RGB LED (shows colorized status) -- Button +- Button (used to flip display pages if device has display, else sends alarm message) - Silicon unique ID - Battery voltage monitoring - GPS (Generic serial NMEA, or Quectel L76 I2C) @@ -140,6 +140,10 @@ Paxcounter generates identifiers for sniffed MAC adresses and collects them temp - Red long blink: LoRaWAN stack error - White long blink: Known Beacon detected +# Display + +If you're using a device with OLED display, or if you add such one to the I2C bus, the device shows live data on the display. You can flip between pages showing pax, time and gps data by pressing the button of the device. + # Sensors and Peripherals You can add up to 3 user defined sensors. Insert sensor's payload scheme in [*sensors.cpp*](src/sensors.cpp). Bosch BME280 / BME680 environment sensors are supported. Enable *flag lib_deps_sensors* for your board in [*platformio.ini*](src/platformio.ini) and configure BME in board's hal file before build. If you need Bosch's proprietary BSEC libraray (e.g. to get indoor air quality value from BME680) further enable *build_flags_sensors*, which comes on the price of reduced RAM and increased build size. RTC DS3231, generic serial NMEA GPS, I2C LoPy GPS are supported, and to be configured in board's hal file. See [*generic.h*](src/hal/generic.h) for all options. diff --git a/src/display.cpp b/src/display.cpp index aa7b5ffc..6899e951 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -166,6 +166,7 @@ void draw_page(time_t t, uint8_t page) { char timeState, buff[16]; uint8_t msgWaiting; + static bool wasnofix = true; switch (page % DISPLAY_PAGES) { @@ -306,16 +307,28 @@ void draw_page(time_t t, uint8_t page) { #if (HAS_GPS) if (gps.location.age() < 1500) { + // line 5: clear "No fix" + if (wasnofix) { + snprintf(buff, sizeof(buff), " "); + u8x8.draw2x2String(2, 5, buff); + wasnofix = false; + } // line 3-4: GPS latitude - snprintf(buff, sizeof(buff), "%-02.4f", gps.location.lat()); + snprintf(buff, sizeof(buff), "%c%-07.4f", + gps.location.rawLat().negative ? 'S' : 'N', gps.location.lat()); u8x8.draw2x2String(0, 3, buff); // line 6-7: GPS longitude - snprintf(buff, sizeof(buff), "%-03.4f", gps.location.lng()); + snprintf(buff, sizeof(buff), "%c%-07.4f", + gps.location.rawLat().negative ? 'W' : 'E', gps.location.lng()); u8x8.draw2x2String(0, 6, buff); + } else { snprintf(buff, sizeof(buff), "No fix"); + u8x8.setInverseFont(1); u8x8.draw2x2String(2, 5, buff); + u8x8.setInverseFont(0); + wasnofix = true; } #else