From 98d878cdfe7c320a87165d251db91419d5114246 Mon Sep 17 00:00:00 2001 From: Vadim Furman Date: Sun, 14 Mar 2021 19:00:20 -0700 Subject: [PATCH] Port to lora_isp4520 board --- boards/lora_isp4520.json | 48 ++++++++++++ platformio.ini | 22 +++++- src/Power.cpp | 60 +++++++++++--- src/PowerFSM.cpp | 2 +- src/RedirectablePrint.cpp | 126 +++++++++++++++--------------- src/buzz/buzz.cpp | 52 ++++++++++++ src/buzz/buzz.h | 5 ++ src/buzz/pitches.h | 91 +++++++++++++++++++++ src/configuration.h | 4 + src/gps/GPS.cpp | 46 +++++++++++ src/gps/GPS.h | 7 ++ src/gps/RTC.cpp | 15 ++-- src/graphics/Screen.h | 19 +++++ src/main.cpp | 68 +++++++--------- src/mesh/SX1262Interface.cpp | 6 +- src/nrf52/NRF52Bluetooth.cpp | 5 +- src/nrf52/main-nrf52.cpp | 6 +- variants/lora_isp4520/variant.cpp | 52 ++++++++++++ variants/lora_isp4520/variant.h | 98 +++++++++++++++++++++++ 19 files changed, 604 insertions(+), 128 deletions(-) create mode 100644 boards/lora_isp4520.json create mode 100644 src/buzz/buzz.cpp create mode 100644 src/buzz/buzz.h create mode 100644 src/buzz/pitches.h create mode 100644 variants/lora_isp4520/variant.cpp create mode 100644 variants/lora_isp4520/variant.h diff --git a/boards/lora_isp4520.json b/boards/lora_isp4520.json new file mode 100644 index 000000000..180cd2fe7 --- /dev/null +++ b/boards/lora_isp4520.json @@ -0,0 +1,48 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52832_s132_v6.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DNRF52832_XXAA -DNRF52", + "f_cpu": "64000000L", + "mcu": "nrf52832", + "variant": "lora_isp4520", + "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": "lora ISP4520", + "upload": { + "maximum_ram_size": 65536, + "maximum_size": 524288, + "require_upload_port": true, + "speed": 115200, + "protocol": "nrfutil", + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "stlink" + ] + }, + "url": "", + "vendor": "PsiSoft" +} \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 2033b2faf..155242b81 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,7 +33,7 @@ extra_scripts = bin/platformio-custom.py ; note: we add src to our include search path so that lmic_project_config can override ; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc -build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map +build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map -DHW_VERSION_${sysenv.COUNTRY} -DHW_VERSION=${sysenv.HW_VERSION} -DUSE_THREAD_NAMES @@ -65,7 +65,6 @@ debug_tool = jlink ; monitor adapter_khz 10000 lib_deps = - https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306 https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39 @@ -104,6 +103,7 @@ build_flags = lib_deps = ${arduino_base.lib_deps} https://github.com/meshtastic/esp32_https_server.git + https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306 # Hmm - this doesn't work yet # board_build.ldscript = linker/esp32.extram.bss.ld lib_ignore = segger_rtt @@ -204,6 +204,24 @@ debug_init_break = ;debug_init_break = tbreak loop ;debug_init_break = tbreak Reset_Handler +[env:lora_isp4520] +extends = nrf52_base +board = lora_isp4520 + +# add our variants files to the include and src paths +build_flags = ${nrf52_base.build_flags} -Ivariants/lora_isp4520 + +# No screen and GPS on the board. We still need RTC.cpp for the RTC clock. +src_filter = ${nrf52_base.src_filter} +<../variants/lora_isp4520> - - + + +lib_ignore = ${nrf52_base.lib_ignore} + ESP8266_SSD1306 + SparkFun Ublox Arduino Library + AXP202X_Library + TinyGPSPlus + +upload_protocol = jlink +monitor_port = /dev/ttyUSB0 + ; The NRF52840-dk development board ; Note: By default no lora device is created for this build - it uses a simulated interface [env:nrf52840dk] diff --git a/src/Power.cpp b/src/Power.cpp index 26c40f926..f709fb22e 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -5,12 +5,35 @@ #include "sleep.h" #include "utils.h" +#ifdef TBEAM_V10 // FIXME. nasty hack cleanup how we load axp192 #undef AXP192_SLAVE_ADDRESS #include "axp20x.h" -#ifdef TBEAM_V10 AXP20X_Class axp; +#else +// Copy of the base class defined in axp20x.h. +// I'd rather not inlude axp20x.h as it brings Wire dependency. +class HasBatteryLevel { +public: + /** + * Battery state of charge, from 0 to 100 or -1 for unknown + */ + virtual int getBattPercentage() { return -1; } + + /** + * The raw voltage of the battery or NAN if unknown + */ + virtual float getBattVoltage() { return NAN; } + + /** + * return true if there is a battery installed in this unit + */ + virtual bool isBatteryConnect() { return false; } + + virtual bool isVBUSPlug() { return false; } + virtual bool isCharging() { return false; } +}; #endif bool pmu_irq = false; @@ -51,7 +74,7 @@ class AnalogBatteryLevel : public HasBatteryLevel */ virtual int getBattPercentage() { - float v = getBattVoltage() / 1000; + float v = getBattVoltage(); if (v < noBatVolt) return -1; // If voltage is super low assume no battery installed @@ -67,13 +90,26 @@ class AnalogBatteryLevel : public HasBatteryLevel */ virtual float getBattVoltage() { - // Tested ttgo eink nrf52 board and the reported value is perfect - // DEBUG_MSG("raw val %u", raw); - return + +#ifndef ADC_MULTIPLIER +#define ADC_MULTIPLIER 2.0 +#endif + #ifdef BATTERY_PIN - 1000.0 * 2.0 * (AREF_VOLTAGE / 1024.0) * analogRead(BATTERY_PIN); + // Do not call analogRead() often. + const uint32_t min_read_interval = 5000; + if (millis() - last_read_time_ms > min_read_interval) { + last_read_time_ms = millis(); + uint32_t raw = analogRead(BATTERY_PIN); + float scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw; + // DEBUG_MSG("raw val=%u scaled=%u\n", raw, (uint32_t)(scaled)); + last_read_value = scaled; + return scaled; + } else { + return last_read_value; + } #else - NAN; + return NAN; #endif } @@ -88,12 +124,14 @@ class AnalogBatteryLevel : public HasBatteryLevel /// Assume charging if we have a battery and external power is connected. /// we can't be smart enough to say 'full'? - virtual bool isChargeing() { return isBatteryConnect() && isVBUSPlug(); } + virtual bool isCharging() { return isBatteryConnect() && isVBUSPlug(); } private: /// If we see a battery voltage higher than physics allows - assume charger is pumping /// in power - const float fullVolt = 4.2, emptyVolt = 3.27, chargingVolt = 4.3, noBatVolt = 2.1; + const float fullVolt = 4200, emptyVolt = 3270, chargingVolt = 4210, noBatVolt = 2100; + float last_read_value = 0.0; + uint32_t last_read_time_ms = 0; } analogLevel; Power::Power() : OSThread("Power") {} @@ -140,6 +178,8 @@ void Power::shutdown() #ifdef TBEAM_V10 DEBUG_MSG("Shutting down\n"); axp.shutdown(); +#elif NRF52_SERIES + doDeepSleep(DELAY_FOREVER); #endif } @@ -170,7 +210,7 @@ void Power::readPowerStatus() // Notify any status instances that are observing us const PowerStatus powerStatus = PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse, - batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent); + batteryLevel->isCharging() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent); DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus.getHasUSB(), powerStatus.getIsCharging(), powerStatus.getBatteryVoltageMv(), powerStatus.getBatteryChargePercent()); newStatus.notifyObservers(&powerStatus); diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 85e08f536..4857ae07d 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -97,7 +97,7 @@ static void lsIdle() static void lsExit() { // setGPSPower(true); // restore GPS power - gps->forceWake(true); + if (gps) gps->forceWake(true); } static void nbEnter() diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 541b55c78..585b3a9a0 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -1,99 +1,97 @@ #include "RedirectablePrint.h" -#include "configuration.h" + #include -#include -#include + +#include "RTC.h" #include "concurrency/OSThread.h" +#include "configuration.h" /** * A printer that doesn't go anywhere */ NoopPrint noopPrint; -void RedirectablePrint::setDestination(Print *_dest) -{ - assert(_dest); - dest = _dest; +void RedirectablePrint::setDestination(Print *_dest) { + assert(_dest); + dest = _dest; } -size_t RedirectablePrint::write(uint8_t c) -{ - // Always send the characters to our segger JTAG debugger +size_t RedirectablePrint::write(uint8_t c) { + // Always send the characters to our segger JTAG debugger #ifdef SEGGER_STDOUT_CH - SEGGER_RTT_PutCharSkip(SEGGER_STDOUT_CH, c); + SEGGER_RTT_PutCharSkip(SEGGER_STDOUT_CH, c); #endif - dest->write(c); - return 1; // We always claim one was written, rather than trusting what the serial port said (which could be zero) + dest->write(c); + return 1; // We always claim one was written, rather than trusting what the + // serial port said (which could be zero) } -size_t RedirectablePrint::vprintf(const char *format, va_list arg) -{ - va_list copy; +size_t RedirectablePrint::vprintf(const char *format, va_list arg) { + va_list copy; - va_copy(copy, arg); - int len = vsnprintf(printBuf, printBufLen, format, copy); - va_end(copy); - if (len < 0) { - va_end(arg); - return 0; - }; - if (len >= printBufLen) { - delete[] printBuf; - printBufLen *= 2; - printBuf = new char[printBufLen]; - len = vsnprintf(printBuf, printBufLen, format, arg); - } + va_copy(copy, arg); + int len = vsnprintf(printBuf, printBufLen, format, copy); + va_end(copy); + if (len < 0) { + va_end(arg); + return 0; + }; + if (len >= printBufLen) { + delete[] printBuf; + printBufLen *= 2; + printBuf = new char[printBufLen]; + len = vsnprintf(printBuf, printBufLen, format, arg); + } - len = Print::write(printBuf, len); - return len; + len = Print::write(printBuf, len); + return len; } #define SEC_PER_DAY 86400 #define SEC_PER_HOUR 3600 #define SEC_PER_MIN 60 -size_t RedirectablePrint::logDebug(const char *format, ...) -{ - va_list arg; - va_start(arg, format); +size_t RedirectablePrint::logDebug(const char *format, ...) { + va_list arg; + va_start(arg, format); - // Cope with 0 len format strings, but look for new line terminator - bool hasNewline = *format && format[strlen(format) - 1] == '\n'; + // Cope with 0 len format strings, but look for new line terminator + bool hasNewline = *format && format[strlen(format) - 1] == '\n'; - size_t r = 0; + size_t r = 0; - // If we are the first message on a report, include the header - if (!isContinuationMessage) { - struct timeval tv; - if (!gettimeofday(&tv, NULL)) { - long hms = tv.tv_sec % SEC_PER_DAY; - //hms += tz.tz_dsttime * SEC_PER_HOUR; - //hms -= tz.tz_minuteswest * SEC_PER_MIN; - // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) - hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; + // If we are the first message on a report, include the header + if (!isContinuationMessage) { + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityFromNet); + if (rtc_sec > 0) { + long hms = rtc_sec % SEC_PER_DAY; + // hms += tz.tz_dsttime * SEC_PER_HOUR; + // hms -= tz.tz_minuteswest * SEC_PER_MIN; + // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) + hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; - // Tear apart hms into h:m:s - int hour = hms / SEC_PER_HOUR; - int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; - int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN + // Tear apart hms into h:m:s + int hour = hms / SEC_PER_HOUR; + int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; + int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN - r += printf("%02d:%02d:%02d ", hour, min, sec); - } else - r += printf("??:??:?? "); + r += printf("%02d:%02d:%02d ", hour, min, sec); + } else + r += printf("??:??:?? "); - auto thread = concurrency::OSThread::currentThread; - if(thread) { - print("["); - print(thread->ThreadName); - print("] "); - } + auto thread = concurrency::OSThread::currentThread; + if (thread) { + print("["); + print(thread->ThreadName); + print("] "); } + } - r += vprintf(format, arg); - va_end(arg); + r += vprintf(format, arg); + va_end(arg); - isContinuationMessage = !hasNewline; + isContinuationMessage = !hasNewline; - return r; + return r; } \ No newline at end of file diff --git a/src/buzz/buzz.cpp b/src/buzz/buzz.cpp new file mode 100644 index 000000000..f9f6ba414 --- /dev/null +++ b/src/buzz/buzz.cpp @@ -0,0 +1,52 @@ +#include "buzz.h" +#include "configuration.h" + +#ifdef NRF52_SERIES +#include "variant.h" +#endif + +#ifndef PIN_BUZZER + +void playBeep(){}; +void playStartMelody(){}; +void playShutdownMelody(){}; + +#else +#include "Tone.h" +#include "pitches.h" + +extern "C" void delay(uint32_t dwMs); + +struct ToneDuration { + int frequency_khz; + int duration_ms; +}; + +const int DURATION_1_8 = 125; // 1/8 note +const int DURATION_1_4 = 250; // 1/4 note + +void playTones(const ToneDuration *tone_durations, int size) { + for (int i = 0; i < size; i++) { + const auto &tone_duration = tone_durations[i]; + tone(PIN_BUZZER, tone_duration.frequency_khz, tone_duration.duration_ms); + // to distinguish the notes, set a minimum time between them. + delay(1.3 * tone_duration.duration_ms); + } +} + +void playBeep() { tone(PIN_BUZZER, NOTE_B3, DURATION_1_4); } + +void playStartMelody() { + ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}, + {NOTE_B3, DURATION_1_8}, + {NOTE_B3, DURATION_1_8}}; + playTones(melody, sizeof(melody) / sizeof(ToneDuration)); +} + +void playShutdownMelody() { + ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}, + {NOTE_G3, DURATION_1_8}, + {NOTE_D3, DURATION_1_8}}; + playTones(melody, sizeof(melody) / sizeof(ToneDuration)); +} +#endif \ No newline at end of file diff --git a/src/buzz/buzz.h b/src/buzz/buzz.h new file mode 100644 index 000000000..3883bd057 --- /dev/null +++ b/src/buzz/buzz.h @@ -0,0 +1,5 @@ +#pragma once + +void playBeep(); +void playStartMelody(); +void playShutdownMelody(); diff --git a/src/buzz/pitches.h b/src/buzz/pitches.h new file mode 100644 index 000000000..3acf0db82 --- /dev/null +++ b/src/buzz/pitches.h @@ -0,0 +1,91 @@ +#pragma once + +#define NOTE_B0 31 +#define NOTE_C1 33 +#define NOTE_CS1 35 +#define NOTE_D1 37 +#define NOTE_DS1 39 +#define NOTE_E1 41 +#define NOTE_F1 44 +#define NOTE_FS1 46 +#define NOTE_G1 49 +#define NOTE_GS1 52 +#define NOTE_A1 55 +#define NOTE_AS1 58 +#define NOTE_B1 62 +#define NOTE_C2 65 +#define NOTE_CS2 69 +#define NOTE_D2 73 +#define NOTE_DS2 78 +#define NOTE_E2 82 +#define NOTE_F2 87 +#define NOTE_FS2 93 +#define NOTE_G2 98 +#define NOTE_GS2 104 +#define NOTE_A2 110 +#define NOTE_AS2 117 +#define NOTE_B2 123 +#define NOTE_C3 131 +#define NOTE_CS3 139 +#define NOTE_D3 147 +#define NOTE_DS3 156 +#define NOTE_E3 165 +#define NOTE_F3 175 +#define NOTE_FS3 185 +#define NOTE_G3 196 +#define NOTE_GS3 208 +#define NOTE_A3 220 +#define NOTE_AS3 233 +#define NOTE_B3 247 +#define NOTE_C4 262 +#define NOTE_CS4 277 +#define NOTE_D4 294 +#define NOTE_DS4 311 +#define NOTE_E4 330 +#define NOTE_F4 349 +#define NOTE_FS4 370 +#define NOTE_G4 392 +#define NOTE_GS4 415 +#define NOTE_A4 440 +#define NOTE_AS4 466 +#define NOTE_B4 494 +#define NOTE_C5 523 +#define NOTE_CS5 554 +#define NOTE_D5 587 +#define NOTE_DS5 622 +#define NOTE_E5 659 +#define NOTE_F5 698 +#define NOTE_FS5 740 +#define NOTE_G5 784 +#define NOTE_GS5 831 +#define NOTE_A5 880 +#define NOTE_AS5 932 +#define NOTE_B5 988 +#define NOTE_C6 1047 +#define NOTE_CS6 1109 +#define NOTE_D6 1175 +#define NOTE_DS6 1245 +#define NOTE_E6 1319 +#define NOTE_F6 1397 +#define NOTE_FS6 1480 +#define NOTE_G6 1568 +#define NOTE_GS6 1661 +#define NOTE_A6 1760 +#define NOTE_AS6 1865 +#define NOTE_B6 1976 +#define NOTE_C7 2093 +#define NOTE_CS7 2217 +#define NOTE_D7 2349 +#define NOTE_DS7 2489 +#define NOTE_E7 2637 +#define NOTE_F7 2794 +#define NOTE_FS7 2960 +#define NOTE_G7 3136 +#define NOTE_GS7 3322 +#define NOTE_A7 3520 +#define NOTE_AS7 3729 +#define NOTE_B7 3951 +#define NOTE_C8 4186 +#define NOTE_CS8 4435 +#define NOTE_D8 4699 +#define NOTE_DS8 4978 \ No newline at end of file diff --git a/src/configuration.h b/src/configuration.h index 79d1009ca..6ba24f1c9 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -384,7 +384,9 @@ along with this program. If not, see . #elif NRF52_SERIES +#ifndef HW_VENDOR #define HW_VENDOR "nrf52unknown" // FIXME - unknown nrf52 board +#endif #elif PORTDUINO @@ -432,6 +434,8 @@ along with this program. If not, see . #define DEBUG_PORT console // Serial debug port + + // What platforms should use SEGGER? #ifdef NRF52_SERIES diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 04aa2c7af..4a6fca7c4 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -300,3 +300,49 @@ int GPS::prepareDeepSleep(void *unused) return 0; } + +#ifdef GPS_TX_PIN +#include "UBloxGPS.h" +#endif + +#ifdef HAS_AIR530_GPS +#include "Air530GPS.h" +#elif !defined(NO_GPS) +#include "NMEAGPS.h" +#endif + + +GPS* createGps() { + +#ifdef NO_GPS + return nullptr; +#else +// 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 { + 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("Hoping that NMEA might work\n"); +#ifdef HAS_AIR530_GPS + GPS* new_gps = new Air530GPS(); +#else + GPS* new_gps = new NMEAGPS(); +#endif + new_gps->setup(); + return new_gps; + } + return nullptr; +#endif +} \ No newline at end of file diff --git a/src/gps/GPS.h b/src/gps/GPS.h index eca2962d2..50cb07f2b 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -71,6 +71,9 @@ class GPS : private concurrency::OSThread * */ void forceWake(bool on); + // Some GPS modules (ublock) require factory reset + virtual bool factoryReset() { return true; } + protected: /// Do gps chipset specific init, return true for success virtual bool setupGPS(); @@ -145,4 +148,8 @@ class GPS : private concurrency::OSThread virtual int32_t runOnce(); }; +// Creates an instance of the GPS class. +// Returns the new instance or null if the GPS is not present. +GPS* createGps(); + extern GPS *gps; diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index 56b51e0af..1508aef60 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -39,22 +39,23 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv) currentQuality = q; shouldSet = true; DEBUG_MSG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q); - } else if(q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000L)) { - // Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift + } else if(q > RTCQualityNone && q == currentQuality && (now - lastSetMsec) > (12 * 60 * 60 * 1000L)) { + // Every 12 hrs we will slam in a new time, to correct for local RTC clock drift shouldSet = true; - DEBUG_MSG("Reapplying GPS time to correct clock drift %ld secs\n", tv->tv_sec); + DEBUG_MSG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec); } else shouldSet = false; if (shouldSet) { - lastSetMsec = now; + lastSetMsec = now; #ifndef NO_ESP32 settimeofday(tv, NULL); -#else - DEBUG_MSG("ERROR TIME SETTING NOT IMPLEMENTED!\n"); -#endif readFromRTC(); +#else + timeStartMsec = now; + zeroOffsetSecs = tv->tv_sec; +#endif return true; } else { return false; diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 888f31011..d629c2d0a 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -1,5 +1,23 @@ #pragma once +#ifdef NO_SCREEN +namespace graphics +{ +// Noop class for boards without screen. +class Screen +{ + public: + Screen(char){} + void onPress() {} + void setup() {} + void setOn(bool) {} + void print(const char*){} + void adjustBrightness(){} + void doDeepSleep() {} +}; +} + +#else #include #include @@ -278,3 +296,4 @@ class Screen : public concurrency::OSThread }; } // namespace graphics +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index aa7b191d9..9997d9e11 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,11 @@ -#include "Air530GPS.h" +#include "GPS.h" #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "UBloxGPS.h" #include "airtime.h" +#include "buzz.h" #include "configuration.h" #include "error.h" #include "power.h" @@ -63,7 +63,7 @@ Router *router = NULL; // Users of router don't care what sort of subclass imple // ----------------------------------------------------------------------------- // Application // ----------------------------------------------------------------------------- - +#if WIRE_INTERFACES_COUNT > 0 void scanI2Cdevice(void) { byte err, addr; @@ -100,6 +100,9 @@ void scanI2Cdevice(void) else DEBUG_MSG("done\n"); } +#else +void scanI2Cdevice(void) {} +#endif const char *getDeviceName() { @@ -169,7 +172,7 @@ class ButtonThread : public OSThread #ifdef BUTTON_PIN_ALT OneButton userButtonAlt; #endif - + static bool shutdown_on_long_stop; public: static uint32_t longPressTime; @@ -235,13 +238,23 @@ class ButtonThread : public OSThread // DEBUG_MSG("Long press!\n"); screen->adjustBrightness(); - // If user button is held down for 10 seconds, shutdown the device. - if (millis() - longPressTime > 10 * 1000) { + // If user button is held down for 5 seconds, shutdown the device. + if (millis() - longPressTime > 5 * 1000) { #ifdef TBEAM_V10 if (axp192_found == true) { setLed(false); power->shutdown(); } +#elif NRF52_SERIES + // Do actual shutdown when button released, otherwise the button release + // may wake the board immediatedly. + if (!shutdown_on_long_stop) { + DEBUG_MSG("Shutdown from long press"); + playBeep(); + ledOff(PIN_LED1); + ledOff(PIN_LED2); + shutdown_on_long_stop = true; + } #endif } else { // DEBUG_MSG("Long press %u\n", (millis() - longPressTime)); @@ -265,9 +278,15 @@ class ButtonThread : public OSThread { DEBUG_MSG("Long press stop!\n"); longPressTime = 0; + if (shutdown_on_long_stop) { + playShutdownMelody(); + power->shutdown(); + } } }; +bool ButtonThread::shutdown_on_long_stop = false; + static Periodic *ledPeriodic; static OSThread *powerFSMthread, *buttonThread; uint32_t ButtonThread::longPressTime = 0; @@ -332,7 +351,7 @@ void setup() #ifdef I2C_SDA Wire.begin(I2C_SDA, I2C_SCL); -#else +#elif WIRE_INTERFACES_COUNT > 0 Wire.begin(); #endif @@ -369,7 +388,7 @@ void setup() #ifdef NRF52_SERIES nrf52Setup(); #endif - + playStartMelody(); // We do this as early as possible because this loads preferences from flash // but we need to do this after main cpu iniot (esp32setup), because we need the random seed set nodeDB.init(); @@ -407,34 +426,7 @@ void setup() pinMode(BATTERY_EN_PIN, OUTPUT); digitalWrite(BATTERY_EN_PIN, LOW); #endif - - // If we don't have bidirectional comms, we can't even try talking to UBLOX - UBloxGPS *ublox = NULL; -#ifdef GPS_TX_PIN - // Init GPS - first try ublox - ublox = new UBloxGPS(); - gps = ublox; - if (!gps->setup()) { - DEBUG_MSG("ERROR: No UBLOX GPS found\n"); - - delete ublox; - gps = ublox = NULL; - } -#endif - - if (!gps && 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. - // dumb NMEA access only work for serial GPSes) - DEBUG_MSG("Hoping that NMEA might work\n"); - -#ifdef HAS_AIR530_GPS - gps = new Air530GPS(); -#else - gps = new NMEAGPS(); -#endif - gps->setup(); - } + gps = createGps(); if (gps) gpsStatus->observe(&gps->newStatus); @@ -468,8 +460,8 @@ void setup() // We have now loaded our saved preferences from flash // ONCE we will factory reset the GPS for bug #327 - if (ublox && !devicestate.did_gps_reset) { - if (ublox->factoryReset()) { // If we don't succeed try again next time + if (gps && !devicestate.did_gps_reset) { + if (gps->factoryReset()) { // If we don't succeed try again next time devicestate.did_gps_reset = true; nodeDB.saveToDisk(); } diff --git a/src/mesh/SX1262Interface.cpp b/src/mesh/SX1262Interface.cpp index 0bff47365..a99787475 100644 --- a/src/mesh/SX1262Interface.cpp +++ b/src/mesh/SX1262Interface.cpp @@ -34,11 +34,11 @@ bool SX1262Interface::init() pinMode(SX1262_TXEN, OUTPUT); #endif -#ifndef SX1262_E22 +#if !defined(SX1262_E22) && !defined(SX1262_USE_DIO3_FOR_TCXO) float tcxoVoltage = 0; // None - we use an XTAL #else - float tcxoVoltage = - 1.8; // E22 uses DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575 + // Use DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575 + float tcxoVoltage = 1.8; #endif bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC? diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index 35093ff17..53edd136d 100644 --- a/src/nrf52/NRF52Bluetooth.cpp +++ b/src/nrf52/NRF52Bluetooth.cpp @@ -3,8 +3,8 @@ #include "configuration.h" #include "main.h" #include - - +#include "mesh/mesh-pb-constants.h" +#include "mesh/PhoneAPI.h" static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16)); static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16)); @@ -213,6 +213,7 @@ void NRF52Bluetooth::setup() { // Initialise the Bluefruit module DEBUG_MSG("Initialise the Bluefruit nRF52 module\n"); + Bluefruit.autoConnLed(false); Bluefruit.begin(); // Set the advertised device name (keep it short!) diff --git a/src/nrf52/main-nrf52.cpp b/src/nrf52/main-nrf52.cpp index a1a96f3b9..d35b4269b 100644 --- a/src/nrf52/main-nrf52.cpp +++ b/src/nrf52/main-nrf52.cpp @@ -1,6 +1,5 @@ #include "NRF52Bluetooth.h" #include "configuration.h" -#include "graphics/TFTDisplay.h" #include #include #include @@ -118,10 +117,15 @@ void cpuDeepSleep(uint64_t msecToWake) { // FIXME, configure RTC or button press to wake us // FIXME, power down SPI, I2C, RAMs + #if WIRE_INTERFACES_COUNT > 0 Wire.end(); + #endif SPI.end(); Serial.end(); + + #ifdef PIN_SERIAL_RX1 Serial1.end(); + #endif // FIXME, use system off mode with ram retention for key state? // FIXME, use non-init RAM per diff --git a/variants/lora_isp4520/variant.cpp b/variants/lora_isp4520/variant.cpp new file mode 100644 index 000000000..cf1320f4f --- /dev/null +++ b/variants/lora_isp4520/variant.cpp @@ -0,0 +1,52 @@ +/* + 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 +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + 25, // D0 SPI_MISO + 24, // D1 SPI_NSS + 23, // D2 SPI_SCK + 4, // D3 VBAT + 11, // D4 DIO1 + 27, // D5 BUSY + 19, // D6 NRESET + 12, // D7 BUTTON2 + 22, // D8 BUTTON3 + 26, // D9 SPI_MOSI + 31, // D10 UART_RX + 2, // D11 UART_TX + 10, // D12 LED1 GREEN + 17, // D13 LED2 RED + 9, // D14 BUZZER + 7, // D15 BUTTON1 +}; + +#include +void initVariant() +{ + for (int i : {PIN_LED1, PIN_LED2}) { + pinMode(i, OUTPUT); + ledOff(i); + } +} diff --git a/variants/lora_isp4520/variant.h b/variants/lora_isp4520/variant.h new file mode 100644 index 000000000..a5b38fde8 --- /dev/null +++ b/variants/lora_isp4520/variant.h @@ -0,0 +1,98 @@ +/* + 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 +*/ + +#ifndef _VARIANT_LORA_ISP4520_ +#define _VARIANT_LORA_ISP4520_ + +#define HW_VERSION_US +#undef HW_VERSION +#define HW_VERSION "0.1.0" +#undef HW_VENDOR +#define HW_VENDOR "lora_ISP4520" + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#define USE_LFXO + +#define USE_SEGGER + +// Number of pins defined in PinDescription array +#define PINS_COUNT (16) +#define NUM_DIGITAL_PINS (16) +#define NUM_ANALOG_INPUTS (1) +#define NUM_ANALOG_OUTPUTS (1) + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 1 + +// These are in arduino pin numbers, +// translation in g_ADigitalPinMap in variants.cpp +#define PIN_SPI_MISO (0) +#define PIN_SPI_MOSI (9) +#define PIN_SPI_SCK (2) + +/* + * Wire Interfaces (I2C) + */ +#define WIRE_INTERFACES_COUNT 0 + +// GPIOs the SX1262 is connected +#define SX1262_CS 1 // aka SPI_NSS +#define SX1262_DIO1 (4) +#define SX1262_BUSY (5) +#define SX1262_RESET (6) + +/* + * Serial interfaces + */ +#define PIN_SERIAL_RX (10) +#define PIN_SERIAL_TX (11) +// LEDs +#define PIN_LED1 (12) +#define PIN_LED2 (13) +#define PIN_BUZZER (14) + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_RED PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_STATE_ON 1 // State when LED is litted + +/* + * Buttons + */ +#define PIN_BUTTON1 (15) +#define PIN_BUTTON2 (7) +#define PIN_BUTTON3 (8) + +// ADC pin and voltage divider +#define BATTERY_PIN 3 +#define ADC_MULTIPLIER 1.436 + +#define SX1262_USE_DIO3_FOR_TCXO +#define NO_GPS +#define NO_SCREEN +#endif