Merge branch 'dev' into ppr1

# Conflicts:
#	src/gps/NMEAGPS.cpp
This commit is contained in:
Kevin Hester 2020-10-16 15:59:55 +08:00
commit 22f23bb07d
12 changed files with 251 additions and 130 deletions

22
bin/install-eink.sh Executable file
View File

@ -0,0 +1,22 @@
# You probably don't want to use this script, it programs a custom bootloader build onto a nrf52 board
set -e
BOOTDIR=/home/kevinh/development/meshtastic/Adafruit_nRF52_Bootloader
nrfjprog --eraseall -f nrf52
# this generates an intel hex file that can be programmed into a NRF52 to tell the adafruit bootloader that the current app image is valid
# Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000
# first 4 bytes should be 0x01 to indicate valid app image
# second 4 bytes should be 0x00 to indicate no CRC required for image
echo "01 00 00 00 00 00 00 00" | xxd -r -p - >/tmp/bootconf.bin
srec_cat /tmp/bootconf.bin -binary -offset 0xff000 -output /tmp/bootconf.hex -intel
echo Generating merged hex file
mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-125-gf38f8f4-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex
echo Telling bootloader app region is valid and telling CPU to run
nrfjprog --program ttgo_eink_full.hex -f nrf52 --reset
# nrfjprog --readuicr /tmp/uicr.hex; objdump -s /tmp/uicr.hex | less

View File

@ -7,6 +7,10 @@
TODO: TODO:
- enter SDS state at correct time (to protect battery or loss of phone contact)
- show screen on eink when we enter SDS state (with app info and say sleeping)
- require button press to pair
- shrink soft device RAM usage - shrink soft device RAM usage
- get nrf52832 working again (currently OOM) - get nrf52832 working again (currently OOM)
- i2c gps comms not quite right - i2c gps comms not quite right

View File

@ -244,10 +244,16 @@ void PowerFSM_setup()
powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout"); powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout");
powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout"); // On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
State *lowPowerState = &stateLS;
#ifndef NRF52_SERIES #ifndef NRF52_SERIES
// We never enter light-sleep state on NRF52 (because the CPU uses so little power normally) // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
lowPowerState = &stateDARK;
powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout"); powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout"); powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
@ -255,9 +261,9 @@ void PowerFSM_setup()
auto meshSds = getPref_mesh_sds_timeout_secs(); auto meshSds = getPref_mesh_sds_timeout_secs();
if (meshSds != UINT32_MAX) if (meshSds != UINT32_MAX)
powerFSM.add_timed_transition(&stateLS, &stateSDS, meshSds * 1000, NULL, "mesh timeout"); powerFSM.add_timed_transition(lowPowerState, &stateSDS, meshSds * 1000, NULL, "mesh timeout");
// removing for now, because some users don't even have phones // removing for now, because some users don't even have phones
// powerFSM.add_timed_transition(&stateLS, &stateSDS, getPref_phone_sds_timeout_sec() * 1000, NULL, "phone // powerFSM.add_timed_transition(lowPowerState, &stateSDS, getPref_phone_sds_timeout_sec() * 1000, NULL, "phone
// timeout"); // timeout");
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state

View File

@ -1,6 +1,6 @@
#include "NMEAGPS.h" #include "NMEAGPS.h"
#include "configuration.h"
#include "RTC.h" #include "RTC.h"
#include "configuration.h"
static int32_t toDegInt(RawDegrees d) static int32_t toDegInt(RawDegrees d)
{ {
@ -32,7 +32,7 @@ bool NMEAGPS::lookForTime()
{ {
auto ti = reader.time; auto ti = reader.time;
auto d = reader.date; auto d = reader.date;
if (ti.isUpdated() && ti.isValid() && d.isValid()) { if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
/* Convert to unix time /* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970
(midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z). (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
@ -65,27 +65,27 @@ bool NMEAGPS::lookForLocation()
// uint8_t fixtype = reader.fixQuality(); // uint8_t fixtype = reader.fixQuality();
// hasValidLocation = ((fixtype >= 1) && (fixtype <= 5)); // hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
if (reader.satellites.isUpdated()) {
setNumSatellites(reader.satellites.value());
}
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
if (reader.hdop.isUpdated()) {
dop = reader.hdop.value();
}
if (reader.course.isUpdated()) {
heading = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
}
if (reader.altitude.isUpdated())
altitude = reader.altitude.meters();
if (reader.location.isUpdated()) { if (reader.location.isUpdated()) {
if (reader.altitude.isValid())
altitude = reader.altitude.meters();
if (reader.location.isValid()) { auto loc = reader.location.value();
auto loc = reader.location.value(); latitude = toDegInt(loc.lat);
latitude = toDegInt(loc.lat); longitude = toDegInt(loc.lng);
longitude = toDegInt(loc.lng); foundLocation = true;
foundLocation = true;
}
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
if (reader.hdop.isValid()) {
dop = reader.hdop.value();
}
if (reader.course.isValid()) {
heading = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
}
if (reader.satellites.isValid()) {
setNumSatellites(reader.satellites.value());
}
// expect gps pos lat=37.520825, lon=-122.309162, alt=158 // expect gps pos lat=37.520825, lon=-122.309162, alt=158
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude,

View File

@ -46,15 +46,18 @@ void updateDisplay(uint8_t *blackFrame = framePtr)
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl) EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
{ {
setGeometry(GEOMETRY_128_64); // FIXME - currently we lie and claim 128x64 because I'm not yet sure other resolutions will setGeometry(GEOMETRY_RAWMODE, EPD_WIDTH, EPD_HEIGHT);
// work ie GEOMETRY_RAWMODE // setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
} }
// FIXME quick hack to limit drawing to a very slow rate // FIXME quick hack to limit drawing to a very slow rate
uint32_t lastDrawMsec; uint32_t lastDrawMsec;
// Write the buffer to the display memory /**
void EInkDisplay::display(void) * Force a display update if we haven't drawn within the specified msecLimit
*/
bool EInkDisplay::forceDisplay(uint32_t msecLimit)
{ {
// No need to grab this lock because we are on our own SPI bus // No need to grab this lock because we are on our own SPI bus
// concurrency::LockGuard g(spiLock); // concurrency::LockGuard g(spiLock);
@ -62,16 +65,16 @@ void EInkDisplay::display(void)
uint32_t now = millis(); uint32_t now = millis();
uint32_t sinceLast = now - lastDrawMsec; uint32_t sinceLast = now - lastDrawMsec;
if (framePtr && (sinceLast > 60 * 1000 || lastDrawMsec == 0)) { if (framePtr && (sinceLast > msecLimit || lastDrawMsec == 0)) {
lastDrawMsec = now; lastDrawMsec = now;
// FIXME - only draw bits have changed (use backbuf similar to the other displays) // FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK); // tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) { for (uint8_t y = 0; y < displayHeight; y++) {
for (uint8_t x = 0; x < SCREEN_WIDTH; x++) { for (uint8_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent // get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto b = buffer[x + (y / 8) * SCREEN_WIDTH]; auto b = buffer[x + (y / 8) * displayWidth];
auto isset = b & (1 << (y & 7)); auto isset = b & (1 << (y & 7));
frame.drawPixel(x, y, isset ? INK : PAPER); frame.drawPixel(x, y, isset ? INK : PAPER);
} }
@ -83,11 +86,25 @@ void EInkDisplay::display(void)
updateDisplay(); // Send image to display and refresh updateDisplay(); // Send image to display and refresh
DEBUG_MSG("done\n"); DEBUG_MSG("done\n");
// Put screen to sleep to save power // Put screen to sleep to save power
ePaper.Sleep(); ePaper.Sleep();
return true;
} else {
// DEBUG_MSG("Skipping eink display\n");
return false;
} }
} }
// Write the buffer to the display memory
void EInkDisplay::display(void)
{
// We don't allow regular 'dumb' display() calls to draw on eink until we've shown
// at least one forceDisplay() keyframe. This prevents flashing when we should the critical
// bootscreen (that we want to look nice)
if (lastDrawMsec)
forceDisplay(slowUpdateMsec); // Show the first screen a few seconds after boot, then slower
}
// Send a command to the display (low level function) // Send a command to the display (low level function)
void EInkDisplay::sendCommand(uint8_t com) void EInkDisplay::sendCommand(uint8_t com)
{ {

View File

@ -14,15 +14,26 @@
*/ */
class EInkDisplay : public OLEDDisplay class EInkDisplay : public OLEDDisplay
{ {
/// How often should we update the display
/// thereafter we do once per 5 minutes
uint32_t slowUpdateMsec = 5 * 60 * 1000;
public: public:
/* constructor /* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/ */
EInkDisplay(uint8_t address, int sda, int scl); EInkDisplay(uint8_t address, int sda, int scl);
// Write the buffer to the display memory // Write the buffer to the display memory (for eink we only do this occasionally)
virtual void display(void); virtual void display(void);
/**
* Force a display update if we haven't drawn within the specified msecLimit
*
* @return true if we did draw the screen
*/
bool forceDisplay(uint32_t msecLimit = 1000);
protected: protected:
// the header size of the buffer used, e.g. for the SPI command header // the header size of the buffer used, e.g. for the SPI command header
virtual int getBufferOffset(void) { return 0; } virtual int getBufferOffset(void) { return 0; }
@ -33,3 +44,5 @@ class EInkDisplay : public OLEDDisplay
// Connect to the display // Connect to the display
virtual bool connect(); virtual bool connect();
}; };

View File

@ -58,17 +58,48 @@ static char ourId[5];
static bool heartbeat = false; static bool heartbeat = false;
#endif #endif
// We used to use constants for this - now we pull from the device at startup
//#define SCREEN_WIDTH 128
//#define SCREEN_HEIGHT 64
static uint16_t displayWidth, displayHeight;
#define SCREEN_WIDTH displayWidth
#define SCREEN_HEIGHT displayHeight
#ifdef HAS_EINK
// The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16
#define FONT_MEDIUM ArialMT_Plain_24
#define FONT_LARGE ArialMT_Plain_24
#else
#define FONT_SMALL ArialMT_Plain_10
#define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24
#endif
#define fontHeight(font) ((font)[1] + 1) // height is position 1
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
// draw an xbm image. // draw an xbm image.
// Please note that everything that should be transitioned // Please note that everything that should be transitioned
// needs to be drawn relative to x and y // needs to be drawn relative to x and y
display->drawXbm(x + 32, y, icon_width, icon_height, (const uint8_t *)icon_bits);
display->setFont(ArialMT_Plain_16); // draw centered left to right and centered above the one line of app text
display->setTextAlignment(TEXT_ALIGN_CENTER); display->drawXbm(x + (SCREEN_WIDTH - icon_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - icon_height) / 2, icon_width,
display->drawString(64 + x, SCREEN_HEIGHT - FONT_HEIGHT_16, "meshtastic.org"); icon_height, (const uint8_t *)icon_bits);
display->setFont(ArialMT_Plain_10);
display->setFont(FONT_MEDIUM);
display->setTextAlignment(TEXT_ALIGN_LEFT);
const char *title = "meshtastic.org";
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
display->setFont(FONT_SMALL);
const char *region = xstr(HW_VERSION); const char *region = xstr(HW_VERSION);
if (*region && region[3] == '-') // Skip past 1.0- in the 1.0-EU865 string if (*region && region[3] == '-') // Skip past 1.0- in the 1.0-EU865 string
region += 4; region += 4;
@ -76,21 +107,24 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1
snprintf(buf, sizeof(buf), "%s", snprintf(buf, sizeof(buf), "%s",
xstr(APP_VERSION)); // Note: we don't bother printing region or now, it makes the string too long xstr(APP_VERSION)); // Note: we don't bother printing region or now, it makes the string too long
display->drawString(SCREEN_WIDTH - 20, 0, buf); display->drawString(SCREEN_WIDTH - 20, 0, buf);
screen->forceDisplay();
} }
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
display->setTextAlignment(TEXT_ALIGN_CENTER); display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_16); display->setFont(FONT_MEDIUM);
display->drawString(64 + x, y, "Bluetooth"); display->drawString(64 + x, y, "Bluetooth");
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
display->drawString(64 + x, FONT_HEIGHT + y + 2, "Enter this code"); display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Enter this code");
display->setFont(ArialMT_Plain_24); display->setFont(FONT_LARGE);
display->drawString(64 + x, 26 + y, btPIN); display->drawString(64 + x, 26 + y, btPIN);
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
char buf[30]; char buf[30];
const char *name = "Name: "; const char *name = "Name: ";
strcpy(buf, name); strcpy(buf, name);
@ -112,10 +146,10 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
// with the third parameter you can define the width after which words will // with the third parameter you can define the width after which words will
// be wrapped. Currently only spaces and "-" are allowed for wrapping // be wrapped. Currently only spaces and "-" are allowed for wrapping
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_16); display->setFont(FONT_MEDIUM);
String sender = (node && node->has_user) ? node->user.short_name : "???"; String sender = (node && node->has_user) ? node->user.short_name : "???";
display->drawString(0 + x, 0 + y, sender); display->drawString(0 + x, 0 + y, sender);
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
// the max length of this buffer is much longer than we can possibly print // the max length of this buffer is much longer than we can possibly print
static char tempBuf[96]; static char tempBuf[96];
@ -135,8 +169,8 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
int xo = x, yo = y; int xo = x, yo = y;
while (*f) { while (*f) {
display->drawString(xo, yo, *f); display->drawString(xo, yo, *f);
yo += FONT_HEIGHT; yo += FONT_HEIGHT_SMALL;
if (yo > SCREEN_HEIGHT - FONT_HEIGHT) { if (yo > SCREEN_HEIGHT - FONT_HEIGHT_SMALL) {
xo += SCREEN_WIDTH / 2; xo += SCREEN_WIDTH / 2;
yo = 0; yo = 0;
} }
@ -162,14 +196,14 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
// Wrap to next row, if needed. // Wrap to next row, if needed.
if (++col >= COLUMNS) { if (++col >= COLUMNS) {
xo = x; xo = x;
yo += FONT_HEIGHT; yo += FONT_HEIGHT_SMALL;
col = 0; col = 0;
} }
f++; f++;
} }
if (col != 0) { if (col != 0) {
// Include last incomplete line in our total. // Include last incomplete line in our total.
yo += FONT_HEIGHT; yo += FONT_HEIGHT_SMALL;
} }
return yo; return yo;
@ -236,7 +270,7 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
display->drawFastImage(x + 24, y, 8, 8, imgSatellite); display->drawFastImage(x + 24, y, 8, 8, imgSatellite);
// Draw the number of satellites // Draw the number of satellites
sprintf(satsString, "%d", gps->getNumSatellites()); sprintf(satsString, "%lu", gps->getNumSatellites());
display->drawString(x + 34, y - 2, satsString); display->drawString(x + 34, y - 2, satsString);
} }
} }
@ -476,7 +510,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex); NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex);
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
@ -489,11 +523,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
uint32_t agoSecs = sinceLastSeen(node); uint32_t agoSecs = sinceLastSeen(node);
static char lastStr[20]; static char lastStr[20];
if (agoSecs < 120) // last 2 mins? if (agoSecs < 120) // last 2 mins?
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs); snprintf(lastStr, sizeof(lastStr), "%lu seconds ago", agoSecs);
else if (agoSecs < 120 * 60) // last 2 hrs else if (agoSecs < 120 * 60) // last 2 hrs
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60); snprintf(lastStr, sizeof(lastStr), "%lu minutes ago", agoSecs / 60);
else else
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60); snprintf(lastStr, sizeof(lastStr), "%lu hours ago", agoSecs / 60 / 60);
static char distStr[20]; static char distStr[20];
strcpy(distStr, "? km"); // might not have location data strcpy(distStr, "? km"); // might not have location data
@ -531,7 +565,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
// direction to node is unknown so display question mark // direction to node is unknown so display question mark
// Debug info for gps lock errors // Debug info for gps lock errors
// DEBUG_MSG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node)); // DEBUG_MSG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
display->drawString(compassX - FONT_HEIGHT / 4, compassY - FONT_HEIGHT / 2, "?"); display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2); display->drawCircle(compassX, compassY, COMPASS_DIAM / 2);
// Must be after distStr is populated // Must be after distStr is populated
@ -561,7 +595,8 @@ void _screen_header()
} }
#endif #endif
Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev) { Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev)
{
cmdQueue.setReader(this); cmdQueue.setReader(this);
} }
@ -596,6 +631,10 @@ void Screen::setup()
// Initialising the UI will init the display too. // Initialising the UI will init the display too.
ui.init(); ui.init();
displayWidth = dispdev.width();
displayHeight = dispdev.height();
ui.setTimePerTransition(300); // msecs ui.setTimePerTransition(300); // msecs
ui.setIndicatorPosition(BOTTOM); ui.setIndicatorPosition(BOTTOM);
// Defines where the first frame is located in the bar. // Defines where the first frame is located in the bar.
@ -645,6 +684,14 @@ void Screen::setup()
nodeStatusObserver.observe(&nodeStatus->onNewStatus); nodeStatusObserver.observe(&nodeStatus->onNewStatus);
} }
void Screen::forceDisplay()
{
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
#ifdef HAS_EINK
dispdev.forceDisplay();
#endif
}
int32_t Screen::runOnce() int32_t Screen::runOnce()
{ {
// If we don't have a screen, don't ever spend any CPU for us. // If we don't have a screen, don't ever spend any CPU for us.
@ -655,7 +702,8 @@ int32_t Screen::runOnce()
// Show boot screen for first 3 seconds, then switch to normal operation. // Show boot screen for first 3 seconds, then switch to normal operation.
static bool showingBootScreen = true; static bool showingBootScreen = true;
if (showingBootScreen && (millis() > 3000)) { if (showingBootScreen && (millis() > 5000)) {
DEBUG_MSG("Done with boot screen...\n");
stopBootScreen(); stopBootScreen();
showingBootScreen = false; showingBootScreen = false;
} }
@ -701,6 +749,10 @@ int32_t Screen::runOnce()
return 0; return 0;
} }
// this must be before the frameState == FIXED check, because we always
// want to draw at least one FIXED frame before doing forceDisplay
ui.update();
// Switch to a low framerate (to save CPU) when we are not in transition // Switch to a low framerate (to save CPU) when we are not in transition
// but we should only call setTargetFPS when framestate changes, because // but we should only call setTargetFPS when framestate changes, because
// otherwise that breaks animations. // otherwise that breaks animations.
@ -709,6 +761,7 @@ int32_t Screen::runOnce()
DEBUG_MSG("Setting idle framerate\n"); DEBUG_MSG("Setting idle framerate\n");
targetFramerate = IDLE_FRAMERATE; targetFramerate = IDLE_FRAMERATE;
ui.setTargetFPS(targetFramerate); ui.setTargetFPS(targetFramerate);
forceDisplay();
} }
// While showing the bootscreen or Bluetooth pair screen all of our // While showing the bootscreen or Bluetooth pair screen all of our
@ -717,8 +770,6 @@ int32_t Screen::runOnce()
// standard screen loop handling here // standard screen loop handling here
} }
ui.update();
// DEBUG_MSG("want fps %d, fixed=%d\n", targetFramerate, // DEBUG_MSG("want fps %d, fixed=%d\n", targetFramerate,
// ui.getUiState()->frameState); If we are scrolling we need to be called // ui.getUiState()->frameState); If we are scrolling we need to be called
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice // soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
@ -785,6 +836,8 @@ void Screen::setFrames()
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
// just changed) // just changed)
setFastFramerate(); // Draw ASAP
} }
void Screen::handleStartBluetoothPinScreen(uint32_t pin) void Screen::handleStartBluetoothPinScreen(uint32_t pin)
@ -794,16 +847,17 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
static FrameCallback btFrames[] = {drawFrameBluetooth}; static FrameCallback btFrames[] = {drawFrameBluetooth};
snprintf(btPIN, sizeof(btPIN), "%06u", pin); snprintf(btPIN, sizeof(btPIN), "%06lu", pin);
ui.disableAllIndicators(); ui.disableAllIndicators();
ui.setFrames(btFrames, 1); ui.setFrames(btFrames, 1);
setFastFramerate();
} }
void Screen::handlePrint(const char *text) void Screen::handlePrint(const char *text)
{ {
DEBUG_MSG("Screen: %s", text); DEBUG_MSG("Screen: %s", text);
if (!useDisplay) if (!useDisplay || !showingNormalScreen)
return; return;
dispdev.print(text); dispdev.print(text);
@ -814,22 +868,27 @@ void Screen::handleOnPress()
// If screen was off, just wake it, otherwise advance to next frame // If screen was off, just wake it, otherwise advance to next frame
// If we are in a transition, the press must have bounced, drop it. // If we are in a transition, the press must have bounced, drop it.
if (ui.getUiState()->frameState == FIXED) { if (ui.getUiState()->frameState == FIXED) {
setInterval(0); // redraw ASAP
ui.nextFrame(); ui.nextFrame();
DEBUG_MSG("Setting fast framerate\n"); setFastFramerate();
// We are about to start a transition so speed up fps
targetFramerate = TRANSITION_FRAMERATE;
ui.setTargetFPS(targetFramerate);
} }
} }
void Screen::setFastFramerate()
{
DEBUG_MSG("Setting fast framerate\n");
// We are about to start a transition so speed up fps
targetFramerate = TRANSITION_FRAMERATE;
ui.setTargetFPS(targetFramerate);
setInterval(0); // redraw ASAP
}
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
displayedNodeNum = 0; // Not currently showing a node pane displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
@ -851,13 +910,13 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus); drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
// Draw the channel name // Draw the channel name
display->drawString(x, y + FONT_HEIGHT, channelStr); display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
// Draw our hardware ID to assist with bluetooth pairing // Draw our hardware ID to assist with bluetooth pairing
display->drawFastImage(x + SCREEN_WIDTH - (10) - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT, 8, 8, imgInfo); display->drawFastImage(x + SCREEN_WIDTH - (10) - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT, ourId); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId);
// Draw any log messages // Draw any log messages
display->drawLogBuffer(x, y + (FONT_HEIGHT * 2)); display->drawLogBuffer(x, y + (FONT_HEIGHT_SMALL * 2));
/* Display a heartbeat pixel that blinks every time the frame is redrawn */ /* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS #ifdef SHOW_REDRAWS
@ -876,7 +935,7 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
displayedNodeNum = 0; // Not currently showing a node pane displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
@ -907,86 +966,86 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
if (WiFi.status() == WL_CONNECTED) { if (WiFi.status() == WL_CONNECTED) {
if (radioConfig.preferences.wifi_ap_mode) { if (radioConfig.preferences.wifi_ap_mode) {
display->drawString(x, y + FONT_HEIGHT * 1, "IP: " + String(WiFi.softAPIP().toString().c_str())); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str()));
} else { } else {
display->drawString(x, y + FONT_HEIGHT * 1, "IP: " + String(WiFi.localIP().toString().c_str())); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str()));
} }
} else if (WiFi.status() == WL_NO_SSID_AVAIL) { } else if (WiFi.status() == WL_NO_SSID_AVAIL) {
display->drawString(x, y + FONT_HEIGHT * 1, "SSID Not Found"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found");
} else if (WiFi.status() == WL_CONNECTION_LOST) { } else if (WiFi.status() == WL_CONNECTION_LOST) {
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Lost"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Lost");
} else if (WiFi.status() == WL_CONNECT_FAILED) { } else if (WiFi.status() == WL_CONNECT_FAILED) {
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Failed"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
//} else if (WiFi.status() == WL_DISCONNECTED) { //} else if (WiFi.status() == WL_DISCONNECTED) {
// display->drawString(x, y + FONT_HEIGHT * 1, "Disconnected"); // display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disconnected");
} else if (WiFi.status() == WL_IDLE_STATUS) { } else if (WiFi.status() == WL_IDLE_STATUS) {
display->drawString(x, y + FONT_HEIGHT * 1, "Idle ... Reconnecting"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting");
} else { } else {
// Codes: // Codes:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code
if (getWifiDisconnectReason() == 2) { if (getWifiDisconnectReason() == 2) {
display->drawString(x, y + FONT_HEIGHT * 1, "Authentication Invalid"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Authentication Invalid");
} else if (getWifiDisconnectReason() == 3) { } else if (getWifiDisconnectReason() == 3) {
display->drawString(x, y + FONT_HEIGHT * 1, "De-authenticated"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "De-authenticated");
} else if (getWifiDisconnectReason() == 4) { } else if (getWifiDisconnectReason() == 4) {
display->drawString(x, y + FONT_HEIGHT * 1, "Disassociated Expired"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disassociated Expired");
} else if (getWifiDisconnectReason() == 5) { } else if (getWifiDisconnectReason() == 5) {
display->drawString(x, y + FONT_HEIGHT * 1, "AP - Too Many Clients"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP - Too Many Clients");
} else if (getWifiDisconnectReason() == 6) { } else if (getWifiDisconnectReason() == 6) {
display->drawString(x, y + FONT_HEIGHT * 1, "NOT_AUTHED"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "NOT_AUTHED");
} else if (getWifiDisconnectReason() == 7) { } else if (getWifiDisconnectReason() == 7) {
display->drawString(x, y + FONT_HEIGHT * 1, "NOT_ASSOCED"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "NOT_ASSOCED");
} else if (getWifiDisconnectReason() == 8) { } else if (getWifiDisconnectReason() == 8) {
display->drawString(x, y + FONT_HEIGHT * 1, "Disassociated"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disassociated");
} else if (getWifiDisconnectReason() == 9) { } else if (getWifiDisconnectReason() == 9) {
display->drawString(x, y + FONT_HEIGHT * 1, "ASSOC_NOT_AUTHED"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "ASSOC_NOT_AUTHED");
} else if (getWifiDisconnectReason() == 10) { } else if (getWifiDisconnectReason() == 10) {
display->drawString(x, y + FONT_HEIGHT * 1, "DISASSOC_PWRCAP_BAD"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "DISASSOC_PWRCAP_BAD");
} else if (getWifiDisconnectReason() == 11) { } else if (getWifiDisconnectReason() == 11) {
display->drawString(x, y + FONT_HEIGHT * 1, "DISASSOC_SUPCHAN_BAD"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "DISASSOC_SUPCHAN_BAD");
} else if (getWifiDisconnectReason() == 13) { } else if (getWifiDisconnectReason() == 13) {
display->drawString(x, y + FONT_HEIGHT * 1, "IE_INVALID"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IE_INVALID");
} else if (getWifiDisconnectReason() == 14) { } else if (getWifiDisconnectReason() == 14) {
display->drawString(x, y + FONT_HEIGHT * 1, "MIC_FAILURE"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "MIC_FAILURE");
} else if (getWifiDisconnectReason() == 15) { } else if (getWifiDisconnectReason() == 15) {
display->drawString(x, y + FONT_HEIGHT * 1, "AP Handshake Timeout"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP Handshake Timeout");
} else if (getWifiDisconnectReason() == 16) { } else if (getWifiDisconnectReason() == 16) {
display->drawString(x, y + FONT_HEIGHT * 1, "GROUP_KEY_UPDATE_TIMEOUT"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "GROUP_KEY_UPDATE_TIMEOUT");
} else if (getWifiDisconnectReason() == 17) { } else if (getWifiDisconnectReason() == 17) {
display->drawString(x, y + FONT_HEIGHT * 1, "IE_IN_4WAY_DIFFERS"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IE_IN_4WAY_DIFFERS");
} else if (getWifiDisconnectReason() == 18) { } else if (getWifiDisconnectReason() == 18) {
display->drawString(x, y + FONT_HEIGHT * 1, "Invalid Group Cipher"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Invalid Group Cipher");
} else if (getWifiDisconnectReason() == 19) { } else if (getWifiDisconnectReason() == 19) {
display->drawString(x, y + FONT_HEIGHT * 1, "Invalid Pairwise Cipher"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Invalid Pairwise Cipher");
} else if (getWifiDisconnectReason() == 20) { } else if (getWifiDisconnectReason() == 20) {
display->drawString(x, y + FONT_HEIGHT * 1, "AKMP_INVALID"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AKMP_INVALID");
} else if (getWifiDisconnectReason() == 21) { } else if (getWifiDisconnectReason() == 21) {
display->drawString(x, y + FONT_HEIGHT * 1, "UNSUPP_RSN_IE_VERSION"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "UNSUPP_RSN_IE_VERSION");
} else if (getWifiDisconnectReason() == 22) { } else if (getWifiDisconnectReason() == 22) {
display->drawString(x, y + FONT_HEIGHT * 1, "INVALID_RSN_IE_CAP"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "INVALID_RSN_IE_CAP");
} else if (getWifiDisconnectReason() == 23) { } else if (getWifiDisconnectReason() == 23) {
display->drawString(x, y + FONT_HEIGHT * 1, "802_1X_AUTH_FAILED"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "802_1X_AUTH_FAILED");
} else if (getWifiDisconnectReason() == 24) { } else if (getWifiDisconnectReason() == 24) {
display->drawString(x, y + FONT_HEIGHT * 1, "CIPHER_SUITE_REJECTED"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "CIPHER_SUITE_REJECTED");
} else if (getWifiDisconnectReason() == 200) { } else if (getWifiDisconnectReason() == 200) {
display->drawString(x, y + FONT_HEIGHT * 1, "BEACON_TIMEOUT"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "BEACON_TIMEOUT");
} else if (getWifiDisconnectReason() == 201) { } else if (getWifiDisconnectReason() == 201) {
display->drawString(x, y + FONT_HEIGHT * 1, "AP Not Found"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP Not Found");
} else if (getWifiDisconnectReason() == 202) { } else if (getWifiDisconnectReason() == 202) {
display->drawString(x, y + FONT_HEIGHT * 1, "AUTH_FAIL"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AUTH_FAIL");
} else if (getWifiDisconnectReason() == 203) { } else if (getWifiDisconnectReason() == 203) {
display->drawString(x, y + FONT_HEIGHT * 1, "ASSOC_FAIL"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "ASSOC_FAIL");
} else if (getWifiDisconnectReason() == 204) { } else if (getWifiDisconnectReason() == 204) {
display->drawString(x, y + FONT_HEIGHT * 1, "HANDSHAKE_TIMEOUT"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "HANDSHAKE_TIMEOUT");
} else if (getWifiDisconnectReason() == 205) { } else if (getWifiDisconnectReason() == 205) {
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Failed"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
} else { } else {
display->drawString(x, y + FONT_HEIGHT * 1, "Unknown Status"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Unknown Status");
} }
} }
display->drawString(x, y + FONT_HEIGHT * 2, "SSID: " + String(wifiName)); display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
display->drawString(x, y + FONT_HEIGHT * 3, "PWD: " + String(wifiPsw)); display->drawString(x, y + FONT_HEIGHT_SMALL * 3, "PWD: " + String(wifiPsw));
/* Display a heartbeat pixel that blinks every time the frame is redrawn */ /* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS #ifdef SHOW_REDRAWS
@ -1001,7 +1060,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
{ {
displayedNodeNum = 0; // Not currently showing a node pane displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
@ -1035,15 +1094,15 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
minutes %= 60; minutes %= 60;
hours %= 24; hours %= 24;
display->drawString(x, y + FONT_HEIGHT * 1, display->drawString(x, y + FONT_HEIGHT_SMALL * 1,
String(days) + "d " + (hours < 10 ? "0" : "") + String(hours) + ":" + (minutes < 10 ? "0" : "") + String(days) + "d " + (hours < 10 ? "0" : "") + String(hours) + ":" + (minutes < 10 ? "0" : "") +
String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds)); String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds));
// Line 3 // Line 3
drawGPSAltitude(display, x, y + FONT_HEIGHT * 2, gpsStatus); drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
// Line 4 // Line 4
drawGPScoordinates(display, x, y + FONT_HEIGHT * 3, gpsStatus); drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
/* Display a heartbeat pixel that blinks every time the frame is redrawn */ /* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS #ifdef SHOW_REDRAWS
@ -1073,9 +1132,7 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
switch (arg->getStatusType()) { switch (arg->getStatusType()) {
case STATUS_TYPE_NODE: case STATUS_TYPE_NODE:
if (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) { if (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
setFrames(); // Regen the list of screens setFrames(); // Regen the list of screens
prevFrame = -1; // Force a GUI update
setInterval(0); // Update the screen right away
} }
nodeDB.updateGUI = false; nodeDB.updateGUI = false;
nodeDB.updateTextMessage = false; nodeDB.updateTextMessage = false;

View File

@ -180,6 +180,9 @@ class Screen : public concurrency::OSThread
int handleStatusUpdate(const meshtastic::Status *arg); int handleStatusUpdate(const meshtastic::Status *arg);
/// Used to force (super slow) eink displays to draw critical frames
void forceDisplay();
protected: protected:
/// Updates the UI. /// Updates the UI.
// //
@ -216,6 +219,9 @@ class Screen : public concurrency::OSThread
/// Rebuilds our list of frames (screens) to default ones. /// Rebuilds our list of frames (screens) to default ones.
void setFrames(); void setFrames();
/// Try to start drawing ASAP
void setFastFramerate();
/// Called when debug screen is to be drawn, calls through to debugInfo.drawFrame. /// Called when debug screen is to be drawn, calls through to debugInfo.drawFrame.
static void drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); static void drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);

View File

@ -11,8 +11,7 @@ static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl) TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl)
{ {
setGeometry(GEOMETRY_128_64); // FIXME - currently we lie and claim 128x64 because I'm not yet sure other resolutions will setGeometry(GEOMETRY_RAWMODE, 160, 80);
// work ie GEOMETRY_RAWMODE
} }
// Write the buffer to the display memory // Write the buffer to the display memory
@ -22,11 +21,11 @@ void TFTDisplay::display(void)
// FIXME - only draw bits have changed (use backbuf similar to the other displays) // FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK); // tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) { for (uint8_t y = 0; y < displayHeight; y++) {
for (uint8_t x = 0; x < SCREEN_WIDTH; x++) { for (uint8_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent // get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto b = buffer[x + (y / 8) * SCREEN_WIDTH]; auto b = buffer[x + (y / 8) * displayWidth];
auto isset = b & (1 << (y & 7)); auto isset = b & (1 << (y & 7));
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK); tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
} }

View File

@ -2,11 +2,7 @@
#include "fonts.h" #include "fonts.h"
#define FONT_HEIGHT 14 // actually 13 for "Arial 10" but want a little extra space
#define FONT_HEIGHT_16 (ArialMT_Plain_16[1] + 1)
// This means the *visible* area (sh1106 can address 132, but shows 128 for example) // This means the *visible* area (sh1106 can address 132, but shows 128 for example)
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define TRANSITION_FRAMERATE 30 // fps #define TRANSITION_FRAMERATE 30 // fps
#define IDLE_FRAMERATE 1 // in fps #define IDLE_FRAMERATE 1 // in fps
#define COMPASS_DIAM 44 #define COMPASS_DIAM 44

View File

@ -147,6 +147,7 @@ bool NodeDB::resetRadioConfig()
radioConfig.preferences.wait_bluetooth_secs = 30; radioConfig.preferences.wait_bluetooth_secs = 30;
radioConfig.preferences.position_broadcast_secs = 6 * 60; radioConfig.preferences.position_broadcast_secs = 6 * 60;
radioConfig.preferences.ls_secs = 60; radioConfig.preferences.ls_secs = 60;
radioConfig.preferences.region = RegionCode_TW;
} }
return didFactoryReset; return didFactoryReset;

View File

@ -239,7 +239,7 @@ External serial flash WP25R1635FZUIL0
#define PIN_SPI_SCK (0 + 19) #define PIN_SPI_SCK (0 + 19)
// To debug via the segger JLINK console rather than the CDC-ACM serial device // To debug via the segger JLINK console rather than the CDC-ACM serial device
#define USE_SEGGER // #define USE_SEGGER
#ifdef __cplusplus #ifdef __cplusplus
} }