diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 8d76cfdac..18ecb22ed 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -34,9 +34,8 @@ jobs: - board: heltec-v2.1 - board: tbeam0.7 - board: meshtastic-diy-v1 - - board: rak4631_5005 - - board: rak4631_19003 - - board: rak4631_5005_eink + - board: rak4631 + - board: rak4631_eink - board: t-echo runs-on: ubuntu-latest @@ -117,7 +116,8 @@ jobs: - name: Upgrade python tools run: | python -m pip install --upgrade pip - pip install -U platformio meshtastic adafruit-nrfutil littlefs-python + pip install -U platformio adafruit-nrfutil littlefs-python + pip install -U --pre meshtastic - name: Upgrade platformio run: | @@ -158,9 +158,8 @@ jobs: max-parallel: 2 matrix: include: - - board: rak4631_5005 - - board: rak4631_19003 - - board: rak4631_5005_eink + - board: rak4631 + - board: rak4631_eink - board: t-echo - board: pca10059_diy_eink @@ -188,7 +187,8 @@ jobs: - name: Upgrade python tools run: | python -m pip install --upgrade pip - pip install -U platformio meshtastic adafruit-nrfutil + pip install -U platformio adafruit-nrfutil + pip install -U --pre meshtastic - name: Upgrade platformio run: | @@ -235,7 +235,8 @@ jobs: - name: Upgrade python tools run: | python -m pip install --upgrade pip - pip install -U platformio meshtastic adafruit-nrfutil + pip install -U platformio adafruit-nrfutil + pip install -U --pre meshtastic - name: Upgrade platformio run: | diff --git a/.gitmodules b/.gitmodules index 4f9bb6b77..59efcedd3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "proto"] path = proto url = https://github.com/meshtastic/Meshtastic-protobufs.git -[submodule "sdk-nrfxlib"] - path = sdk-nrfxlib - url = https://github.com/nrfconnect/sdk-nrfxlib.git [submodule "design"] path = design url = https://github.com/meshtastic/meshtastic-design.git diff --git a/README.md b/README.md index 43b357fd3..4876607e4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Meshtastic-device [![Open in Visual Studio Code](https://open.vscode.dev/badges/open-in-vscode.svg)](https://open.vscode.dev/meshtastic/Meshtastic-device) -[![Continuous Integration](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml/badge.svg)](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml) +[![Continuous Integration](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main_matrix.yml/badge.svg)](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main_matrix.yml) ![GitHub all releases](https://img.shields.io/github/downloads/meshtastic/meshtastic-device/total) [![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/Meshtastic-device)](https://cla-assistant.io/meshtastic/Meshtastic-device) [![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg)](https://opencollective.com/meshtastic/) diff --git a/bin/build-all.sh b/bin/build-all.sh index a92a04745..6ab69d3ef 100755 --- a/bin/build-all.sh +++ b/bin/build-all.sh @@ -9,7 +9,7 @@ BOARDS_ESP32="rak11200 tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec- #BOARDS_ESP32=tbeam # FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine -BOARDS_NRF52="rak4631_5005 rak4631_5005_eink rak4631_19003 t-echo pca10059_diy_eink" +BOARDS_NRF52="rak4631 rak4631_eink t-echo pca10059_diy_eink" #BOARDS_NRF52="" OUTDIR=release/latest diff --git a/bin/check-all.sh b/bin/check-all.sh index f18f87f15..e6db5b959 100755 --- a/bin/check-all.sh +++ b/bin/check-all.sh @@ -13,7 +13,7 @@ if [[ $# -gt 0 ]]; then # can override which environment by passing arg BOARDS="$@" else - BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631_5005 rak4631_19003 rak11200 t-echo pca10059_diy_eink" + BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631 rak4631_eink rak11200 t-echo pca10059_diy_eink" fi echo "BOARDS:${BOARDS}" diff --git a/boards/rak815.json b/boards/rak815.json deleted file mode 100644 index 5411362af..000000000 --- a/boards/rak815.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "build": { - "arduino":{ - "ldscript": "nrf52832_s132_v6.ld" - }, - "core": "nRF5", - "cpu": "cortex-m4", - "extra_flags": "-DNRF52832_XXAA -DNRF52", - "f_cpu": "64000000L", - "hwids": [ - [ - "0x10c4", - "0xea60" - ] - ], - "usb_product": "RAK815", - "mcu": "nrf52832", - "variant": "rak815", - "bsp": { - "name": "adafruit" - }, - "softdevice": { - "sd_flags": "-DS132", - "sd_name": "s132", - "sd_version": "6.1.1", - "sd_fwid": "0x00B7" - } - }, - "connectivity": [ - "bluetooth" - ], - "debug": { - "jlink_device": "nRF52832_xxAA", - "svd_path": "nrf52.svd" - }, - "frameworks": [ - "arduino" - ], - "name": "RAK RAK815", - "upload": { - "maximum_ram_size": 65536, - "maximum_size": 524288, - "require_upload_port": true, - "speed": 115200, - "protocol": "nrfutil", - "protocols": [ - "jlink", - "nrfjprog", - "nrfutil", - "stlink" - ] - }, - "url": "https://store.rakwireless.com/products/rak815-hybrid-location-tracker", - "vendor": "RAK" -} diff --git a/platformio.ini b/platformio.ini index 67c6ae9b3..bb051e5e2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,9 +16,6 @@ default_envs = tbeam ;default_envs = t-echo ;default_envs = nrf52840dk-geeksville ;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here -;default_envs = rak4631_5005 -;default_envs = rak4631_5005_eink -;default_envs = rak4631_19003 ;default_envs = nano-g1 ;default_envs = pca10059_diy_eink ;default_envs = meshtastic-diy-v1 @@ -84,7 +81,7 @@ lib_deps = ; Common settings for ESP targes, mixin with extends = esp32_base [esp32_base] extends = arduino_base -platform = espressif32 +platform = espressif32@3.5.0 src_filter = ${arduino_base.src_filter} - upload_speed = 921600 @@ -132,8 +129,7 @@ build_type = debug ; I'm debugging with ICE a lot now ; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME) build_flags = ${arduino_base.build_flags} -Wno-unused-variable - -Isrc/nrf52 - -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7 + -Isrc/nrf52 src_filter = ${arduino_base.src_filter} - - - - - - lib_ignore = @@ -145,7 +141,7 @@ build_flags = ${nrf52_base.build_flags} lib_deps = ${arduino_base.lib_deps} ${environmental.lib_deps} - Adafruit nRFCrypto + https://github.com/Kongduino/Adafruit_nRFCrypto.git ; Note: By default no lora device is created for this build - it uses a simulated interface [env:nrf52840dk] @@ -156,10 +152,3 @@ board = nrf52840_dk [env:feather_nrf52832] extends = nrf52_base board = adafruit_feather_nrf52832 - -[env:rak815] -extends = nrf52_base -board = rak815 -debug_tool = jlink -upload_protocol = jlink -monitor_speed = 115200 diff --git a/sdk-nrfxlib b/sdk-nrfxlib deleted file mode 160000 index e6e02cb83..000000000 --- a/sdk-nrfxlib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e6e02cb83d238fae2f54f084858bd5e49a31afa1 diff --git a/src/debug/einkScan.h b/src/debug/einkScan.h new file mode 100644 index 000000000..a2509a45a --- /dev/null +++ b/src/debug/einkScan.h @@ -0,0 +1,60 @@ +#include "../configuration.h" + +#ifdef RAK4630 +#include "../main.h" +#include + +void d_writeCommand(uint8_t c) +{ + SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); + if (PIN_EINK_DC >= 0) digitalWrite(PIN_EINK_DC, LOW); + if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, LOW); + SPI1.transfer(c); + if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, HIGH); + if (PIN_EINK_DC >= 0) digitalWrite(PIN_EINK_DC, HIGH); + SPI1.endTransaction(); +} + +void d_writeData(uint8_t d) +{ + SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); + if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, LOW); + SPI1.transfer(d); + if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, HIGH); + SPI1.endTransaction(); +} + +unsigned long d_waitWhileBusy(uint16_t busy_time) +{ + if (PIN_EINK_BUSY >= 0) + { + delay(1); // add some margin to become active + unsigned long start = micros(); + while (1) + { + if (digitalRead(PIN_EINK_BUSY) != HIGH) break; + delay(1); + if (digitalRead(PIN_EINK_BUSY) != HIGH) break; + if (micros() - start > 10000000) break; + } + unsigned long elapsed = micros() - start; + (void) start; + return elapsed; + } + else return busy_time; +} + +void scanEInkDevice(void) +{ + SPI1.begin(); + d_writeCommand(0x22); + d_writeData(0x83); + d_writeCommand(0x20); + eink_found = (d_waitWhileBusy(150) > 0) ? true : false; + if(eink_found) + DEBUG_MSG("EInk display found\n"); + else + DEBUG_MSG("EInk display not found\n"); + SPI1.end(); +} +#endif diff --git a/src/debug/i2cScan.h b/src/debug/i2cScan.h index 9e7a49a62..4279a5122 100644 --- a/src/debug/i2cScan.h +++ b/src/debug/i2cScan.h @@ -54,6 +54,7 @@ void scanI2Cdevice(void) DEBUG_MSG("unknown display found\n"); } } + if (addr == CARDKB_ADDR) { cardkb_found = addr; DEBUG_MSG("m5 cardKB found\n"); diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index aa92d96c8..57647472c 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -16,12 +16,6 @@ HardwareSerial *GPS::_serial_gps = &Serial1; HardwareSerial *GPS::_serial_gps = NULL; #endif -#ifdef GPS_I2C_ADDRESS -uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS; -#else -uint8_t GPS::i2cAddress = 0; -#endif - GPS *gps; /// Multiple GPS instances might use the same serial port (in sequence), but we can @@ -325,10 +319,6 @@ int GPS::prepareDeepSleep(void *unused) return 0; } -#ifdef GPS_TX_PIN -#include "UBloxGPS.h" -#endif - #ifndef NO_GPS #include "NMEAGPS.h" #endif @@ -345,25 +335,9 @@ GPS *createGps() #else DEBUG_MSG("Using MSL altitude model\n"); #endif -// If we don't have bidirectional comms, we can't even try talking to UBLOX -#ifdef GPS_TX_PIN - // Init GPS - first try ublox - UBloxGPS *ublox = new UBloxGPS(); - - if (!ublox->setup()) { - DEBUG_MSG("ERROR: No UBLOX GPS found\n"); - delete ublox; - ublox = NULL; - } else { - DEBUG_MSG("Using UBLOX Mode\n"); - return ublox; - } -#endif - if (GPS::_serial_gps) { // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just // assume NMEA at 9600 baud. - DEBUG_MSG("Using NMEA Mode\n"); GPS *new_gps = new NMEAGPS(); new_gps->setup(); return new_gps; diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 8d4833590..999f88bfa 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -40,9 +40,6 @@ class GPS : private concurrency::OSThread /** If !NULL we will use this serial port to construct our GPS */ static HardwareSerial *_serial_gps; - /** If !0 we will attempt to connect to the GPS over I2C */ - static uint8_t i2cAddress; - Position p = Position_init_default; GPS() : concurrency::OSThread("GPS") {} diff --git a/src/gps/NMEAGPS.cpp b/src/gps/NMEAGPS.cpp index 5c1ebafa0..73031139a 100644 --- a/src/gps/NMEAGPS.cpp +++ b/src/gps/NMEAGPS.cpp @@ -64,11 +64,12 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s t.tm_mon = d.month() - 1; t.tm_year = d.year() - 1900; t.tm_isdst = false; - DEBUG_MSG("NMEA GPS time %d-%d-%d %d:%d:%d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); - - perhapsSetRTC(RTCQualityGPS, t); - - return true; + if (t.tm_mon > -1){ + DEBUG_MSG("NMEA GPS time %d-%d-%d %d:%d:%d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); + perhapsSetRTC(RTCQualityGPS, t); + return true; + } else + return false; } else return false; } @@ -128,8 +129,10 @@ bool NMEAGPS::lookForLocation() auto loc = reader.location.value(); // Bail out EARLY to avoid overwriting previous good data (like #857) - if(toDegInt(loc.lat) == 0) { - DEBUG_MSG("Ignoring bogus NMEA position\n"); + if((toDegInt(loc.lat) == 0) || (toDegInt(loc.lat) > 90)) { + return false; + } + if((toDegInt(loc.lng) == 0) || (toDegInt(loc.lng) > 180)) { return false; } diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp deleted file mode 100644 index 70fc91ecd..000000000 --- a/src/gps/UBloxGPS.cpp +++ /dev/null @@ -1,328 +0,0 @@ -#include "configuration.h" -#include "UBloxGPS.h" -#include "RTC.h" -#include "error.h" -#include "sleep.h" -#include - -// if gps_update_interval below this value, do not powercycle the GPS -#define UBLOX_POWEROFF_THRESHOLD 90 - -#define PDOP_INVALID 9999 - -// #define UBX_MODE_NMEA - -extern RadioConfig radioConfig; - -UBloxGPS::UBloxGPS() {} - -bool UBloxGPS::tryConnect() -{ - bool c = false; - - if (_serial_gps) - c = ublox.begin(*_serial_gps); - - if (!c && i2cAddress) { - extern bool neo6M; // Super skanky - if we are talking to the device i2c we assume it is a neo7 on a RAK815, which - // supports the newer API - neo6M = true; - - c = ublox.begin(Wire, i2cAddress); - } - - if (c) - setConnected(); - - return c; -} - -bool UBloxGPS::setupGPS() -{ - GPS::setupGPS(); - - // uncomment to see debug info - // ublox.enableDebugging(Serial); - - // try a second time, the ublox lib serial parsing is buggy? - // see https://github.com/meshtastic/Meshtastic-device/issues/376 - for (int i = 0; (i < 3) && !tryConnect(); i++) - delay(500); - - if (isConnected()) { -#ifdef UBX_MODE_NMEA - DEBUG_MSG("Connected to UBLOX GPS, downgrading to NMEA mode\n"); - DEBUG_MSG("- GPS errors below are related and safe to ignore\n"); -#else - DEBUG_MSG("Connected to UBLOX GPS successfully\n"); -#endif - - if (!setUBXMode()) - RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug - -#ifdef UBX_MODE_NMEA - return false; -#else - return true; -#endif - - } else { - return false; - } -} - -bool UBloxGPS::setUBXMode() -{ -#ifdef UBX_MODE_NMEA - if (_serial_gps) { - ublox.setUART1Output(COM_TYPE_NMEA, 1000); - } - if (i2cAddress) { - ublox.setI2COutput(COM_TYPE_NMEA, 1000); - } - - return false; // pretend initialization failed to force NMEA mode -#endif - - if (_serial_gps) { - if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API - return false; - } - if (i2cAddress) { - if (!ublox.setI2COutput(COM_TYPE_UBX, 1000)) - return false; - } - - if (!ublox.setNavigationFrequency(1, 1000)) // Produce 4x/sec to keep the amount of time we stall in getPVT low - return false; - - // ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M - // assert(ok); - // ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds - // assert(ok); - - // per https://github.com/meshtastic/Meshtastic-device/issues/376 powerSaveMode might not work with the marginal - // TTGO antennas - // if (!ublox.powerSaveMode(true, 2000)) // use power save mode, the default timeout (1100ms seems a bit too tight) - // return false; - - if (!ublox.saveConfiguration(3000)) - return false; - - return true; -} - -/** - * Reset our GPS back to factory settings - * - * @return true for success - */ -bool UBloxGPS::factoryReset() -{ - bool ok = false; - - // It is useful to force back into factory defaults (9600baud, NMEA to test the behavior of boards that don't have - // GPS_TX connected) - ublox.factoryReset(); - delay(5000); - tryConnect(); // sets isConnected - - // try a second time, the ublox lib serial parsing is buggy? - for (int i = 0; (i < 3) && !tryConnect(); i++) - delay(500); - - DEBUG_MSG("GPS Factory reset success=%d\n", isConnected()); - if (isConnected()) - ok = setUBXMode(); - - return ok; -} - -/** Idle processing while GPS is looking for lock */ -void UBloxGPS::whileActive() -{ - ublox.flushPVT(); // reset ALL freshness flags first - ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back - - // Ask for a new position fix - hopefully it will have results ready by next time - // the order here is important, because we only check for has latitude when reading - - //ublox.getSIV(maxWait()); // redundant with getPDOP below - ublox.getPDOP(maxWait()); // will trigger getSOL on NEO6, getP on others - ublox.getP(maxWait()); // will trigger getPosLLH on NEO6, getP on others - - // the fixType flag will be checked and updated in lookForLocation() -} - -/** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a new location - */ -bool UBloxGPS::lookForTime() -{ - if (ublox.moduleQueried.gpsSecond) { - /* 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). - */ - struct tm t; - t.tm_sec = ublox.getSecond(0); - t.tm_min = ublox.getMinute(0); - t.tm_hour = ublox.getHour(0); - t.tm_mday = ublox.getDay(0); - t.tm_mon = ublox.getMonth(0) - 1; - t.tm_year = ublox.getYear(0) - 1900; - t.tm_isdst = false; - perhapsSetRTC(RTCQualityGPS, t); - return true; - } - - return false; -} - -/** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a new location - */ -bool UBloxGPS::lookForLocation() -{ - bool foundLocation = false; - - // check if a complete GPS solution set is available for reading - // (some of these, like lat/lon are redundant and can be removed) - if ( ! (ublox.moduleQueried.fixType && - ublox.moduleQueried.latitude && - ublox.moduleQueried.longitude && - ublox.moduleQueried.altitude && - ublox.moduleQueried.pDOP && - ublox.moduleQueried.SIV && - ublox.moduleQueried.gpsDay)) - { - // Not ready? No problem! We'll try again later. - return false; - } - - fixType = ublox.getFixType(); -#ifdef UBLOX_EXTRAVERBOSE - DEBUG_MSG("FixType=%d\n", fixType); -#endif - - - // check if GPS has an acceptable lock - if (! hasLock()) { - ublox.flushPVT(); // reset ALL freshness flags - return false; - } - - // read lat/lon/alt/dop data into temporary variables to avoid - // overwriting global variables with potentially invalid data - int32_t tmp_dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it - int32_t tmp_lat = ublox.getLatitude(0); - int32_t tmp_lon = ublox.getLongitude(0); - int32_t tmp_alt_msl = ublox.getAltitudeMSL(0); - int32_t tmp_alt_hae = ublox.getAltitude(0); - int32_t max_dop = PDOP_INVALID; - if (radioConfig.preferences.gps_max_dop) - max_dop = radioConfig.preferences.gps_max_dop * 100; // scaling - - // Note: heading is only currently implmented in the ublox for the 8m chipset - therefore - // don't read it here - it will generate an ignored getPVT command on the 6ms - // heading = ublox.getHeading(0); - - // read positional timestamp - struct tm t; - t.tm_sec = ublox.getSecond(0); - t.tm_min = ublox.getMinute(0); - t.tm_hour = ublox.getHour(0); - t.tm_mday = ublox.getDay(0); - t.tm_mon = ublox.getMonth(0) - 1; - t.tm_year = ublox.getYear(0) - 1900; - t.tm_isdst = false; - - time_t tmp_ts = mktime(&t); - - // FIXME - can opportunistically attempt to set RTC from GPS timestamp? - - // bogus lat lon is reported as 0 or 0 (can be bogus just for one) - // Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg! - // FIXME - NULL ISLAND is a real location on Earth! - foundLocation = (tmp_lat != 0) && (tmp_lon != 0) && - (tmp_lat <= 900000000) && (tmp_lat >= -900000000) && - (tmp_dop < max_dop); - - // only if entire dataset is valid, update globals from temp vars - if (foundLocation) { - p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL; - p.longitude_i = tmp_lon; - p.latitude_i = tmp_lat; - if (fixType > 2) { - // if fix is 2d, ignore altitude data - p.altitude = tmp_alt_msl / 1000; - p.altitude_hae = tmp_alt_hae / 1000; - p.alt_geoid_sep = (tmp_alt_hae - tmp_alt_msl) / 1000; - } else { -#ifdef GPS_EXTRAVERBOSE - DEBUG_MSG("no altitude data (fixType=%d)\n", fixType); -#endif - // clean up old values in case it's a 3d-2d fix transition - p.altitude = p.altitude_hae = p.alt_geoid_sep = 0; - } - p.pos_timestamp = tmp_ts; - p.PDOP = tmp_dop; - p.fix_type = fixType; - p.sats_in_view = ublox.getSIV(0); - // In debug logs, identify position by @timestamp:stage (stage 1 = birth) - DEBUG_MSG("lookForLocation() new pos@%x:1\n", tmp_ts); - } else { - // INVALID solution - should never happen - DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n", - tmp_lat, tmp_lon, tmp_alt_hae, tmp_dop); - } - - ublox.flushPVT(); // reset ALL freshness flags at the end - - return foundLocation; -} - -bool UBloxGPS::hasLock() -{ - if (radioConfig.preferences.gps_accept_2d) - return (fixType >= 2 && fixType <= 4); - else - return (fixType >= 3 && fixType <= 4); -} - -bool UBloxGPS::whileIdle() -{ - // if using i2c or serial look too see if any chars are ready - return ublox.checkUblox(); // See if new data is available. Process bytes as they come in. -} - -/// If possible force the GPS into sleep/low power mode -/// Note: ublox doesn't need a wake method, because as soon as we send chars to the GPS it will wake up -void UBloxGPS::sleep() -{ - if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) { - // Tell GPS to power down until we send it characters on serial port (we leave vcc connected) - ublox.powerOff(); - // setGPSPower(false); - } -} - -void UBloxGPS::wake() -{ - if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) { - fixType = 0; // assume we have no fix yet - } - - // this is idempotent - setGPSPower(true); - - // Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff() - // Give time for the GPS to boot - // delay(200); -} \ No newline at end of file diff --git a/src/gps/UBloxGPS.h b/src/gps/UBloxGPS.h deleted file mode 100644 index 3d940832f..000000000 --- a/src/gps/UBloxGPS.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include "GPS.h" -#include "Observer.h" -#include "SparkFun_Ublox_Arduino_Library.h" - -/** - * A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading) - * - * When new data is available it will notify observers. - */ -class UBloxGPS : public GPS -{ - SFE_UBLOX_GPS ublox; - uint8_t fixType = 0; - - public: - UBloxGPS(); - - /** - * Reset our GPS back to factory settings - * - * @return true for success - */ - bool factoryReset() override; - - protected: - /** - * Returns true if we succeeded - */ - virtual bool setupGPS() override; - - /** Subclasses should look for serial rx characters here and feed it to their GPS parser - * - * Return true if we received a valid message from the GPS - */ - virtual bool whileIdle() override; - - /** Idle processing while GPS is looking for lock */ - virtual void whileActive() override; - - /** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a time - */ - virtual bool lookForTime() override; - - /** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a new location - */ - virtual bool lookForLocation() override; - virtual bool hasLock() override; - - /// If possible force the GPS into sleep/low power mode - virtual void sleep() override; - virtual void wake() override; - - private: - /// Attempt to connect to our GPS, returns false if no gps is present - bool tryConnect(); - - /// Switch to our desired operating mode and save the settings to flash - /// returns true for success - bool setUBXMode(); - - uint16_t maxWait() const { return i2cAddress ? 300 : 0; /*If using i2c we must poll with wait */ } -}; diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 47ced53c6..073b313cd 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -1,6 +1,7 @@ #include "configuration.h" #ifdef HAS_EINK +#include "main.h" #include "EInkDisplay2.h" #include "SPILock.h" #include @@ -171,18 +172,46 @@ bool EInkDisplay::connect() } #elif defined(RAK4630) { - auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY); + if (eink_found) { + auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY); - adafruitDisplay = new GxEPD2_BW(*lowLevel); - - adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0)); + adafruitDisplay = new GxEPD2_BW(*lowLevel); + + adafruitDisplay->init(115200, true, 10, false, SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0)); + //RAK14000 2.13 inch b/w 250x122 does not support partial updates //RAK14000 2.13 inch b/w 250x122 does not support partial updates - adafruitDisplay->setRotation(3); - //For 1.54, 2.9 and 4.2 - //adafruitDisplay->setRotation(1); + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + //RAK14000 2.13 inch b/w 250x122 does not support partial updates + adafruitDisplay->setRotation(3); + //For 1.54, 2.9 and 4.2 + //adafruitDisplay->setRotation(1); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight); + } else { + (void)adafruitDisplay; + } } #elif defined(PCA10059) { diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index a4bddaf17..edb3ebc45 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -815,12 +815,25 @@ void _screen_header() } #endif +// #ifdef RAK4630 +// Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), dispdev_oled(address, sda, scl), ui(&dispdev) +// { +// address_found = address; +// cmdQueue.setReader(this); +// if (screen_found) { +// (void)dispdev; +// AutoOLEDWire dispdev = dispdev_oled; +// (void)ui; +// OLEDDisplayUi ui(&dispdev); +// } +// } +// #else Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev) { address_found = address; cmdQueue.setReader(this); } - +// #endif /** * Prepare the display for the unit going to the lowest power mode possible. Most screens will just * poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 59d68c902..259598b80 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -27,6 +27,10 @@ class Screen #ifdef USE_ST7567 #include +#elif defined(USE_SH1106) +#include +#elif defined(USE_SSD1306) +#include #else // the SH1106/SSD1306 variant is auto-detected #include @@ -297,9 +301,16 @@ class Screen : public concurrency::OSThread /// Holds state for debug information DebugInfo debugInfo; - /// Display device - /** FIXME cleanup display abstraction */ -#ifdef ST7735_CS + /// Display device + +// #ifdef RAK4630 +// EInkDisplay dispdev; +// AutoOLEDWire dispdev_oled; +#ifdef USE_SH1106 + SH1106Wire dispdev; +#elif defined(USE_SSD1306) + SSD1306Wire dispdev; +#elif defined(ST7735_CS) TFTDisplay dispdev; #elif defined(HAS_EINK) EInkDisplay dispdev; diff --git a/src/main.cpp b/src/main.cpp index 5a7887608..afb162cee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,6 +24,7 @@ #include "shutdown.h" #include "target_specific.h" #include "debug/i2cScan.h" +#include "debug/einkScan.h" #include "debug/axpDebug.h" #include // #include @@ -78,6 +79,8 @@ uint8_t cardkb_found; // The I2C address of the Faces Keyboard (if found) uint8_t faceskb_found; +bool eink_found = true; + uint32_t serialSinceMsec; bool axp192_found; @@ -208,6 +211,9 @@ void setup() #endif scanI2Cdevice(); +#ifdef RAK4630 + // scanEInkDevice(); +#endif // Buttons & LED buttonThread = new ButtonThread(); diff --git a/src/main.h b/src/main.h index 21138d3f0..fc91f396a 100644 --- a/src/main.h +++ b/src/main.h @@ -10,6 +10,7 @@ extern uint8_t screen_model; extern uint8_t cardkb_found; extern uint8_t faceskb_found; +extern bool eink_found; extern bool axp192_found; extern bool isCharging; extern bool isUSBPowered; diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index 87347f309..51af89df8 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -72,6 +72,16 @@ MeshPacket *MeshPacketQueue::dequeue() return p; } +MeshPacket *MeshPacketQueue::getFront() +{ + if (empty()) { + return NULL; + } + + auto *p = queue.front(); + return p; +} + /** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */ MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id) { diff --git a/src/mesh/MeshPacketQueue.h b/src/mesh/MeshPacketQueue.h index c74addf4e..8c93b452e 100644 --- a/src/mesh/MeshPacketQueue.h +++ b/src/mesh/MeshPacketQueue.h @@ -28,6 +28,8 @@ class MeshPacketQueue MeshPacket *dequeue(); + MeshPacket *getFront(); + /** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ MeshPacket *remove(NodeNum from, PacketId id); }; diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index ad113e8ab..660280fcb 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -95,14 +95,16 @@ bool NodeDB::resetRadioConfig() nvs_flash_erase(); #endif #ifdef NRF52_SERIES + // first, remove the "/prefs" (this removes most prefs) FSCom.rmdir_r("/prefs"); - + // second, install default state (this will deal with the duplicate mac address issue) + installDefaultDeviceState(); + // third, write to disk + saveToDisk(); Bluefruit.begin(); - DEBUG_MSG("Clearing bluetooth bonds!\n"); bond_print_list(BLE_GAP_ROLE_PERIPH); bond_print_list(BLE_GAP_ROLE_CENTRAL); - Bluefruit.Periph.clearBonds(); Bluefruit.Central.clearBonds(); #endif @@ -215,7 +217,7 @@ void NodeDB::init() myNodeInfo.error_address = 0; // likewise - we always want the app requirements to come from the running appload - myNodeInfo.min_app_version = 20200; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20 + myNodeInfo.min_app_version = 20300; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20 // Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't // keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts) diff --git a/src/mesh/ProtobufModule.h b/src/mesh/ProtobufModule.h index dad0eade3..4e411c2a4 100644 --- a/src/mesh/ProtobufModule.h +++ b/src/mesh/ProtobufModule.h @@ -48,6 +48,17 @@ template class ProtobufModule : protected SinglePortModule return p; } + /** + * Gets the short name from the sender of the mesh packet + * Returns "???" if unknown sender + */ + const char *getSenderShortName(const MeshPacket &mp) + { + auto node = nodeDB.getNode(getFrom(&mp)); + const char *sender = (node) ? node->user.short_name : "???"; + return sender; + } + private: /** Called to handle a particular incoming message diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index adaeead46..a96b95100 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -176,6 +176,25 @@ void RF95Interface::startReceive() enableInterrupt(isrRxLevel0); } +bool RF95Interface::isChannelActive() +{ + // check if we can detect a LoRa preamble on the current channel + int16_t result; + setTransmitEnable(false); + setStandby(); // needed for smooth transition + result = lora->scanChannel(); + + if (result == PREAMBLE_DETECTED) { + // DEBUG_MSG("Channel is busy!\n"); + return true; + } + + assert(result != ERR_WRONG_MODEM); + + // DEBUG_MSG("Channel is free!\n"); + return false; +} + /** Could we send right now (i.e. either not actively receving or transmitting)? */ bool RF95Interface::isActivelyReceiving() { diff --git a/src/mesh/RF95Interface.h b/src/mesh/RF95Interface.h index f62195a26..5e666ae8b 100644 --- a/src/mesh/RF95Interface.h +++ b/src/mesh/RF95Interface.h @@ -40,6 +40,9 @@ class RF95Interface : public RadioLibInterface */ virtual void enableInterrupt(void (*callback)()) { lora->setDio0Action(callback); } + /** can we detect a LoRa preamble on the current channel? */ + virtual bool isChannelActive() override; + /** are we actively receiving a packet (only called during receiving state) */ virtual bool isActivelyReceiving() override; diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 5f0e57210..a0058893a 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -118,20 +118,10 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) return res; } - // We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent - // in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio - - /* We assume if rx_snr = 0 and rx_rssi = 0, the packet was not generated locally. - * This assumption is valid because of the offset generated by the radio to account for the noise - * floor. - */ - if (p->rx_snr == 0 && p->rx_rssi == 0) { - startTransmitTimer(true); - } else { - // If there is a SNR, start a timer scaled based on that SNR. - DEBUG_MSG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr); - startTransmitTimerSNR(p->rx_snr); - } + // set (random) transmit delay to let others reconfigure their radio, + // to avoid collisions and implement timing-based flooding + // DEBUG_MSG("Set random delay before transmitting.\n"); + setTransmitDelay(); return res; #else @@ -164,8 +154,8 @@ bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) /** radio helper thread callback. We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and -wait a random delay of 50 to 200 ms to make sure we are not stomping on someone else. The 50ms delay at the beginning ensures all -possible listeners have had time to finish processing the previous packet and now have their radio in RX state. The up to 200ms +wait a random delay of 100ms to 100ms+shortPacketMsec to make sure we are not stomping on someone else. The 100ms delay at the beginning ensures all +possible listeners have had time to finish processing the previous packet and now have their radio in RX state. The up to 100ms+shortPacketMsec random delay gives a chance for all possible senders to have high odds of detecting that someone else started transmitting first and then they will wait until that packet finishes. @@ -192,20 +182,26 @@ void RadioLibInterface::onNotify(uint32_t notification) case TRANSMIT_DELAY_COMPLETED: // DEBUG_MSG("delay done\n"); - // If we are not currently in receive mode, then restart the timer and try again later (this can happen if the main thread + // If we are not currently in receive mode, then restart the random delay (this can happen if the main thread // has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode? if (!txQueue.empty()) { if (!canSendImmediately()) { - startTransmitTimer(); // try again in a little while + // DEBUG_MSG("Currently Rx/Tx-ing: set random delay\n"); + setTransmitDelay(); // currently Rx/Tx-ing: reset random delay } else { - // Send any outgoing packets we have ready - MeshPacket *txp = txQueue.dequeue(); - assert(txp); - startSend(txp); + if (isChannelActive()) { // check if there is currently a LoRa packet on the channel + // DEBUG_MSG("Channel is active: set random delay\n"); + setTransmitDelay(); // reset random delay + } else { + // Send any outgoing packets we have ready + MeshPacket *txp = txQueue.dequeue(); + assert(txp); + startSend(txp); - // Packet has been sent, count it toward our TX airtime utilization. - uint32_t xmitMsec = getPacketTime(txp); - airTime->logAirtime(TX_LOG, xmitMsec); + // Packet has been sent, count it toward our TX airtime utilization. + uint32_t xmitMsec = getPacketTime(txp); + airTime->logAirtime(TX_LOG, xmitMsec); + } } } else { // DEBUG_MSG("done with txqueue\n"); @@ -216,6 +212,26 @@ void RadioLibInterface::onNotify(uint32_t notification) } } +void RadioLibInterface::setTransmitDelay() +{ + MeshPacket *p = txQueue.getFront(); + // We want all sending/receiving to be done by our daemon thread. + // We use a delay here because this packet might have been sent in response to a packet we just received. + // So we want to make sure the other side has had a chance to reconfigure its radio. + + /* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally. + * This assumption is valid because of the offset generated by the radio to account for the noise + * floor. + */ + if (p->rx_snr == 0 && p->rx_rssi == 0) { + startTransmitTimer(true); + } else { + // If there is a SNR, start a timer scaled based on that SNR. + DEBUG_MSG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr); + startTransmitTimerSNR(p->rx_snr); + } +} + void RadioLibInterface::startTransmitTimer(bool withDelay) { // If we have work to do and the timer wasn't already scheduled, schedule it now diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 68dfe96d0..0f59c1fab 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -132,6 +132,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified */ virtual void startReceive() = 0; + /** can we detect a LoRa preamble on the current channel? */ + virtual bool isChannelActive() = 0; + /** are we actively receiving a packet (only called during receiving state) * This method is only public to facilitate debugging. Do not call. */ @@ -141,18 +144,14 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified virtual bool cancelSending(NodeNum from, PacketId id) override; private: - /** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing - * the transmit - * - * If the timer was already running, we just wait for that one to occur. - * */ + /** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually doing + * the transmit */ + void setTransmitDelay(); + + /** random timer with certain min. and max. settings */ void startTransmitTimer(bool withDelay = true); - /** if we have something waiting to send, start a short scaled timer based on SNR so we can come check for collision before actually doing - * the transmit - * - * If the timer was already running, we just wait for that one to occur. - * */ + /** timer scaled to SNR of to be flooded packet */ void startTransmitTimerSNR(float snr); void handleTransmitInterrupt(); diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index b0c48d55a..ac96aa70b 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -226,6 +226,23 @@ void SX126xInterface::startReceive() #endif } +/** Could we send right now (i.e. either not actively receving or transmitting)? */ +template +bool SX126xInterface::isChannelActive() +{ + // check if we can detect a LoRa preamble on the current channel + int16_t result; + + setStandby(); + result = lora.scanChannel(); + if (result == PREAMBLE_DETECTED) + return true; + + assert(result != ERR_WRONG_MODEM); + + return false; +} + /** Could we send right now (i.e. either not actively receving or transmitting)? */ template bool SX126xInterface::isActivelyReceiving() diff --git a/src/mesh/SX126xInterface.h b/src/mesh/SX126xInterface.h index 5168313e2..b0e5d9a32 100644 --- a/src/mesh/SX126xInterface.h +++ b/src/mesh/SX126xInterface.h @@ -46,6 +46,9 @@ class SX126xInterface : public RadioLibInterface */ virtual void enableInterrupt(void (*callback)()) { lora.setDio1Action(callback); } + /** can we detect a LoRa preamble on the current channel? */ + virtual bool isChannelActive() override; + /** are we actively receiving a packet (only called during receiving state) */ virtual bool isActivelyReceiving() override; diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 23c8a42a9..4568521c3 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -27,7 +27,7 @@ int32_t DeviceTelemetryModule::runOnce() bool DeviceTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemetry *t) { if (t->which_variant == Telemetry_device_metrics_tag) { - String sender = getSenderName(mp); + const char *sender = getSenderShortName(mp); DEBUG_MSG("-----------------------------------------\n"); DEBUG_MSG("Device Telemetry: Received data from %s\n", sender); @@ -44,19 +44,6 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemet return false; // Let others look at this message also if they want } -String DeviceTelemetryModule::getSenderName(const MeshPacket &mp) -{ - String sender; - - auto node = nodeDB.getNode(getFrom(&mp)); - if (node) { - sender = node->user.short_name; - } else { - sender = "UNK"; - } - return sender; -} - bool DeviceTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies) { Telemetry t; diff --git a/src/modules/Telemetry/DeviceTelemetry.h b/src/modules/Telemetry/DeviceTelemetry.h index 67c7ac305..c224a2c1d 100644 --- a/src/modules/Telemetry/DeviceTelemetry.h +++ b/src/modules/Telemetry/DeviceTelemetry.h @@ -27,7 +27,6 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu bool sendOurTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); private: - String getSenderName(const MeshPacket &mp); bool firstTime = 1; const MeshPacket *lastMeasurementPacket; }; diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 675969fd7..0257fe311 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -149,19 +149,6 @@ int32_t EnvironmentTelemetryModule::runOnce() #endif } -String GetSenderName(const MeshPacket &mp) -{ - String sender; - - auto node = nodeDB.getNode(getFrom(&mp)); - if (node) { - sender = node->user.short_name; - } else { - sender = "UNK"; - } - return sender; -} - uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp) { uint32_t now = getTime(); @@ -198,7 +185,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt Telemetry lastMeasurement; uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket); - String lastSender = GetSenderName(*lastMeasurementPacket); + const char *lastSender = getSenderShortName(*lastMeasurementPacket); auto &p = lastMeasurementPacket->decoded; if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, Telemetry_fields, &lastMeasurement)) { @@ -213,16 +200,16 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt if (radioConfig.preferences.telemetry_module_environment_display_fahrenheit) { last_temp = String(CelsiusToFahrenheit(lastMeasurement.variant.environment_metrics.temperature), 0) + "°F"; } - display->drawString(x, y += fontHeight(FONT_MEDIUM) - 2, "From: " + lastSender + "(" + String(agoSecs) + "s)"); - display->drawString(x, y += fontHeight(FONT_SMALL) - 2,"Temp/Hum: " + last_temp + " / " + String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%"); + display->drawString(x, y += fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)"); + display->drawString(x, y += fontHeight(FONT_SMALL) - 2, "Temp/Hum: " + last_temp + " / " + String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%"); if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0) - display->drawString(x, y += fontHeight(FONT_SMALL),"Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA"); + display->drawString(x, y += fontHeight(FONT_SMALL), "Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA"); } bool EnvironmentTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemetry *t) { if (t->which_variant == Telemetry_environment_metrics_tag) { - String sender = GetSenderName(mp); + const char *sender = getSenderShortName(mp); DEBUG_MSG("-----------------------------------------\n"); DEBUG_MSG("Environment Telemetry: Received data from %s\n", sender); diff --git a/src/nrf52/NRF52CryptoEngine.cpp b/src/nrf52/NRF52CryptoEngine.cpp index 1018b94fd..49f85a857 100644 --- a/src/nrf52/NRF52CryptoEngine.cpp +++ b/src/nrf52/NRF52CryptoEngine.cpp @@ -1,12 +1,9 @@ #include "configuration.h" #include "CryptoEngine.h" -#include "ocrypto_aes_ctr.h" +#include class NRF52CryptoEngine : public CryptoEngine { - - - public: NRF52CryptoEngine() {} @@ -19,29 +16,37 @@ class NRF52CryptoEngine : public CryptoEngine */ virtual void encrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override { - // DEBUG_MSG("NRF52 encrypt!\n"); +// DEBUG_MSG("NRF52 encrypt!\n"); if (key.length > 0) { - ocrypto_aes_ctr_ctx ctx; - + nRFCrypto.begin(); + nRFCrypto_AES ctx; + uint8_t myLen = ctx.blockLen(numBytes); + char encBuf[myLen] = {0}; + memcpy(encBuf, bytes, numBytes); initNonce(fromNode, packetId); - ocrypto_aes_ctr_init(&ctx, key.bytes, key.length, nonce); - - ocrypto_aes_ctr_encrypt(&ctx, bytes, bytes, numBytes); + ctx.begin(); + ctx.Process(encBuf, numBytes, nonce, key.bytes, key.length, (char*)bytes, ctx.encryptFlag, ctx.ctrMode); + ctx.end(); + nRFCrypto.end(); } } virtual void decrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override { - // DEBUG_MSG("NRF52 decrypt!\n"); +// DEBUG_MSG("NRF52 decrypt!\n"); if (key.length > 0) { - ocrypto_aes_ctr_ctx ctx; - + nRFCrypto.begin(); + nRFCrypto_AES ctx; + uint8_t myLen = ctx.blockLen(numBytes); + char decBuf[myLen] = {0}; + memcpy(decBuf, bytes, numBytes); initNonce(fromNode, packetId); - ocrypto_aes_ctr_init(&ctx, key.bytes, key.length, nonce); - - ocrypto_aes_ctr_decrypt(&ctx, bytes, bytes, numBytes); + ctx.begin(); + ctx.Process(decBuf, numBytes, nonce, key.bytes, key.length, (char*)bytes, ctx.decryptFlag, ctx.ctrMode); + ctx.end(); + nRFCrypto.end(); } } diff --git a/src/nrf52/main-nrf52.cpp b/src/nrf52/main-nrf52.cpp index bcf354024..655170c36 100644 --- a/src/nrf52/main-nrf52.cpp +++ b/src/nrf52/main-nrf52.cpp @@ -5,6 +5,7 @@ #include #include #include +#include // #include #include "NRF52Bluetooth.h" @@ -145,13 +146,15 @@ void nrf52Setup() #endif // Init random seed - // FIXME - use this to get random numbers - // #include "nrf_rng.h" - // uint32_t r; - // ble_controller_rand_vector_get_blocking(&r, sizeof(r)); - // randomSeed(r); - DEBUG_MSG("FIXME, call randomSeed\n"); - // ::printf("TESTING PRINTF\n"); + union seedParts { + uint32_t seed32; + uint8_t seed8[4]; + } seed; + nRFCrypto.begin(); + nRFCrypto.Random.generate(seed.seed8, sizeof(seed.seed8)); + DEBUG_MSG("Setting random seed %u\n", seed.seed32); + randomSeed(seed.seed32); + nRFCrypto.end(); } void cpuDeepSleep(uint64_t msecToWake) diff --git a/variants/WisCore_RAK4631_Board/platformio.ini b/variants/WisCore_RAK4631_Board/platformio.ini deleted file mode 100644 index cfd9297e0..000000000 --- a/variants/WisCore_RAK4631_Board/platformio.ini +++ /dev/null @@ -1,20 +0,0 @@ -; The very slick RAK wireless RAK 4631 / 4630 board -[env:rak4631_5005] -extends = nrf52840_base -board = wiscore_rak4631 -# add our variants files to the include and src paths -# define build flags for the TFT_eSPI library -build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board -D RAK_BASE_5005 -src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board> -debug_tool = jlink - -[env:rak4631_19003] -extends = nrf52840_base -board = wiscore_rak4631 -# add our variants files to the include and src paths -# define build flags for the TFT_eSPI library -build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board -D RAK_BASE_19003 -src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board> -debug_tool = jlink -; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink \ No newline at end of file diff --git a/variants/WisCore_RAK4631_E-Paper_Board/platformio.ini b/variants/WisCore_RAK4631_E-Paper_Board/platformio.ini deleted file mode 100644 index 19855006b..000000000 --- a/variants/WisCore_RAK4631_E-Paper_Board/platformio.ini +++ /dev/null @@ -1,9 +0,0 @@ -[env:rak4631_5005_eink] -extends = nrf52840_base -board = wiscore_rak4631 -build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_E-Paper_Board -D RAK_BASE_5005 -src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_E-Paper_Board> -lib_deps = - ${nrf52840_base.lib_deps} - https://github.com/ZinggJM/GxEPD2.git -debug_tool = jlink diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini new file mode 100644 index 000000000..6e0563598 --- /dev/null +++ b/variants/rak4631/platformio.ini @@ -0,0 +1,11 @@ +; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmare for 5005/19003, with or without OLED RAK 1921 +[env:rak4631] +extends = nrf52840_base +board = wiscore_rak4631 +build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631 -D RAK_4631 +src_filter = ${nrf52_base.src_filter} +<../variants/rak4631> +lib_deps = + ${nrf52840_base.lib_deps} +debug_tool = jlink +; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) +;upload_protocol = jlink \ No newline at end of file diff --git a/variants/WisCore_RAK4631_Board/variant.cpp b/variants/rak4631/variant.cpp similarity index 100% rename from variants/WisCore_RAK4631_Board/variant.cpp rename to variants/rak4631/variant.cpp diff --git a/variants/WisCore_RAK4631_Board/variant.h b/variants/rak4631/variant.h similarity index 89% rename from variants/WisCore_RAK4631_Board/variant.h rename to variants/rak4631/variant.h index 3058068c8..c211ec4a1 100644 --- a/variants/WisCore_RAK4631_Board/variant.h +++ b/variants/rak4631/variant.h @@ -59,10 +59,8 @@ extern "C" { * Buttons */ -#ifdef RAK_BASE_5005 #define PIN_BUTTON1 9 // Pin for button on E-ink button module or IO expansion #define BUTTON_NEED_PULLUP -#endif #define PIN_BUTTON2 12 #define PIN_BUTTON3 24 #define PIN_BUTTON4 25 @@ -110,17 +108,39 @@ static const uint8_t AREF = PIN_AREF; /* * SPI Interfaces */ -#define SPI_INTERFACES_COUNT 1 +#define SPI_INTERFACES_COUNT 2 #define PIN_SPI_MISO (45) #define PIN_SPI_MOSI (44) #define PIN_SPI_SCK (43) +#define PIN_SPI1_MISO (29) // (0 + 29) +#define PIN_SPI1_MOSI (30) // (0 + 30) +#define PIN_SPI1_SCK (3) // (0 + 3) + static const uint8_t SS = 42; static const uint8_t MOSI = PIN_SPI_MOSI; static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; + /* + * eink display pins + */ + +#define PIN_EINK_EN (0 + 2) // (0 + 2) Note: this is really just backlight power +#define PIN_EINK_CS (0 + 26) +#define PIN_EINK_BUSY (0 + 4) +#define PIN_EINK_DC (0 + 17) +#define PIN_EINK_RES (-1) +#define PIN_EINK_SCLK (0 + 3) +#define PIN_EINK_MOSI (0 + 30) // also called SDI + +// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON +// FIXME - I think this is actually just the board power enable - it enables power to the CPU also +//#define PIN_EINK_PWR_ON (-1) + +// #define HAS_EINK + /* * Wire Interfaces */ @@ -175,10 +195,8 @@ static const uint8_t SCK = PIN_SPI_SCK; #define PIN_GPS_EN (34) #define PIN_GPS_PPS (17) // Pulse per second input from the GPS -#ifdef RAK_BASE_5005 #define GPS_RX_PIN PIN_SERIAL1_RX #define GPS_TX_PIN PIN_SERIAL1_TX -#endif // Battery // The battery sense is hooked to pin A0 (5) diff --git a/variants/rak4631_epaper/platformio.ini b/variants/rak4631_epaper/platformio.ini new file mode 100644 index 000000000..fc65ac2c8 --- /dev/null +++ b/variants/rak4631_epaper/platformio.ini @@ -0,0 +1,12 @@ +; The very slick RAK wireless RAK 4631 / 4630 board - Firmware for 5005 with the RAK 14000 ePaper +[env:rak4631_eink] +extends = nrf52840_base +board = wiscore_rak4631 +build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631_epaper -D RAK_4631 +src_filter = ${nrf52_base.src_filter} +<../variants/rak4631_epaper> +lib_deps = + ${nrf52840_base.lib_deps} + https://github.com/ZinggJM/GxEPD2.git +debug_tool = jlink +; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) +;upload_protocol = jlink \ No newline at end of file diff --git a/variants/WisCore_RAK4631_E-Paper_Board/variant.cpp b/variants/rak4631_epaper/variant.cpp similarity index 99% rename from variants/WisCore_RAK4631_E-Paper_Board/variant.cpp rename to variants/rak4631_epaper/variant.cpp index 5b9288319..b96f6f1cd 100644 --- a/variants/WisCore_RAK4631_E-Paper_Board/variant.cpp +++ b/variants/rak4631_epaper/variant.cpp @@ -2,14 +2,17 @@ Copyright (c) 2014-2015 Arduino LLC. All right reserved. Copyright (c) 2016 Sandeep Mistry All right reserved. Copyright (c) 2018, Adafruit Industries (adafruit.com) + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/variants/WisCore_RAK4631_E-Paper_Board/variant.h b/variants/rak4631_epaper/variant.h similarity index 99% rename from variants/WisCore_RAK4631_E-Paper_Board/variant.h rename to variants/rak4631_epaper/variant.h index 4b5d21add..071c659e1 100644 --- a/variants/WisCore_RAK4631_E-Paper_Board/variant.h +++ b/variants/rak4631_epaper/variant.h @@ -2,6 +2,7 @@ Copyright (c) 2014-2015 Arduino LLC. All right reserved. Copyright (c) 2016 Sandeep Mistry All right reserved. Copyright (c) 2018, Adafruit Industries (adafruit.com) + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either @@ -58,10 +59,8 @@ extern "C" { * Buttons */ -#ifdef RAK_BASE_5005 #define PIN_BUTTON1 9 // Pin for button on E-ink button module or IO expansion #define BUTTON_NEED_PULLUP -#endif #define PIN_BUTTON2 12 #define PIN_BUTTON3 24 #define PIN_BUTTON4 25 @@ -196,10 +195,8 @@ static const uint8_t SCK = PIN_SPI_SCK; #define PIN_GPS_EN (34) #define PIN_GPS_PPS (17) // Pulse per second input from the GPS -#ifdef RAK_BASE_5005 #define GPS_RX_PIN PIN_SERIAL1_RX #define GPS_TX_PIN PIN_SERIAL1_TX -#endif // Battery // The battery sense is hooked to pin A0 (5)