Skip to content

Commit

Permalink
Merge pull request #19 from meshtastic/master
Browse files Browse the repository at this point in the history
update my branch from master
  • Loading branch information
mc-hamster authored Oct 17, 2020
2 parents 0d9481b + cff21ca commit 3262f73
Show file tree
Hide file tree
Showing 13 changed files with 257 additions and 135 deletions.
22 changes: 22 additions & 0 deletions bin/install-eink.sh
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions docs/software/nrf52-TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

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
- get nrf52832 working again (currently OOM)
- i2c gps comms not quite right
Expand Down
2 changes: 1 addition & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ board_build.partitions = partition-table.csv
extends = esp32_base
board = ttgo-t-beam
lib_deps =
${arduino_base.lib_deps}
${esp32_base.lib_deps}
build_flags =
${esp32_base.build_flags} -D TBEAM_V10

Expand Down
14 changes: 10 additions & 4 deletions src/PowerFSM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,20 +245,26 @@ void PowerFSM_setup()

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
// 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(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
#endif

auto meshSds = getPref_mesh_sds_timeout_secs();
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
// 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");

powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state
Expand Down
46 changes: 23 additions & 23 deletions src/gps/NMEAGPS.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "NMEAGPS.h"
#include "configuration.h"
#include "RTC.h"
#include "configuration.h"

static int32_t toDegInt(RawDegrees d)
{
Expand Down Expand Up @@ -32,7 +32,7 @@ bool NMEAGPS::lookForTime()
{
auto ti = reader.time;
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
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).
Expand Down Expand Up @@ -65,27 +65,27 @@ bool NMEAGPS::lookForLocation()
// uint8_t fixtype = reader.fixQuality();
// 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.altitude.isValid())
altitude = reader.altitude.meters();

if (reader.location.isValid()) {
auto loc = reader.location.value();
latitude = toDegInt(loc.lat);
longitude = toDegInt(loc.lng);
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());
}

auto loc = reader.location.value();
latitude = toDegInt(loc.lat);
longitude = toDegInt(loc.lng);
foundLocation = true;

// 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,
Expand All @@ -102,7 +102,7 @@ bool NMEAGPS::whileIdle()
// First consume any chars that have piled up at the receiver
while (_serial_gps->available() > 0) {
int c = _serial_gps->read();
// DEBUG_MSG("%c", c);
//DEBUG_MSG("%c", c);
isValid |= reader.encode(c);
}

Expand Down
35 changes: 26 additions & 9 deletions src/graphics/EInkDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,32 +46,35 @@ void updateDisplay(uint8_t *blackFrame = framePtr)

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
// work ie GEOMETRY_RAWMODE
setGeometry(GEOMETRY_RAWMODE, EPD_WIDTH, EPD_HEIGHT);
// 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
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
// concurrency::LockGuard g(spiLock);

uint32_t now = millis();
uint32_t sinceLast = now - lastDrawMsec;

if (framePtr && (sinceLast > 60 * 1000 || lastDrawMsec == 0)) {
if (framePtr && (sinceLast > msecLimit || lastDrawMsec == 0)) {
lastDrawMsec = now;

// FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) {
for (uint8_t x = 0; x < SCREEN_WIDTH; x++) {
for (uint8_t y = 0; y < displayHeight; y++) {
for (uint8_t x = 0; x < displayWidth; x++) {

// 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));
frame.drawPixel(x, y, isset ? INK : PAPER);
}
Expand All @@ -83,11 +86,25 @@ void EInkDisplay::display(void)
updateDisplay(); // Send image to display and refresh
DEBUG_MSG("done\n");

// Put screen to sleep to save power
// Put screen to sleep to save power
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)
void EInkDisplay::sendCommand(uint8_t com)
{
Expand Down
15 changes: 14 additions & 1 deletion src/graphics/EInkDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,26 @@
*/
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:
/* constructor
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);

// 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);

/**
* 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:
// the header size of the buffer used, e.g. for the SPI command header
virtual int getBufferOffset(void) { return 0; }
Expand All @@ -33,3 +44,5 @@ class EInkDisplay : public OLEDDisplay
// Connect to the display
virtual bool connect();
};


Loading

0 comments on commit 3262f73

Please sign in to comment.