diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8b7b4592c..9ef8f77c6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -7,7 +7,7 @@ is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc... - Please do not check in files that don't have real changes - Please do not reformat lines that you didn't have to change the code on -- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor, +- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor and the 'clang-format' extension, because automatically follows our indentation rules and it's auto reformatting will not cause spurious changes to lines. - If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description. - If your other co-developers have comments on your PR please tweak as needed. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 585775e48..b01111fd9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,10 +15,10 @@ jobs: uses: actions/setup-python@v2 with: python-version: 3.x - - name: Install Platform IO + - name: Install Platform IO and meshtastic-python run: | python -m pip install --upgrade pip - pip install -U platformio + pip install -U platformio meshtastic - name: Install extra python tools run: | pip install -U adafruit-nrfutil @@ -31,6 +31,11 @@ jobs: run: platformio run -e heltec - name: Build for lora-relay-v1 run: platformio run -e lora-relay-v1 - # Turn off linux for now - name: Build for native + - name: Build for native run: platformio run -e native + - name: Integration test + run: | + .pio/build/native/program & + sleep 1 + python3 -c 'from meshtastic.test import testSimulator; testSimulator()' + diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0f0d7401d..27bdd05a2 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,6 +2,7 @@ // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ - "platformio.platformio-ide" + "platformio.platformio-ide", + "xaver.clang-format" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index b89870c5b..5ce21fa35 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -77,5 +77,6 @@ "--java_out=/tmp", "-I=/home/kevinh/development/meshtastic/meshtastic-esp32/proto" ] - } + }, + "editor.formatOnSave": true } \ No newline at end of file diff --git a/bin/program-1.0-tbeam.sh b/bin/program-1.0-tbeam.sh new file mode 100755 index 000000000..b2b37756b --- /dev/null +++ b/bin/program-1.0-tbeam.sh @@ -0,0 +1,3 @@ +esptool.py --baud 921600 write_flash 0x10000 release/archive/old/firmware-tbeam-EU865-1.0.0.bin +echo "Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used" +esptool.py --baud 921600 erase_region 0xe000 0x2000 diff --git a/bin/program-1.1-tbeam.sh b/bin/program-1.1-tbeam.sh index 9b95c3380..98ba5c682 100755 --- a/bin/program-1.1-tbeam.sh +++ b/bin/program-1.1-tbeam.sh @@ -1 +1 @@ -esptool.py --baud 921600 write_flash 0x10000 release/archive/firmware-tbeam-1.1.50.bin +esptool.py --baud 921600 write_flash 0x10000 release/archive/old/firmware-tbeam-1.1.50.bin 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/docs/software/TODO.md b/docs/software/TODO.md index c65a53658..7ffe9361f 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -2,16 +2,26 @@ You probably don't care about this section - skip to the next one. +## before next release + +* DONE timestamps on oled screen are wrong - don't seem to be updating based on message rx (actually: this is expected behavior when no node on the mesh has GPS time) +* DONE add ch-del +* DONE channel hash suffixes are wrong on android +* DONE before next relase: test empty channel sets on android +* DONE channel sharing in android +* DONE test 1.0 firmware update on android +* DONE test 1.1 firmware update on android +* test 1.2.10 firmware update on android +* DONE test link sharing on android +* luxon bug report - seeing rx acks for nodes that are not on the network +* document how to do remote admin +* release py, android, device + ## 1.2 cleanup & multichannel support: -* before next relase: test empty channel sets on android -* test link sharing on android - * DONE cleanup the external notification and serial plugins * non ack version of stress test fails sometimes! -* timestamps on oled screen are wrong - don't seem to be updating based on message rx -* luxon bug report - seeing rx acks for nodes that are not on the network -* channel hash suffixes are wrong on android + * tx fault test has a bug #734 * DONE move device types into an enum in nodeinfo * fix android to use new device types for firmware update diff --git a/platformio.ini b/platformio.ini index 3965c848b..f2142b8e4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -;default_envs = tbeam +default_envs = tbeam ;default_envs = tbeam0.7 ;default_envs = heltec ;default_envs = tlora-v1 @@ -17,7 +17,7 @@ ;default_envs = lora-relay-v1 # nrf board ;default_envs = eink ;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 = 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 [common] ; common is not currently used @@ -39,7 +39,7 @@ extra_scripts = bin/platformio-custom.py ; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc build_flags = -Wno-missing-field-initializers -Wno-format - -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map + -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Isrc/buzz -Wl,-Map,.pio/build/output.map -DHW_VERSION_${sysenv.COUNTRY} -DHW_VERSION=${sysenv.HW_VERSION} -DUSE_THREAD_NAMES @@ -232,6 +232,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/proto b/proto index 39bb8b26b..b8c0499f2 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 39bb8b26bbc107aae3586d5a5e11a06ea12680bc +Subproject commit b8c0499f28f9673d1df17d04da562e30703f01cb diff --git a/src/Power.cpp b/src/Power.cpp index f4aa700a4..61533887c 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 isChargeing() { 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 } @@ -93,7 +129,9 @@ class AnalogBatteryLevel : public HasBatteryLevel 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 } diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 09fc35e6c..1303329e5 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 4c460d77f..0bb2864e2 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -4,49 +4,49 @@ #include #include #include +#include "RTC.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_PutChar(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; + 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 >= (int)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 @@ -68,9 +68,9 @@ size_t RedirectablePrint::logDebug(const char *format, ...) // 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; + 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) @@ -102,5 +102,5 @@ size_t RedirectablePrint::logDebug(const char *format, ...) inDebugPrint = false; } - 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..a667df004 --- /dev/null +++ b/src/buzz/buzz.cpp @@ -0,0 +1,66 @@ +#include "buzz.h" +#include "configuration.h" + +#ifdef NRF52_SERIES +#include "variant.h" +#endif + +#ifndef PIN_BUZZER + +// Noop methods for boards w/o buzzer +void playBeep(){}; +void playStartMelody(){}; +void playShutdownMelody(){}; + +#else +#include "Tone.h" + +extern "C" void delay(uint32_t dwMs); + +struct ToneDuration { + int frequency_khz; + int duration_ms; +}; + +// Some common frequencies. +#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 + +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/configuration.h b/src/configuration.h index e389e46cf..3d4fb652d 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -338,7 +338,7 @@ along with this program. If not, see . #elif defined(TLORA_V2_1_16) // This string must exactly match the case used in release file names or the android updater won't work -#define HW_VENDOR HardwareModel_TLORA_V2_1p6_ +#define HW_VENDOR HardwareModel_TLORA_V2_1_1p6 #undef GPS_RX_PIN #undef GPS_TX_PIN @@ -382,8 +382,8 @@ along with this program. If not, see . #define LED_PIN 12 // If defined we will blink this LED //#define BUTTON_PIN 36 // If defined, this will be used for user button presses (ToDo problem on that line on debug screen --> -//Long press start!) #define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs – input only pins. These pins don’t have internal -//pull-ups or pull-down resistors. +// Long press start!) #define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs – input only pins. These pins don’t have internal +// pull-ups or pull-down resistors. #define USE_RF95 #define LORA_DIO0 38 // a No connect on the SX1262 module @@ -459,6 +459,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 abf7fc270..c5c30fcb9 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -308,3 +308,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 9d25b2f83..6de72f29c 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..87b73ce89 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -42,19 +42,20 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv) } 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 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 9be119a48..65e7b0a12 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 0d2997165..6a4caf330 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" @@ -67,7 +67,7 @@ Router *router = NULL; // Users of router don't care what sort of subclass imple // ----------------------------------------------------------------------------- // Application // ----------------------------------------------------------------------------- - +#ifndef NO_WIRE void scanI2Cdevice(void) { byte err, addr; @@ -104,6 +104,9 @@ void scanI2Cdevice(void) else DEBUG_MSG("done\n"); } +#else +void scanI2Cdevice(void) {} +#endif const char *getDeviceName() { @@ -173,7 +176,7 @@ class ButtonThread : public OSThread #ifdef BUTTON_PIN_ALT OneButton userButtonAlt; #endif - + static bool shutdown_on_long_stop; public: static uint32_t longPressTime; @@ -239,13 +242,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)); @@ -269,9 +282,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; @@ -345,7 +364,7 @@ void setup() #ifdef I2C_SDA Wire.begin(I2C_SDA, I2C_SCL); -#else +#elif !defined(NO_WIRE) Wire.begin(); #endif @@ -382,7 +401,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(); @@ -420,34 +439,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); @@ -481,8 +473,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/MeshPlugin.h b/src/mesh/MeshPlugin.h index dc905a0e5..2295d1224 100644 --- a/src/mesh/MeshPlugin.h +++ b/src/mesh/MeshPlugin.h @@ -1,9 +1,13 @@ #pragma once #include "mesh/MeshTypes.h" +#include + +#ifndef NO_SCREEN #include #include -#include +#endif + /** A baseclass for any mesh "plugin". * * A plugin allows you to add new features to meshtastic device code, without needing to know messaging details. @@ -31,9 +35,9 @@ class MeshPlugin static void callPlugins(const MeshPacket &mp); static std::vector GetMeshPluginsWithUIFrames(); - +#ifndef NO_SCREEN virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; } - +#endif protected: const char *name; diff --git a/src/mesh/SX1262Interface.cpp b/src/mesh/SX1262Interface.cpp index 0bff47365..7d4046731 100644 --- a/src/mesh/SX1262Interface.cpp +++ b/src/mesh/SX1262Interface.cpp @@ -37,8 +37,8 @@ bool SX1262Interface::init() #ifndef SX1262_E22 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/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h index d68103cea..cf71a9cb2 100644 --- a/src/mesh/generated/admin.pb.h +++ b/src/mesh/generated/admin.pb.h @@ -25,6 +25,7 @@ typedef struct _AdminMessage { Channel get_channel_response; bool confirm_set_channel; bool confirm_set_radio; + bool exit_simulator; }; } AdminMessage; @@ -47,6 +48,7 @@ extern "C" { #define AdminMessage_get_channel_response_tag 7 #define AdminMessage_confirm_set_channel_tag 32 #define AdminMessage_confirm_set_radio_tag 33 +#define AdminMessage_exit_simulator_tag 34 /* Struct field encoding specification for nanopb */ #define AdminMessage_FIELDLIST(X, a) \ @@ -58,7 +60,8 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,get_radio_response,get_radio_respons X(a, STATIC, ONEOF, UINT32, (variant,get_channel_request,get_channel_request), 6) \ X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7) \ X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_channel,confirm_set_channel), 32) \ -X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) +X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) \ +X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34) #define AdminMessage_CALLBACK NULL #define AdminMessage_DEFAULT NULL #define AdminMessage_variant_set_radio_MSGTYPE RadioConfig diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp index 244918e93..bcd74e10c 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 1ba0602b9..e5a4aadf7 100644 --- a/src/nrf52/main-nrf52.cpp +++ b/src/nrf52/main-nrf52.cpp @@ -1,7 +1,3 @@ -#include "NRF52Bluetooth.h" -#include "configuration.h" -#include "error.h" -#include "graphics/TFTDisplay.h" #include #include #include @@ -9,179 +5,182 @@ #include #include -#ifdef NRF52840_XXAA -// #include +#include "NRF52Bluetooth.h" +#include "configuration.h" +#include "error.h" + +#ifdef BQ25703A_ADDR +#include "BQ25713.h" #endif -// #define USE_SOFTDEVICE -static inline void debugger_break(void) -{ - __asm volatile("bkpt #0x01\n\t" - "mov pc, lr\n\t"); +static inline void debugger_break(void) { + __asm volatile( + "bkpt #0x01\n\t" + "mov pc, lr\n\t"); } // handle standard gcc assert failures -void __attribute__((noreturn)) __assert_func(const char *file, int line, const char *func, const char *failedexpr) -{ - DEBUG_MSG("assert failed %s: %d, %s, test=%s\n", file, line, func, failedexpr); - // debugger_break(); FIXME doesn't work, possibly not for segger - while (1) - ; // FIXME, reboot! +void __attribute__((noreturn)) +__assert_func(const char *file, int line, const char *func, + const char *failedexpr) { + DEBUG_MSG("assert failed %s: %d, %s, test=%s\n", file, line, func, + failedexpr); + // debugger_break(); FIXME doesn't work, possibly not for segger + while (1) + ; // FIXME, reboot! } -void getMacAddr(uint8_t *dmac) -{ - ble_gap_addr_t addr; - -#ifdef USE_SOFTDEVICE - uint32_t res = sd_ble_gap_addr_get(&addr); - assert(res == NRF_SUCCESS); +void getMacAddr(uint8_t *dmac) { + ble_gap_addr_t addr; + if (sd_ble_gap_addr_get(&addr) == NRF_SUCCESS) { memcpy(dmac, addr.addr, 6); -#else + } else { const uint8_t *src = (const uint8_t *)NRF_FICR->DEVICEADDR; dmac[5] = src[0]; dmac[4] = src[1]; dmac[3] = src[2]; dmac[2] = src[3]; dmac[1] = src[4]; - dmac[0] = src[5] | 0xc0; // MSB high two bits get set elsewhere in the bluetooth stack -#endif + dmac[0] = src[5] | + 0xc0; // MSB high two bits get set elsewhere in the bluetooth stack + } } NRF52Bluetooth *nrf52Bluetooth; static bool bleOn = false; -static const bool useSoftDevice = false; // Set to false for easier debugging +static const bool useSoftDevice = true; // Set to false for easier debugging -void setBluetoothEnable(bool on) -{ - if (on != bleOn) { - if (on) { - if (!nrf52Bluetooth) { - if (!useSoftDevice) - DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n"); - else { - nrf52Bluetooth = new NRF52Bluetooth(); - nrf52Bluetooth->setup(); - } - } - } else { - if (nrf52Bluetooth) - nrf52Bluetooth->shutdown(); +void setBluetoothEnable(bool on) { + if (on != bleOn) { + if (on) { + if (!nrf52Bluetooth) { + if (!useSoftDevice) + DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n"); + else { + nrf52Bluetooth = new NRF52Bluetooth(); + nrf52Bluetooth->setup(); } - bleOn = on; + } + } else { + if (nrf52Bluetooth) nrf52Bluetooth->shutdown(); } + bleOn = on; + } } /** * Override printf to use the SEGGER output library */ -int printf(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - auto res = SEGGER_RTT_vprintf(0, fmt, &args); - va_end(args); - return res; +int printf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + auto res = SEGGER_RTT_vprintf(0, fmt, &args); + va_end(args); + return res; } -#include "BQ25713.h" +void initBrownout() { + auto vccthresh = POWER_POFCON_THRESHOLD_V28; -void initBrownout() -{ - auto vccthresh = POWER_POFCON_THRESHOLD_V28; + if (useSoftDevice) { + auto err_code = sd_power_pof_enable(POWER_POFCON_POF_Enabled); + assert(err_code == NRF_SUCCESS); + + err_code = sd_power_pof_threshold_set(vccthresh); + assert(err_code == NRF_SUCCESS); + } else { + uint32_t pof_flags = POWER_POFCON_POF_Enabled | (vccthresh << POWER_POFCON_THRESHOLD_Pos); + + #ifdef POWER_POFCON_THRESHOLDVDDH_Msk auto vcchthresh = POWER_POFCON_THRESHOLDVDDH_V27; - - if (useSoftDevice) { - auto err_code = sd_power_pof_enable(POWER_POFCON_POF_Enabled); - assert(err_code == NRF_SUCCESS); - - err_code = sd_power_pof_threshold_set(vccthresh); - assert(err_code == NRF_SUCCESS); - } - else { - NRF_POWER->POFCON = POWER_POFCON_POF_Msk | (vccthresh << POWER_POFCON_THRESHOLD_Pos) | (vcchthresh << POWER_POFCON_THRESHOLDVDDH_Pos); - } + pof_flags |= (vcchthresh << POWER_POFCON_THRESHOLDVDDH_Pos); + #endif + + NRF_POWER->POFCON = pof_flags; + } } -void checkSDEvents() -{ - if (useSoftDevice) { - uint32_t evt; - while (NRF_ERROR_NOT_FOUND == sd_evt_get(&evt)) { - switch (evt) { - case NRF_EVT_POWER_FAILURE_WARNING: - recordCriticalError(CriticalErrorCode_Brownout); - break; +void checkSDEvents() { + if (useSoftDevice) { + uint32_t evt; + while (NRF_SUCCESS == sd_evt_get(&evt)) { + switch (evt) { + case NRF_EVT_POWER_FAILURE_WARNING: + recordCriticalError(CriticalErrorCode_Brownout); + break; - default: - DEBUG_MSG("Unexpected SDevt %d\n", evt); - break; - } - } - } else { - if(NRF_POWER->EVENTS_POFWARN) - recordCriticalError(CriticalErrorCode_Brownout); + default: + DEBUG_MSG("Unexpected SDevt %d\n", evt); + break; + } } + } else { + if (NRF_POWER->EVENTS_POFWARN) + recordCriticalError(CriticalErrorCode_Brownout); + } } -void nrf52Loop() -{ - checkSDEvents(); -} +void nrf52Loop() { checkSDEvents(); } -void nrf52Setup() -{ +void nrf52Setup() { + auto why = NRF_POWER->RESETREAS; + // per + // https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpower.html + DEBUG_MSG("Reset reason: 0x%x\n", why); - auto why = NRF_POWER->RESETREAS; - // per https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpower.html - DEBUG_MSG("Reset reason: 0x%x\n", why); - - // Per https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/monitor-mode-debugging-with-j-link-and-gdbeclipse - // This is the recommended setting for Monitor Mode Debugging - NVIC_SetPriority(DebugMonitor_IRQn, 6UL); + // Per + // https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/monitor-mode-debugging-with-j-link-and-gdbeclipse + // This is the recommended setting for Monitor Mode Debugging + NVIC_SetPriority(DebugMonitor_IRQn, 6UL); #ifdef BQ25703A_ADDR - auto *bq = new BQ25713(); - if (!bq->setup()) - DEBUG_MSG("ERROR! Charge controller init failed\n"); + auto *bq = new BQ25713(); + if (!bq->setup()) DEBUG_MSG("ERROR! Charge controller init failed\n"); #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"); + // 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"); - initBrownout(); + initBrownout(); } -void cpuDeepSleep(uint64_t msecToWake) -{ - // FIXME, configure RTC or button press to wake us - // FIXME, power down SPI, I2C, RAMs - Wire.end(); - SPI.end(); - Serial.end(); - Serial1.end(); +void cpuDeepSleep(uint64_t msecToWake) { + // FIXME, configure RTC or button press to wake us + // FIXME, power down SPI, I2C, RAMs +#ifndef NO_WIRE + Wire.end(); +#endif + SPI.end(); + // This may cause crashes as debug messages continue to flow. + Serial.end(); - // FIXME, use system off mode with ram retention for key state? - // FIXME, use non-init RAM per - // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled +#ifdef PIN_SERIAL_RX1 + Serial1.end(); +#endif + setBluetoothEnable(false); + // FIXME, use system off mode with ram retention for key state? + // FIXME, use non-init RAM per + // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled - auto ok = sd_power_system_off(); - if (ok != NRF_SUCCESS) { - DEBUG_MSG("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n"); - NRF_POWER->SYSTEMOFF = 1; - } + auto ok = sd_power_system_off(); + if (ok != NRF_SUCCESS) { + DEBUG_MSG( + "FIXME: Ignoring soft device (EasyDMA pending?) and forcing " + "system-off!\n"); + NRF_POWER->SYSTEMOFF = 1; + } - // The following code should not be run, because we are off - while (1) { - delay(5000); - DEBUG_MSG("."); - } + // The following code should not be run, because we are off + while (1) { + delay(5000); + DEBUG_MSG("."); + } } \ No newline at end of file diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp index 96b5c51a0..65c901121 100644 --- a/src/plugins/AdminPlugin.cpp +++ b/src/plugins/AdminPlugin.cpp @@ -6,6 +6,10 @@ #include "configuration.h" #include "main.h" +#ifdef PORTDUINO +#include "unistd.h" +#endif + AdminPlugin *adminPlugin; void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex) @@ -51,7 +55,7 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag break; case AdminMessage_set_channel_tag: - DEBUG_MSG("Client is setting channel\n"); + DEBUG_MSG("Client is setting channel %d\n", r->set_channel.index); handleSetChannel(r->set_channel); break; @@ -65,6 +69,13 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag handleGetRadio(mp); break; +#ifdef PORTDUINO + case AdminMessage_exit_simulator_tag: + DEBUG_MSG("Exiting simulator\n"); + _exit(0); + break; +#endif + default: // Probably a message sent by us or sent to our local node. FIXME, we should avoid scanning these messages DEBUG_MSG("Ignoring nonrelevant admin %d\n", r->which_variant); @@ -102,8 +113,7 @@ void AdminPlugin::handleSetChannel(const Channel &cc) if (cc.index == 0) { // FIXME, this updates the user preferences also, which isn't needed - we really just want to notify on configChanged service.reloadConfig(); - } - else { + } else { channels.onConfigChanged(); // tell the radios about this change nodeDB.saveChannelsToDisk(); } 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..9bf5cd502 --- /dev/null +++ b/variants/lora_isp4520/variant.h @@ -0,0 +1,99 @@ +/* + 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 1 +#undef HW_VERSION +#define HW_VERSION "1.0" + +#define USE_SEGGER +/*---------------------------------------------------------------------------- + * 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_E22 // Not really an E22 but this board clones using DIO3 for tcxo control + +#define NO_WIRE +#define NO_GPS +#define NO_SCREEN +#endif diff --git a/version.properties b/version.properties index e615e8b4b..565c90526 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 10 +build = 11