mirror of
https://github.com/meshtastic/firmware.git
synced 2025-07-31 19:05:44 +00:00
Merge branch 'dev' into ppr1
# Conflicts: # src/gps/NMEAGPS.cpp
This commit is contained in:
commit
22f23bb07d
22
bin/install-eink.sh
Executable file
22
bin/install-eink.sh
Executable 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
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user