diff --git a/TODO.md b/TODO.md index 38bbf8564..f8ca81d78 100644 --- a/TODO.md +++ b/TODO.md @@ -33,6 +33,7 @@ * optionally do lora messaging only during special scheduled intervals (unless nodes are told to go to low latency mode), then deep sleep except during those intervals - before implementing calculate what battery life would be with this feature * see section 7.3 of https://cdn.sparkfun.com/assets/learn_tutorials/8/0/4/RFM95_96_97_98W.pdf and have hope radio wake only when a valid packet is received. Possibly even wake the ESP32 from deep sleep via GPIO. * never enter deep sleep while connected to USB power (but still go to other low power modes) +* when main cpu is idle (in loop), turn cpu clock rate down and/or activate special sleep modes. We want almost everything shutdown until it gets an interrupt. # dynamic nodenum assignment tasks diff --git a/images/compass.png b/images/compass.png new file mode 100644 index 000000000..8639dde52 Binary files /dev/null and b/images/compass.png differ diff --git a/images/face.png b/images/face.png new file mode 100644 index 000000000..036e29f73 Binary files /dev/null and b/images/face.png differ diff --git a/images/genfiles.sh b/images/genfiles.sh index 1a2f7b8ed..bc14f6e8e 100755 --- a/images/genfiles.sh +++ b/images/genfiles.sh @@ -1,3 +1,11 @@ # using height of 50 to have 14 pixels beneath icon for text inkscape -z -e icon.png -w 50 -h 50 icon-24px.svg convert icon.png -background white -alpha Background ../src/icon.xbm + +inkscape -z -e compass.png -w 48 -h 48 location_searching-24px.svg +convert compass.png -background white -alpha Background ../src/compass.xbm + +inkscape -z -e face.png -w 13 -h 13 face-24px.svg + +inkscape -z -e pin.png -w 13 -h 13 room-24px.svg +convert pin.png -background white -alpha Background ../src/pin.xbm diff --git a/images/pin.png b/images/pin.png new file mode 100644 index 000000000..112a7ce8e Binary files /dev/null and b/images/pin.png differ diff --git a/src/MeshService.cpp b/src/MeshService.cpp index 0477de1f8..696d68c5f 100644 --- a/src/MeshService.cpp +++ b/src/MeshService.cpp @@ -7,6 +7,7 @@ #include "MeshBluetoothService.h" #include "NodeDB.h" #include "GPS.h" +#include "screen.h" /* receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone. @@ -72,6 +73,9 @@ void MeshService::loop() // Someone just sent us a User, reply with our Owner DEBUG_MSG("Received broadcast Owner from 0x%x, replying with our owner\n", mp->from); sendOurOwner(mp->from); + + String lcd = String("Joined: ") + mp->payload.variant.user.long_name; + screen_print(lcd.c_str()); } fromNum++; diff --git a/src/compass.xbm b/src/compass.xbm new file mode 100644 index 000000000..115a7a1d4 --- /dev/null +++ b/src/compass.xbm @@ -0,0 +1,28 @@ +#define compass_width 48 +#define compass_height 48 +static char compass_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00, + 0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, + 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFC, 0x07, 0xE0, 0x3F, 0x00, + 0x00, 0xFE, 0x01, 0x80, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, + 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xFC, 0x01, + 0x80, 0x1F, 0x00, 0x00, 0xF8, 0x01, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01, + 0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, + 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, + 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, + 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, 0xFC, 0x07, 0x00, 0x00, 0xE0, 0x3F, + 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, + 0xC0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x03, + 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01, 0x80, 0x1F, 0x00, 0x00, 0xF8, 0x01, + 0x80, 0x3F, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x01, 0x80, 0x7F, 0x00, + 0x00, 0xFC, 0x07, 0xE0, 0x3F, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, + 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x00, + 0x00, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; diff --git a/src/icon.xbm b/src/icon.xbm index 7b07a22e2..d7394c8e7 100644 --- a/src/icon.xbm +++ b/src/icon.xbm @@ -1,6 +1,6 @@ #define icon_width 50 #define icon_height 50 -static const char icon_bits[] = { +static char icon_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, diff --git a/src/images.h b/src/images.h index 6d1232cab..6a9992c2d 100644 --- a/src/images.h +++ b/src/images.h @@ -7,8 +7,12 @@ const uint8_t SATELLITE_IMAGE[] PROGMEM = { }; +const #include "icon.xbm" +const +#include "compass.xbm" + #if 0 const uint8_t activeSymbol[] PROGMEM = { B00000000, diff --git a/src/main.ino b/src/main.ino index 0550fc234..c15f1e338 100644 --- a/src/main.ino +++ b/src/main.ino @@ -352,11 +352,7 @@ void setup() // Init GPS gps.setup(); - // Show logo on first boot after removing battery - //if (bootCount == 0) { - screen_print(APP_NAME " " APP_VERSION); - screen_show_logo(); - //} + screen_print("Started..."); service.init(); @@ -430,6 +426,6 @@ void loop() // No GPS lock yet, let the OS put the main CPU in low power mode for 100ms (or until another interrupt comes in) // i.e. don't just keep spinning in loop as fast as we can. - DEBUG_MSG("msecs %d\n", msecstosleep); + //DEBUG_MSG("msecs %d\n", msecstosleep); delay(msecstosleep); } \ No newline at end of file diff --git a/src/pin.xbm b/src/pin.xbm new file mode 100644 index 000000000..e8c8f8930 --- /dev/null +++ b/src/pin.xbm @@ -0,0 +1,6 @@ +#define pin_width 13 +#define pin_height 13 +static char pin_bits[] = { + 0x00, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xBC, 0x07, 0xBC, 0x07, + 0xFC, 0x07, 0xF8, 0x03, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0xE0, 0x00, + 0x00, 0x00, }; diff --git a/src/screen.cpp b/src/screen.cpp index 589b060b7..462d2ac24 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -110,30 +110,105 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 String sender = "KH:"; display->drawString(0 + x, 0 + y, sender); display->setFont(ArialMT_Plain_10); - display->drawStringMaxWidth(4 + x, 10 + y, 128, " Lorem ipsum\n dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore."); + display->drawStringMaxWidth(4 + x, 10 + y, 128, " Lorem ipsum\n dolor sit amet, consetetur sadipscing elitr, sed diam"); - ui.disableIndicator(); + // ui.disableIndicator(); } -void drawFrame5(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +/// Draw a series of fields in a column, wrapping to multiple colums if needed +void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields) { + // The coordinates define the left starting point of the text + display->setTextAlignment(TEXT_ALIGN_LEFT); + + const char **f = fields; + int xo = x, yo = y; + while (*f) + { + display->drawString(xo, yo, *f); + yo += FONT_HEIGHT; + if (yo > SCREEN_HEIGHT - FONT_HEIGHT) + { + xo += SCREEN_WIDTH / 2; + yo = 0; + } + f++; + } +} + +/// Draw a series of fields in a row, wrapping to multiple rows if needed +/// @return the max y we ended up printing to +uint32_t drawRows(OLEDDisplay *display, int16_t x, int16_t y, const char **fields) +{ + // The coordinates define the left starting point of the text + display->setTextAlignment(TEXT_ALIGN_LEFT); + + const char **f = fields; + int xo = x, yo = y; + while (*f) + { + display->drawString(xo, yo, *f); + xo += SCREEN_WIDTH / 2; // hardwired for two columns per row.... + if (xo >= SCREEN_WIDTH) + { + yo += FONT_HEIGHT; + xo = 0; + } + f++; + } + + yo += FONT_HEIGHT; // include the last line in our total + + return yo; +} + +void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + display->setFont(ArialMT_Plain_10); + + // The coordinates define the left starting point of the text + display->setTextAlignment(TEXT_ALIGN_LEFT); + + const char *fields[] = { + "Kevin Hester (KH)", + "4.2 mi", + "Signal: good", + "24 minutes ago", + NULL}; + drawColumns(display, x, y, fields); + + display->drawXbm(x + (SCREEN_WIDTH - compass_width), y + (SCREEN_HEIGHT - compass_height) / 2, compass_width, compass_height, (const uint8_t *)compass_bits); +} + +void drawDebugInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + display->setFont(ArialMT_Plain_10); + + // The coordinates define the left starting point of the text + display->setTextAlignment(TEXT_ALIGN_LEFT); + + const char *fields[] = { + "Batt 89%", + "GPS 75%", + "Users 4/12", + NULL}; + uint32_t yo = drawRows(display, x, y, fields); + + display->drawLogBuffer(x, yo); } // This array keeps function pointers to all frames // frames are the single views that slide in -FrameCallback frames[] = {drawBootScreen, drawTextMessageFrame}; +FrameCallback frames[] = {drawBootScreen, drawTextMessageFrame, drawNodeInfo, drawDebugInfo}; FrameCallback *nonBootFrames = frames + 1; - // Overlays are statically drawn on top of a frame eg. a clock -OverlayCallback overlays[] = {msOverlay}; +OverlayCallback overlays[] = {/* msOverlay */}; // how many frames are there? const int frameCount = sizeof(frames) / sizeof(frames[0]); const int overlaysCount = sizeof(overlays) / sizeof(overlays[0]); - - void _screen_header() { if (!disp) @@ -157,18 +232,6 @@ void _screen_header() #endif } -void screen_show_logo() -{ - if (!disp) - return; - -#if 0 - uint8_t x = (display->getWidth() - TTN_IMAGE_WIDTH) / 2; - uint8_t y = SCREEN_HEADER_HEIGHT + (display->getHeight() - SCREEN_HEADER_HEIGHT - TTN_IMAGE_HEIGHT) / 2 + 1; - display->drawXbm(x, y, TTN_IMAGE_WIDTH, TTN_IMAGE_HEIGHT, TTN_IMAGE); -#endif -} - void screen_off() { if (!disp) @@ -208,12 +271,7 @@ void screen_print(const char *text) return; dispdev.print(text); - /* if (_screen_line + 8 > dispdev.getHeight()) - { - // scroll - } - _screen_line += 8; */ - screen_loop(); + // ui.update(); } void screen_setup() @@ -242,8 +300,8 @@ void screen_setup() // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_UP, SLIDE_DOWN ui.setFrameAnimation(SLIDE_LEFT); - // Add frames - ui.setFrames(frames, frameCount); + // Add frames - we subtract one from the framecount so there won't be a visual glitch when we take the boot screen out of the sequence. + ui.setFrames(frames, frameCount - 1); // Add overlays ui.setOverlays(overlays, overlaysCount); @@ -252,7 +310,7 @@ void screen_setup() ui.init(); // Scroll buffer - dispdev.setLogBuffer(5, 30); + dispdev.setLogBuffer(5, 32); // dispdev.flipScreenVertically(); // looks better without this on lora32 // dispdev.setFont(Custom_ArialMT_Plain_10); @@ -295,14 +353,12 @@ uint32_t screen_loop() #endif static bool showingBootScreen = true; - - - - uint32_t msecstosleep = ui.update(); + ui.update(); // Once we finish showing the bootscreen, remove it from the loop if (showingBootScreen && ui.getUiState()->currentFrame == 1) { + showingBootScreen = false; ui.setFrames(nonBootFrames, frameCount - 1); }