Ver código fonte

* basic UITask added to repeater and room server (only HeltecV3 targets enable so far)

Scott Powell 1 ano atrás
pai
commit
c2ae34314e

+ 79 - 0
examples/simple_repeater/UITask.cpp

@@ -0,0 +1,79 @@
+#include "UITask.h"
+#include <Arduino.h>
+
+#define AUTO_OFF_MILLIS   20000   // 20 seconds
+
+// 'meshcore', 128x13px
+static const uint8_t meshcore_logo [] PROGMEM = {
+    0x3c, 0x01, 0xe3, 0xff, 0xc7, 0xff, 0x8f, 0x03, 0x87, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 
+    0x3c, 0x03, 0xe3, 0xff, 0xc7, 0xff, 0x8e, 0x03, 0x8f, 0xfe, 0x3f, 0xfe, 0x1f, 0xff, 0x1f, 0xfe, 
+    0x3e, 0x03, 0xc3, 0xff, 0x8f, 0xff, 0x0e, 0x07, 0x8f, 0xfe, 0x7f, 0xfe, 0x1f, 0xff, 0x1f, 0xfc, 
+    0x3e, 0x07, 0xc7, 0x80, 0x0e, 0x00, 0x0e, 0x07, 0x9e, 0x00, 0x78, 0x0e, 0x3c, 0x0f, 0x1c, 0x00, 
+    0x3e, 0x0f, 0xc7, 0x80, 0x1e, 0x00, 0x0e, 0x07, 0x1e, 0x00, 0x70, 0x0e, 0x38, 0x0f, 0x3c, 0x00, 
+    0x7f, 0x0f, 0xc7, 0xfe, 0x1f, 0xfc, 0x1f, 0xff, 0x1c, 0x00, 0x70, 0x0e, 0x38, 0x0e, 0x3f, 0xf8, 
+    0x7f, 0x1f, 0xc7, 0xfe, 0x0f, 0xff, 0x1f, 0xff, 0x1c, 0x00, 0xf0, 0x0e, 0x38, 0x0e, 0x3f, 0xf8, 
+    0x7f, 0x3f, 0xc7, 0xfe, 0x0f, 0xff, 0x1f, 0xff, 0x1c, 0x00, 0xf0, 0x1e, 0x3f, 0xfe, 0x3f, 0xf0, 
+    0x77, 0x3b, 0x87, 0x00, 0x00, 0x07, 0x1c, 0x0f, 0x3c, 0x00, 0xe0, 0x1c, 0x7f, 0xfc, 0x38, 0x00, 
+    0x77, 0xfb, 0x8f, 0x00, 0x00, 0x07, 0x1c, 0x0f, 0x3c, 0x00, 0xe0, 0x1c, 0x7f, 0xf8, 0x38, 0x00, 
+    0x73, 0xf3, 0x8f, 0xff, 0x0f, 0xff, 0x1c, 0x0e, 0x3f, 0xf8, 0xff, 0xfc, 0x70, 0x78, 0x7f, 0xf8, 
+    0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfe, 0x3c, 0x0e, 0x3f, 0xf8, 0xff, 0xfc, 0x70, 0x3c, 0x7f, 0xf8, 
+    0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfc, 0x3c, 0x0e, 0x1f, 0xf8, 0xff, 0xf8, 0x70, 0x3c, 0x7f, 0xf8, 
+};
+
+void UITask::begin(const char* node_name, const char* build_date) {
+  _prevBtnState = HIGH;
+  _auto_off = millis() + AUTO_OFF_MILLIS;
+  _node_name = node_name;
+  _build_date = build_date;
+  _display->turnOn();
+}
+
+void UITask::renderCurrScreen() {
+  char tmp[80];
+  // render 'home' screen
+  _display->drawXbm(0, 0, meshcore_logo, 128, 13);
+  _display->setCursor(0, 20);
+  _display->setTextSize(1);
+  _display->print(_node_name);
+
+  sprintf(tmp, "Build: %s", _build_date);
+  _display->setCursor(0, 32);
+  _display->print(tmp);
+  _display->setCursor(0, 43);
+  _display->print("< Repeater >");
+  //_display->printf("freq : %03.2f sf %d\n", _prefs.freq, _prefs.sf);
+  //_display->printf("bw   : %03.2f cr %d\n", _prefs.bw, _prefs.cr);
+}
+
+void UITask::loop() {
+#ifdef PIN_USER_BTN
+  if (millis() >= _next_read) {
+    int btnState = digitalRead(PIN_USER_BTN);
+    if (btnState != _prevBtnState) {
+      if (btnState == LOW) {  // pressed?
+        if (_display->isOn()) {
+          // TODO: any action ?
+        } else {
+          _display->turnOn();
+        }
+        _auto_off = millis() + AUTO_OFF_MILLIS;   // extend auto-off timer
+      }
+      _prevBtnState = btnState;
+    }
+    _next_read = millis() + 200;  // 5 reads per second
+  }
+#endif
+
+  if (_display->isOn()) {
+    if (millis() >= _next_refresh) {
+      _display->startFrame();
+      renderCurrScreen();
+      _display->endFrame();
+
+      _next_refresh = millis() + 1000;   // refresh every second
+    }
+    if (millis() > _auto_off) {
+      _display->turnOff();
+    }
+  }
+}

+ 18 - 0
examples/simple_repeater/UITask.h

@@ -0,0 +1,18 @@
+#pragma once
+
+#include <helpers/ui/DisplayDriver.h>
+
+class UITask {
+  DisplayDriver* _display;
+  unsigned long _next_read, _next_refresh, _auto_off;
+  int _prevBtnState;
+  const char* _node_name;
+  const char* _build_date;
+
+  void renderCurrScreen();
+public:
+  UITask(DisplayDriver& display) : _display(&display) { _next_read = _next_refresh = 0; }
+  void begin(const char* node_name, const char* build_date);
+
+  void loop();
+};

+ 21 - 0
examples/simple_repeater/main.cpp

@@ -84,6 +84,15 @@
   #error "need to provide a 'board' object"
 #endif
 
+#ifdef DISPLAY_CLASS
+  #include <helpers/ui/SSD1306Display.h>
+
+  static DISPLAY_CLASS  display;
+
+  #include "UITask.h"
+  static UITask ui_task(display);
+#endif
+
 #define PACKET_LOG_FILE  "/packet_log"
 
 /* ------------------------------ Code -------------------------------- */
@@ -529,6 +538,7 @@ public:
 
   const char* getFirmwareVer() override { return FIRMWARE_VERSION; }
   const char* getBuildDate() override { return FIRMWARE_BUILD_DATE; }
+  const char* getNodeName() { return _prefs.node_name; }
 
   void savePrefs() override {
 #if defined(NRF52_PLATFORM)
@@ -604,6 +614,9 @@ public:
 
       updateAdvertTimer();   // schedule next local advert
     }
+  #ifdef DISPLAY_CLASS
+    ui_task.loop();
+  #endif
   }
 };
 
@@ -649,6 +662,10 @@ void setup() {
   float tcxo = 1.6f;
 #endif
   
+#ifdef DISPLAY_CLASS
+  display.begin();
+#endif
+
 #if defined(NRF52_PLATFORM)
   SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
   SPI.begin();
@@ -701,6 +718,10 @@ void setup() {
 
   the_mesh.begin(fs);
 
+#ifdef DISPLAY_CLASS
+  ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE);
+#endif
+
   // send out initial Advertisement to the mesh
   the_mesh.sendSelfAdvertisement(2000);
 }

+ 79 - 0
examples/simple_room_server/UITask.cpp

@@ -0,0 +1,79 @@
+#include "UITask.h"
+#include <Arduino.h>
+
+#define AUTO_OFF_MILLIS   20000   // 20 seconds
+
+// 'meshcore', 128x13px
+static const uint8_t meshcore_logo [] PROGMEM = {
+    0x3c, 0x01, 0xe3, 0xff, 0xc7, 0xff, 0x8f, 0x03, 0x87, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 
+    0x3c, 0x03, 0xe3, 0xff, 0xc7, 0xff, 0x8e, 0x03, 0x8f, 0xfe, 0x3f, 0xfe, 0x1f, 0xff, 0x1f, 0xfe, 
+    0x3e, 0x03, 0xc3, 0xff, 0x8f, 0xff, 0x0e, 0x07, 0x8f, 0xfe, 0x7f, 0xfe, 0x1f, 0xff, 0x1f, 0xfc, 
+    0x3e, 0x07, 0xc7, 0x80, 0x0e, 0x00, 0x0e, 0x07, 0x9e, 0x00, 0x78, 0x0e, 0x3c, 0x0f, 0x1c, 0x00, 
+    0x3e, 0x0f, 0xc7, 0x80, 0x1e, 0x00, 0x0e, 0x07, 0x1e, 0x00, 0x70, 0x0e, 0x38, 0x0f, 0x3c, 0x00, 
+    0x7f, 0x0f, 0xc7, 0xfe, 0x1f, 0xfc, 0x1f, 0xff, 0x1c, 0x00, 0x70, 0x0e, 0x38, 0x0e, 0x3f, 0xf8, 
+    0x7f, 0x1f, 0xc7, 0xfe, 0x0f, 0xff, 0x1f, 0xff, 0x1c, 0x00, 0xf0, 0x0e, 0x38, 0x0e, 0x3f, 0xf8, 
+    0x7f, 0x3f, 0xc7, 0xfe, 0x0f, 0xff, 0x1f, 0xff, 0x1c, 0x00, 0xf0, 0x1e, 0x3f, 0xfe, 0x3f, 0xf0, 
+    0x77, 0x3b, 0x87, 0x00, 0x00, 0x07, 0x1c, 0x0f, 0x3c, 0x00, 0xe0, 0x1c, 0x7f, 0xfc, 0x38, 0x00, 
+    0x77, 0xfb, 0x8f, 0x00, 0x00, 0x07, 0x1c, 0x0f, 0x3c, 0x00, 0xe0, 0x1c, 0x7f, 0xf8, 0x38, 0x00, 
+    0x73, 0xf3, 0x8f, 0xff, 0x0f, 0xff, 0x1c, 0x0e, 0x3f, 0xf8, 0xff, 0xfc, 0x70, 0x78, 0x7f, 0xf8, 
+    0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfe, 0x3c, 0x0e, 0x3f, 0xf8, 0xff, 0xfc, 0x70, 0x3c, 0x7f, 0xf8, 
+    0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfc, 0x3c, 0x0e, 0x1f, 0xf8, 0xff, 0xf8, 0x70, 0x3c, 0x7f, 0xf8, 
+};
+
+void UITask::begin(const char* node_name, const char* build_date) {
+  _prevBtnState = HIGH;
+  _auto_off = millis() + AUTO_OFF_MILLIS;
+  _node_name = node_name;
+  _build_date = build_date;
+  _display->turnOn();
+}
+
+void UITask::renderCurrScreen() {
+  char tmp[80];
+  // render 'home' screen
+  _display->drawXbm(0, 0, meshcore_logo, 128, 13);
+  _display->setCursor(0, 20);
+  _display->setTextSize(1);
+  _display->print(_node_name);
+
+  sprintf(tmp, "Build: %s", _build_date);
+  _display->setCursor(0, 32);
+  _display->print(tmp);
+  _display->setCursor(0, 43);
+  _display->print("< Room Server >");
+  //_display->printf("freq : %03.2f sf %d\n", _prefs.freq, _prefs.sf);
+  //_display->printf("bw   : %03.2f cr %d\n", _prefs.bw, _prefs.cr);
+}
+
+void UITask::loop() {
+#ifdef PIN_USER_BTN
+  if (millis() >= _next_read) {
+    int btnState = digitalRead(PIN_USER_BTN);
+    if (btnState != _prevBtnState) {
+      if (btnState == LOW) {  // pressed?
+        if (_display->isOn()) {
+          // TODO: any action ?
+        } else {
+          _display->turnOn();
+        }
+        _auto_off = millis() + AUTO_OFF_MILLIS;   // extend auto-off timer
+      }
+      _prevBtnState = btnState;
+    }
+    _next_read = millis() + 200;  // 5 reads per second
+  }
+#endif
+
+  if (_display->isOn()) {
+    if (millis() >= _next_refresh) {
+      _display->startFrame();
+      renderCurrScreen();
+      _display->endFrame();
+
+      _next_refresh = millis() + 1000;   // refresh every second
+    }
+    if (millis() > _auto_off) {
+      _display->turnOff();
+    }
+  }
+}

+ 18 - 0
examples/simple_room_server/UITask.h

@@ -0,0 +1,18 @@
+#pragma once
+
+#include <helpers/ui/DisplayDriver.h>
+
+class UITask {
+  DisplayDriver* _display;
+  unsigned long _next_read, _next_refresh, _auto_off;
+  int _prevBtnState;
+  const char* _node_name;
+  const char* _build_date;
+
+  void renderCurrScreen();
+public:
+  UITask(DisplayDriver& display) : _display(&display) { _next_read = _next_refresh = 0; }
+  void begin(const char* node_name, const char* build_date);
+
+  void loop();
+};

+ 22 - 0
examples/simple_room_server/main.cpp

@@ -88,6 +88,15 @@
   #error "need to provide a 'board' object"
 #endif
 
+#ifdef DISPLAY_CLASS
+  #include <helpers/ui/SSD1306Display.h>
+
+  static DISPLAY_CLASS  display;
+
+  #include "UITask.h"
+  static UITask ui_task(display);
+#endif
+
 /* ------------------------------ Code -------------------------------- */
 
 struct ClientInfo {
@@ -570,6 +579,7 @@ public:
 
   const char* getFirmwareVer() override { return FIRMWARE_VERSION; }
   const char* getBuildDate() override { return FIRMWARE_BUILD_DATE; }
+  const char* getNodeName() { return _prefs.node_name; }
 
   void savePrefs() override {
 #if defined(NRF52_PLATFORM)
@@ -664,6 +674,10 @@ public:
       updateAdvertTimer();   // schedule next local advert
     }
 
+  #ifdef DISPLAY_CLASS
+    ui_task.loop();
+  #endif
+
     // TODO: periodically check for OLD/inactive entries in known_clients[], and evict
   }
 };
@@ -710,6 +724,10 @@ void setup() {
   float tcxo = 1.6f;
 #endif
 
+#ifdef DISPLAY_CLASS
+  display.begin();
+#endif
+
 #if defined(NRF52_PLATFORM)
   SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
   SPI.begin();
@@ -761,6 +779,10 @@ void setup() {
 
   the_mesh.begin(fs);
 
+#ifdef DISPLAY_CLASS
+  ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE);
+#endif
+
   // send out initial Advertisement to the mesh
   the_mesh.sendSelfAdvertisement(2000);
 }

+ 5 - 2
platformio.ini

@@ -126,19 +126,21 @@ lib_deps =
 extends = Heltec_lora32_v3
 build_flags =
   ${Heltec_lora32_v3.build_flags} 
+  -D DISPLAY_CLASS=SSD1306Display
   -D ADVERT_NAME="\"Heltec Repeater\""
   -D ADVERT_LAT=-37.0
   -D ADVERT_LON=145.0
   -D ADMIN_PASSWORD="\"password\""
   -D MESH_PACKET_LOGGING=1
 ;  -D MESH_DEBUG=1
-build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<../examples/simple_repeater/main.cpp>
+build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<helpers/ui/*.cpp> +<../examples/simple_repeater>
 
 [env:Heltec_v3_room_server]
 extends = Heltec_lora32_v3
-build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<../examples/simple_room_server/main.cpp>
+build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<helpers/ui/*.cpp> +<../examples/simple_room_server>
 build_flags =
   ${Heltec_lora32_v3.build_flags} 
+  -D DISPLAY_CLASS=SSD1306Display
   -D ADVERT_NAME="\"Heltec Room\""
   -D ADVERT_LAT=-37.0
   -D ADVERT_LON=145.0
@@ -526,6 +528,7 @@ board_build.ldscript = boards/nrf52840_s140_v7.ld
 build_flags = ${nrf52840_t1000e.build_flags} 
   -Ivariants/t1000-e
   -DT1000_E
+  -D PIN_USER_BTN=6
   -D RADIO_CLASS=CustomLR1110
   -D WRAPPER_CLASS=CustomLR1110Wrapper
 build_src_filter = ${nrf52840_t1000e.build_src_filter}