diff --git a/.vscode/settings.json b/.vscode/settings.json index e6f1d49e..9b72a2a2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -48,7 +48,8 @@ "optional": "cpp", "string_view": "cpp", "cassert": "cpp", - "iterator": "cpp" + "iterator": "cpp", + "shared_mutex": "cpp" }, "cSpell.words": [ "Blox", diff --git a/platformio.ini b/platformio.ini index 1069f8e0..6ef76e7d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = tbeam # or if you'd like to change the default to something like lora-relay-v1 put that here +default_envs = tbeam # 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 @@ -23,15 +23,9 @@ default_envs = tbeam # or if you'd like to change the default to something like [env] -framework = arduino - -; customize the partition table -; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables -board_build.partitions = partition-table.csv - ; 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 -Os -Wl,-Map,.pio/build/output.map +build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map -DHW_VERSION_${sysenv.COUNTRY} -DAPP_VERSION=${sysenv.APP_VERSION} -DHW_VERSION=${sysenv.HW_VERSION} @@ -60,25 +54,38 @@ debug_tool = jlink lib_deps = https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306 - SPI 1260 ; OneButton library for non-blocking button debounce 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib - Wire ; explicitly needed here because the AXP202 library forgets to add it https://github.com/meshtastic/arduino-fsm.git https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git https://github.com/meshtastic/RadioLib.git#7989a269be590a5d4914ac04069b58f4930c45c1 https://github.com/meshtastic/TinyGPSPlus.git https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460 + Wire ; explicitly needed here because the AXP202 library forgets to add it + SPI + +; Common settings for conventional (non Portduino) Ardino targets +[arduino_base] + +framework = arduino + +lib_deps = + ${env.lib_deps} + +build_flags = ${env.build_flags} -Os + +src_filter = ${env.src_filter} - ; Common settings for ESP targes, mixin with extends = esp32_base [esp32_base] +extends = arduino_base platform = espressif32 src_filter = - ${env.src_filter} - + ${arduino_base.src_filter} - upload_speed = 921600 debug_init_break = tbreak setup build_flags = - ${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue -lnimble -std=c++11 + ${arduino_base.build_flags} -Wall -Wextra -Isrc/esp32 -Isrc/esp32-mfix-esp32-psram-cache-issue -lnimble -std=c++11 -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG -DAXP_DEBUG_PORT=Serial # Hmm - this doesn't work yet @@ -87,6 +94,10 @@ lib_ignore = segger_rtt platform_packages = framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#2814f110aa618429bdd9a0a2d6a93c55f29f87a6 +; customize the partition table +; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables +board_build.partitions = partition-table.csv + ; not needed included in ttgo-t-beam board file ; also to use PSRAM https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram ; -DBOARD_HAS_PSRAM @@ -99,7 +110,7 @@ platform_packages = extends = esp32_base board = ttgo-t-beam lib_deps = - ${env.lib_deps} + ${arduino_base.lib_deps} build_flags = ${esp32_base.build_flags} -D TBEAM_V10 @@ -142,25 +153,26 @@ build_flags = platform = https://github.com/HelTecAutomation/platform-asrmicro650x.git ; we use top-of-tree because stable version has too many bugs - asrmicro650x board = cubecell_board_plus ; FIXME, bug in cubecell arduino - they are supposed to set ARDUINO -build_flags = ${env.build_flags} -DARDUINO=100 -Isrc/cubecell +build_flags = ${arduino_base.build_flags} -DARDUINO=100 -Isrc/cubecell src_filter = - ${env.src_filter} - - + ${arduino_base.src_filter} - - ; Common settings for NRF52 based targets [nrf52_base] ; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files ; platform = nordicnrf52 platform = https://github.com/meshtastic/platform-nordicnrf52.git#1a2639a6b0f79b5df66bea3e3089f0d5285fdc63 +extends = arduino_base debug_tool = jlink 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 = - ${env.build_flags} -Wno-unused-variable + ${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.3 ;-DCFG_DEBUG=3 src_filter = - ${env.src_filter} - - + ${arduino_base.src_filter} - - lib_ignore = BluetoothOTA monitor_port = /dev/ttyACM1 @@ -212,7 +224,7 @@ monitor_speed = 115200 extends = nrf52_base board = ppr lib_deps = - ${env.lib_deps} + ${arduino_base.lib_deps} UC1701 ; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus @@ -233,11 +245,15 @@ build_flags = ${nrf52_base.build_flags} -Ivariants/lora_relay_v1 -DSPI_FREQUENCY=27000000 src_filter = ${nrf52_base.src_filter} +<../variants/lora_relay_v1> lib_deps = - ${env.lib_deps} + ${arduino_base.lib_deps} SparkFun BQ27441 LiPo Fuel Gauge Arduino Library TFT_eSPI # Adafruit ST7735 and ST7789 Library - - - +; The Portduino based sim environment on top of linux +[env:linux] +platform = https://github.com/geeksville/platform-portduino.git +src_filter = ${env.src_filter} - - - +build_flags = ${arduino_base.build_flags} -O0 +framework = arduino +board = linux_x86_64 diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 80580fd0..128947bc 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -8,7 +8,6 @@ #include "graphics/Screen.h" #include "sleep.h" #include "target_specific.h" -#include "timing.h" static void sdsEnter() { @@ -16,7 +15,7 @@ static void sdsEnter() // Don't deepsleep if we have USB power or if the user as pressed a button recently // !isUSBPowered <- doesn't work yet because the axp192 isn't letting the battery fully charge when we are awake - FIXME - if (timing::millis() - lastPressMs > radioConfig.preferences.mesh_sds_timeout_secs) + if (millis() - lastPressMs > radioConfig.preferences.mesh_sds_timeout_secs) { doDeepSleep(radioConfig.preferences.sds_secs); } @@ -131,7 +130,7 @@ static void onEnter() static uint32_t lastPingMs; - uint32_t now = timing::millis(); + uint32_t now = millis(); if (now - lastPingMs > 30 * 1000) { // if more than a minute since our last press, ask other nodes to update their state if (displayedNodeNum) diff --git a/src/concurrency/BaseNotifiedWorkerThread.h b/src/concurrency/BaseNotifiedWorkerThread.h new file mode 100644 index 00000000..03b82c4b --- /dev/null +++ b/src/concurrency/BaseNotifiedWorkerThread.h @@ -0,0 +1,44 @@ +#pragma once + +#include "WorkerThread.h" + +namespace concurrency { + +/** + * @brief A worker thread that waits on a freertos notification + */ +class BaseNotifiedWorkerThread : public WorkerThread +{ + public: + /** + * Notify this thread so it can run + */ + virtual void notify(uint32_t v = 0, eNotifyAction action = eNoAction) = 0; + + /** + * Notify from an ISR + * + * This must be inline or IRAM_ATTR on ESP32 + */ + virtual void notifyFromISR(BaseType_t *highPriWoken, uint32_t v = 0, eNotifyAction action = eNoAction) { notify(v, action); } + + protected: + /** + * The notification that was most recently used to wake the thread. Read from loop() + */ + uint32_t notification = 0; + + /** + * What notification bits should be cleared just after we read and return them in notification? + * + * Defaults to clear all of them. + */ + uint32_t clearOnRead = UINT32_MAX; + + /** + * A method that should block execution - either waiting ona queue/mutex or a "task notification" + */ + virtual void block() = 0; +}; + +} // namespace concurrency diff --git a/src/concurrency/BaseThread.cpp b/src/concurrency/BaseThread.cpp new file mode 100644 index 00000000..ab39a8c9 --- /dev/null +++ b/src/concurrency/BaseThread.cpp @@ -0,0 +1,12 @@ +#include "Thread.h" +#include + +namespace concurrency +{ + +void BaseThread::callRun(void *_this) +{ + ((BaseThread *)_this)->doRun(); +} + +} // namespace concurrency diff --git a/src/concurrency/BaseThread.h b/src/concurrency/BaseThread.h new file mode 100644 index 00000000..b1947cf4 --- /dev/null +++ b/src/concurrency/BaseThread.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +#include "freertosinc.h" + +namespace concurrency +{ + +/** + * @brief Base threading + */ +class BaseThread +{ + protected: + /** + * set this to true to ask thread to cleanly exit asap + */ + volatile bool wantExit = false; + + public: + virtual void start(const char *name, size_t stackSize = 1024, uint32_t priority = tskIDLE_PRIORITY) = 0; + + virtual ~BaseThread() {} + + // uint32_t getStackHighwaterMark() { return uxTaskGetStackHighWaterMark(taskHandle); } + + protected: + /** + * The method that will be called when start is called. + */ + virtual void doRun() = 0; + + /** + * All thread run methods must periodically call serviceWatchdog, or the system will declare them hung and panic. + * + * this only applies after startWatchdog() has been called. If you need to sleep for a long time call stopWatchdog() + */ + virtual void serviceWatchdog() {} + virtual void startWatchdog() {} + virtual void stopWatchdog() {} + + static void callRun(void *_this); +}; + +} // namespace concurrency diff --git a/src/concurrency/NotifiedWorkerThread.cpp b/src/concurrency/FreeRtosNotifiedWorkerThread.cpp similarity index 70% rename from src/concurrency/NotifiedWorkerThread.cpp rename to src/concurrency/FreeRtosNotifiedWorkerThread.cpp index 7785ecf8..8fec432d 100644 --- a/src/concurrency/NotifiedWorkerThread.cpp +++ b/src/concurrency/FreeRtosNotifiedWorkerThread.cpp @@ -1,19 +1,23 @@ #include "NotifiedWorkerThread.h" +#ifdef HAS_FREE_RTOS + namespace concurrency { /** * Notify this thread so it can run */ -void NotifiedWorkerThread::notify(uint32_t v, eNotifyAction action) +void FreeRtosNotifiedWorkerThread::notify(uint32_t v, eNotifyAction action) { xTaskNotify(taskHandle, v, action); } -void NotifiedWorkerThread::block() +void FreeRtosNotifiedWorkerThread::block() { xTaskNotifyWait(0, // don't clear notification on entry clearOnRead, ¬ification, portMAX_DELAY); // Wait forever } } // namespace concurrency + +#endif \ No newline at end of file diff --git a/src/concurrency/FreeRtosNotifiedWorkerThread.h b/src/concurrency/FreeRtosNotifiedWorkerThread.h new file mode 100644 index 00000000..c18009e4 --- /dev/null +++ b/src/concurrency/FreeRtosNotifiedWorkerThread.h @@ -0,0 +1,40 @@ +#pragma once + +#include "BaseNotifiedWorkerThread.h" + +#ifdef HAS_FREE_RTOS + +namespace concurrency { + +/** + * @brief A worker thread that waits on a freertos notification + */ +class FreeRtosNotifiedWorkerThread : public BaseNotifiedWorkerThread +{ + public: + /** + * Notify this thread so it can run + */ + void notify(uint32_t v = 0, eNotifyAction action = eNoAction); + + /** + * Notify from an ISR + * + * This must be inline or IRAM_ATTR on ESP32 + */ + inline void notifyFromISR(BaseType_t *highPriWoken, uint32_t v = 0, eNotifyAction action = eNoAction) + { + xTaskNotifyFromISR(taskHandle, v, action, highPriWoken); + } + + protected: + + /** + * A method that should block execution - either waiting ona queue/mutex or a "task notification" + */ + virtual void block(); +}; + +} // namespace concurrency + +#endif \ No newline at end of file diff --git a/src/concurrency/Thread.cpp b/src/concurrency/FreeRtosThread.cpp similarity index 65% rename from src/concurrency/Thread.cpp rename to src/concurrency/FreeRtosThread.cpp index 1e1c7bb6..1fe7108e 100644 --- a/src/concurrency/Thread.cpp +++ b/src/concurrency/FreeRtosThread.cpp @@ -1,5 +1,7 @@ -#include "Thread.h" -#include "timing.h" +#include "FreeRtosThread.h" + +#ifdef HAS_FREE_RTOS + #include #ifdef ARDUINO_ARCH_ESP32 @@ -9,25 +11,20 @@ namespace concurrency { -void Thread::start(const char *name, size_t stackSize, uint32_t priority) +void FreeRtosThread::start(const char *name, size_t stackSize, uint32_t priority) { auto r = xTaskCreate(callRun, name, stackSize, this, priority, &taskHandle); assert(r == pdPASS); } -void Thread::callRun(void *_this) -{ - ((Thread *)_this)->doRun(); -} - -void Thread::serviceWatchdog() +void FreeRtosThread::serviceWatchdog() { #ifdef ARDUINO_ARCH_ESP32 esp_task_wdt_reset(); #endif } -void Thread::startWatchdog() +void FreeRtosThread::startWatchdog() { #ifdef ARDUINO_ARCH_ESP32 auto r = esp_task_wdt_add(taskHandle); @@ -35,7 +32,7 @@ void Thread::startWatchdog() #endif } -void Thread::stopWatchdog() +void FreeRtosThread::stopWatchdog() { #ifdef ARDUINO_ARCH_ESP32 auto r = esp_task_wdt_delete(taskHandle); @@ -44,3 +41,5 @@ void Thread::stopWatchdog() } } // namespace concurrency + +#endif \ No newline at end of file diff --git a/src/concurrency/FreeRtosThread.h b/src/concurrency/FreeRtosThread.h new file mode 100644 index 00000000..6f52119d --- /dev/null +++ b/src/concurrency/FreeRtosThread.h @@ -0,0 +1,44 @@ +#pragma once + +#include "BaseThread.h" +#include "freertosinc.h" + +#ifdef HAS_FREE_RTOS + +namespace concurrency +{ + +/** + * @brief Base threading + */ +class FreeRtosThread : public BaseThread +{ + protected: + TaskHandle_t taskHandle = NULL; + + public: + void start(const char *name, size_t stackSize = 1024, uint32_t priority = tskIDLE_PRIORITY); + + virtual ~FreeRtosThread() { vTaskDelete(taskHandle); } + + // uint32_t getStackHighwaterMark() { return uxTaskGetStackHighWaterMark(taskHandle); } + + protected: + /** + * The method that will be called when start is called. + */ + virtual void doRun() = 0; + + /** + * All thread run methods must periodically call serviceWatchdog, or the system will declare them hung and panic. + * + * this only applies after startWatchdog() has been called. If you need to sleep for a long time call stopWatchdog() + */ + void serviceWatchdog(); + void startWatchdog(); + void stopWatchdog(); +}; + +} // namespace concurrency + +#endif \ No newline at end of file diff --git a/src/concurrency/Lock.cpp b/src/concurrency/Lock.cpp index 07f5a2ef..ffe997f8 100644 --- a/src/concurrency/Lock.cpp +++ b/src/concurrency/Lock.cpp @@ -1,8 +1,10 @@ #include "Lock.h" #include -namespace concurrency { +namespace concurrency +{ +#ifdef HAS_FREE_RTOS Lock::Lock() { handle = xSemaphoreCreateBinary(); @@ -19,5 +21,12 @@ void Lock::unlock() { assert(xSemaphoreGive(handle)); } +#else +Lock::Lock() {} + +void Lock::lock() {} + +void Lock::unlock() {} +#endif } // namespace concurrency diff --git a/src/concurrency/Lock.h b/src/concurrency/Lock.h index 09877cc2..1b9ea20d 100644 --- a/src/concurrency/Lock.h +++ b/src/concurrency/Lock.h @@ -2,7 +2,8 @@ #include "../freertosinc.h" -namespace concurrency { +namespace concurrency +{ /** * @brief Simple wrapper around FreeRTOS API for implementing a mutex lock @@ -26,8 +27,9 @@ class Lock void unlock(); private: +#ifdef HAS_FREE_RTOS SemaphoreHandle_t handle; - +#endif }; } // namespace concurrency diff --git a/src/concurrency/NotifiedWorkerThread.h b/src/concurrency/NotifiedWorkerThread.h index 5ab5a58e..dee92eb8 100644 --- a/src/concurrency/NotifiedWorkerThread.h +++ b/src/concurrency/NotifiedWorkerThread.h @@ -1,47 +1,17 @@ #pragma once -#include "WorkerThread.h" +#include "FreeRtosNotifiedWorkerThread.h" +#include "PosixNotifiedWorkerThread.h" -namespace concurrency { - -/** - * @brief A worker thread that waits on a freertos notification - */ -class NotifiedWorkerThread : public WorkerThread +namespace concurrency { - public: - /** - * Notify this thread so it can run - */ - void notify(uint32_t v = 0, eNotifyAction action = eNoAction); - /** - * Notify from an ISR - * - * This must be inline or IRAM_ATTR on ESP32 - */ - inline void notifyFromISR(BaseType_t *highPriWoken, uint32_t v = 0, eNotifyAction action = eNoAction) - { - xTaskNotifyFromISR(taskHandle, v, action, highPriWoken); - } +#ifdef HAS_FREE_RTOS +typedef FreeRtosNotifiedWorkerThread NotifiedWorkerThread; +#endif - protected: - /** - * The notification that was most recently used to wake the thread. Read from loop() - */ - uint32_t notification = 0; - - /** - * What notification bits should be cleared just after we read and return them in notification? - * - * Defaults to clear all of them. - */ - uint32_t clearOnRead = UINT32_MAX; - - /** - * A method that should block execution - either waiting ona queue/mutex or a "task notification" - */ - virtual void block(); -}; +#ifdef __unix__ +typedef PosixNotifiedWorkerThread NotifiedWorkerThread; +#endif } // namespace concurrency diff --git a/src/concurrency/PeriodicScheduler.cpp b/src/concurrency/PeriodicScheduler.cpp index d2fa77f9..5902ddd7 100644 --- a/src/concurrency/PeriodicScheduler.cpp +++ b/src/concurrency/PeriodicScheduler.cpp @@ -1,7 +1,6 @@ #include "PeriodicScheduler.h" #include "PeriodicTask.h" #include "LockGuard.h" -#include "../timing.h" namespace concurrency { @@ -10,7 +9,7 @@ void PeriodicScheduler::loop() { LockGuard lg(&lock); - uint32_t now = timing::millis(); + uint32_t now = millis(); for (auto t : tasks) { if (t->period && (now - t->lastMsec) >= t->period) { diff --git a/src/concurrency/PeriodicTask.h b/src/concurrency/PeriodicTask.h index 910c0dfd..74d4c8a3 100644 --- a/src/concurrency/PeriodicTask.h +++ b/src/concurrency/PeriodicTask.h @@ -1,7 +1,7 @@ #pragma once +#include #include "PeriodicScheduler.h" -#include "timing.h" namespace concurrency { @@ -38,7 +38,7 @@ class PeriodicTask */ void setPeriod(uint32_t p) { - lastMsec = timing::millis(); // reset starting from now + lastMsec = millis(); // reset starting from now period = p; } diff --git a/src/concurrency/PosixNotifiedWorkerThread.cpp b/src/concurrency/PosixNotifiedWorkerThread.cpp new file mode 100644 index 00000000..e759a871 --- /dev/null +++ b/src/concurrency/PosixNotifiedWorkerThread.cpp @@ -0,0 +1,19 @@ +#include "PosixNotifiedWorkerThread.h" + +#ifdef __unix__ + +#include + +using namespace concurrency; + +/** + * Notify this thread so it can run + */ +void PosixNotifiedWorkerThread::notify(uint32_t v, eNotifyAction action) NOT_IMPLEMENTED("notify"); + +/** + * A method that should block execution - either waiting ona queue/mutex or a "task notification" + */ +void PosixNotifiedWorkerThread::block() NOT_IMPLEMENTED("block"); + +#endif \ No newline at end of file diff --git a/src/concurrency/PosixNotifiedWorkerThread.h b/src/concurrency/PosixNotifiedWorkerThread.h new file mode 100644 index 00000000..d75b74dd --- /dev/null +++ b/src/concurrency/PosixNotifiedWorkerThread.h @@ -0,0 +1,26 @@ +#pragma once + +#include "BaseNotifiedWorkerThread.h" + +namespace concurrency { + +/** + * @brief A worker thread that waits on a freertos notification + */ +class PosixNotifiedWorkerThread : public BaseNotifiedWorkerThread +{ + public: + /** + * Notify this thread so it can run + */ + void notify(uint32_t v = 0, eNotifyAction action = eNoAction); + + protected: + + /** + * A method that should block execution - either waiting ona queue/mutex or a "task notification" + */ + virtual void block(); +}; + +} // namespace concurrency diff --git a/src/concurrency/PosixThread.h b/src/concurrency/PosixThread.h new file mode 100644 index 00000000..3f46ebc0 --- /dev/null +++ b/src/concurrency/PosixThread.h @@ -0,0 +1,33 @@ +#pragma once + +#include "BaseThread.h" + +#ifdef __unix__ + +namespace concurrency +{ + +/** + * @brief Base threading + */ +class PosixThread : public BaseThread +{ + protected: + public: + void start(const char *name, size_t stackSize = 1024, uint32_t priority = tskIDLE_PRIORITY) {} + + virtual ~PosixThread() {} + + // uint32_t getStackHighwaterMark() { return uxTaskGetStackHighWaterMark(taskHandle); } + + protected: + /** + * The method that will be called when start is called. + */ + virtual void doRun() = 0; + +}; + +} // namespace concurrency + +#endif \ No newline at end of file diff --git a/src/concurrency/Thread.h b/src/concurrency/Thread.h index ce72111e..f9fa60fd 100644 --- a/src/concurrency/Thread.h +++ b/src/concurrency/Thread.h @@ -1,47 +1,17 @@ #pragma once -#include "freertosinc.h" +#include "FreeRtosThread.h" +#include "PosixThread.h" -namespace concurrency { - -/** - * @brief Base threading - */ -class Thread +namespace concurrency { - protected: - TaskHandle_t taskHandle = NULL; - /** - * set this to true to ask thread to cleanly exit asap - */ - volatile bool wantExit = false; - - public: - void start(const char *name, size_t stackSize = 1024, uint32_t priority = tskIDLE_PRIORITY); - - virtual ~Thread() { vTaskDelete(taskHandle); } - - uint32_t getStackHighwaterMark() { return uxTaskGetStackHighWaterMark(taskHandle); } - - protected: - /** - * The method that will be called when start is called. - */ - virtual void doRun() = 0; - - /** - * All thread run methods must periodically call serviceWatchdog, or the system will declare them hung and panic. - * - * this only applies after startWatchdog() has been called. If you need to sleep for a long time call stopWatchdog() - */ - void serviceWatchdog(); - void startWatchdog(); - void stopWatchdog(); - - private: - static void callRun(void *_this); -}; +#ifdef HAS_FREE_RTOS +typedef FreeRtosThread Thread; +#endif +#ifdef __unix__ +typedef PosixThread Thread; +#endif } // namespace concurrency diff --git a/src/concurrency/WorkerThread.cpp b/src/concurrency/WorkerThread.cpp index 8ea1e6a8..b2ec18d8 100644 --- a/src/concurrency/WorkerThread.cpp +++ b/src/concurrency/WorkerThread.cpp @@ -1,5 +1,4 @@ #include "WorkerThread.h" -#include "timing.h" namespace concurrency { @@ -17,8 +16,8 @@ void WorkerThread::doRun() #ifdef DEBUG_STACK static uint32_t lastPrint = 0; - if (timing::millis() - lastPrint > 10 * 1000L) { - lastPrint = timing::millis(); + if (millis() - lastPrint > 10 * 1000L) { + lastPrint = millis(); meshtastic::printThreadInfo("net"); } #endif diff --git a/src/configuration.h b/src/configuration.h index e70f1fda..55464d6c 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -55,24 +55,21 @@ along with this program. If not, see . /// Convert a preprocessor name into a quoted string and if that string is empty use "unset" #define optstr(s) (xstr(s)[0] ? xstr(s) : "unset") -#ifdef NRF52_SERIES // All of the NRF52 targets are configured using variant.h, so this section shouldn't need to be - // board specific +#ifdef PORTDUINO + +#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth) + +#elif defined(NRF52_SERIES) // All of the NRF52 targets are configured using variant.h, so this section shouldn't need to be +// board specific // // Standard definitions for NRF52 targets // -// Nop definition for these attributes - not used on NRF52 -#define EXT_RAM_ATTR -#define IRAM_ATTR - #define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth) // We bind to the GPS using variant.h instead for this platform (Serial1) -// FIXME, not yet ready for NRF52 -#define RTC_DATA_ATTR - #define LED_PIN PIN_LED1 // LED1 on nrf52840-DK // If the variant filed defines as standard button @@ -89,9 +86,6 @@ along with this program. If not, see . #define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth) -// FIXME, not yet ready for NRF52 -#define RTC_DATA_ATTR - #define LED_PIN -1 // FIXME totally bogus #define BUTTON_PIN -1 @@ -123,6 +117,17 @@ along with this program. If not, see . #endif +// +// Standard definitions for !ESP32 targets +// + +#ifdef NO_ESP32 +// Nop definition for these attributes - not used on NRF52 +#define EXT_RAM_ATTR +#define IRAM_ATTR +#define RTC_DATA_ATTR +#endif + // ----------------------------------------------------------------------------- // OLED // ----------------------------------------------------------------------------- @@ -195,8 +200,6 @@ along with this program. If not, see . #define BUTTON_PIN 39 #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage -#define USE_RF95 - #define USE_RF95 #define LORA_DIO0 26 // a No connect on the SX1262 module #define LORA_RESET 23 @@ -338,6 +341,24 @@ along with this program. If not, see . #define HW_VENDOR "nrf52unknown" // FIXME - unknown nrf52 board +#elif PORTDUINO + +#define HW_VENDOR "portduino" + +#define USE_SIM_RADIO + +#define USE_RF95 +#define LORA_DIO0 26 // a No connect on the SX1262 module +#define LORA_RESET 23 +#define LORA_DIO1 33 // Not really used +#define LORA_DIO2 32 // Not really used + +// Fake SPI device selections +#define RF95_SCK 5 +#define RF95_MISO 19 +#define RF95_MOSI 27 +#define RF95_NSS 18 + #endif #ifdef USE_RF95 diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp index 9bc7445a..4fa518cc 100644 --- a/src/esp32/BluetoothSoftwareUpdate.cpp +++ b/src/esp32/BluetoothSoftwareUpdate.cpp @@ -1,7 +1,6 @@ #include #include "../concurrency/LockGuard.h" -#include "../timing.h" #include "BluetoothSoftwareUpdate.h" #include "PowerFSM.h" #include "RadioLibInterface.h" @@ -102,7 +101,7 @@ int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble } else { if (Update.end()) { DEBUG_MSG("OTA done, rebooting in 5 seconds!\n"); - rebootAtMsec = timing::millis() + 5000; + rebootAtMsec = millis() + 5000; } else { DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError()); } @@ -128,7 +127,7 @@ int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct bl void bluetoothRebootCheck() { - if (rebootAtMsec && timing::millis() > rebootAtMsec) { + if (rebootAtMsec && millis() > rebootAtMsec) { DEBUG_MSG("Rebooting for update\n"); ESP.restart(); } diff --git a/src/freertosinc.h b/src/freertosinc.h index 818eae6b..c5dfddc8 100644 --- a/src/freertosinc.h +++ b/src/freertosinc.h @@ -3,22 +3,32 @@ // The FreeRTOS includes are in a different directory on ESP32 and I can't figure out how to make that work with platformio gcc // options so this is my quick hack to make things work -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) #define HAS_FREE_RTOS + #include #include #include #include -#else -// not yet supported on cubecell -#ifndef CubeCell_BoardPlus +#endif + +#if defined(ARDUINO_NRF52_ADAFRUIT) #define HAS_FREE_RTOS + #include #include #include #include +#endif + +#ifdef HAS_FREE_RTOS + +// Include real FreeRTOS defs above + #else +// Include placeholder fake FreeRTOS defs + #include typedef uint32_t TickType_t; @@ -26,5 +36,12 @@ typedef uint32_t BaseType_t; #define portMAX_DELAY UINT32_MAX +#define tskIDLE_PRIORITY 0 +#define configMAX_PRIORITIES 10 // Highest priority level + +// Don't do anything on non free rtos platforms when done with the ISR +#define portYIELD_FROM_ISR(x) + +enum eNotifyAction { eNoAction, eSetValueWithoutOverwrite, eSetValueWithOverwrite }; + #endif -#endif \ No newline at end of file diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 3902b655..b3ab28d2 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1,7 +1,6 @@ #include "GPS.h" #include "configuration.h" -#include "timing.h" #include #include @@ -36,7 +35,7 @@ void readFromRTC() struct timeval tv; /* btw settimeofday() is helpfull here too*/ if (!gettimeofday(&tv, NULL)) { - uint32_t now = timing::millis(); + uint32_t now = millis(); DEBUG_MSG("Read RTC time as %ld (cur millis %u) valid=%d\n", tv.tv_sec, now, timeSetFromGPS); timeStartMsec = now; @@ -79,7 +78,7 @@ void perhapsSetRTC(struct tm &t) uint32_t getTime() { - return ((timing::millis() - timeStartMsec) / 1000) + zeroOffsetSecs; + return ((millis() - timeStartMsec) / 1000) + zeroOffsetSecs; } uint32_t getValidTime() diff --git a/src/gps/NMEAGPS.cpp b/src/gps/NMEAGPS.cpp index 6b797fd7..2100fdcb 100644 --- a/src/gps/NMEAGPS.cpp +++ b/src/gps/NMEAGPS.cpp @@ -1,6 +1,5 @@ #include "NMEAGPS.h" #include "configuration.h" -#include "timing.h" static int32_t toDegInt(RawDegrees d) { @@ -19,7 +18,7 @@ void NMEAGPS::loop() reader.encode(c); } - uint32_t now = timing::millis(); + uint32_t now = millis(); if ((now - lastUpdateMsec) > 20 * 1000) { // Ugly hack for now - limit update checks to once every 20 secs (but still consume // serial chars at whatever rate) lastUpdateMsec = now; diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 5229f566..b460775a 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -31,6 +31,7 @@ along with this program. If not, see . #include "graphics/images.h" #include "main.h" #include "mesh-pb-constants.h" +#include "target_specific.h" #include "utils.h" using namespace meshtastic; /** @todo remove */ diff --git a/src/main.cpp b/src/main.cpp index 0a474e08..207ae7b1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,7 +38,7 @@ #include "graphics/Screen.h" #include "main.h" #include "sleep.h" -#include "timing.h" +#include "target_specific.h" #include #include // #include @@ -223,7 +223,7 @@ void setup() // Init our SPI controller (must be before screen and lora) initSPI(); -#ifdef NRF52_SERIES +#ifdef NO_ESP32 SPI.begin(); #else // ESP32 @@ -268,7 +268,10 @@ void setup() gps = new NMEAGPS(); gps->setup(); #endif - gpsStatus->observe(&gps->newStatus); + if (gps) + gpsStatus->observe(&gps->newStatus); + else + DEBUG_MSG("Warning: No GPS found - running without GPS\n"); nodeStatus->observe(&nodeDB.newStatus); service.init(); @@ -362,7 +365,8 @@ void loop() { uint32_t msecstosleep = 1000 * 30; // How long can we sleep before we again need to service the main loop? - gps->loop(); // FIXME, remove from main, instead block on read + if (gps) + gps->loop(); // FIXME, remove from main, instead block on read router.loop(); powerFSM.run_machine(); service.loop(); @@ -392,15 +396,15 @@ void loop() // Show boot screen for first 3 seconds, then switch to normal operation. static bool showingBootScreen = true; - if (showingBootScreen && (timing::millis() > 3000)) { + if (showingBootScreen && (millis() > 3000)) { screen.stopBootScreen(); showingBootScreen = false; } #ifdef DEBUG_STACK static uint32_t lastPrint = 0; - if (timing::millis() - lastPrint > 10 * 1000L) { - lastPrint = timing::millis(); + if (millis() - lastPrint > 10 * 1000L) { + lastPrint = millis(); meshtastic::printThreadInfo("main"); } #endif diff --git a/src/main.h b/src/main.h index fb64d9ff..74ad0b44 100644 --- a/src/main.h +++ b/src/main.h @@ -21,6 +21,6 @@ extern graphics::Screen screen; // Return a human readable string of the form "Meshtastic_ab13" const char *getDeviceName(); -void getMacAddr(uint8_t *dmac); + void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(); \ No newline at end of file diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index c614c086..3356e092 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -13,7 +13,6 @@ #include "main.h" #include "mesh-pb-constants.h" #include "power.h" -#include "timing.h" /* receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone. @@ -68,8 +67,8 @@ void MeshService::init() sendOwnerPeriod.setup(); nodeDB.init(); - assert(gps); - gpsObserver.observe(&gps->newStatus); + if (gps) + gpsObserver.observe(&gps->newStatus); packetReceivedObserver.observe(&router.notifyPacketReceived); } @@ -316,7 +315,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused) // We limit our GPS broadcasts to a max rate static uint32_t lastGpsSend; - uint32_t now = timing::millis(); + uint32_t now = millis(); if (lastGpsSend == 0 || now - lastGpsSend > radioConfig.preferences.position_broadcast_secs * 1000) { lastGpsSend = now; DEBUG_MSG("Sending position to mesh\n"); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 93d0787d..634bd951 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -32,7 +32,14 @@ DeviceState versions used to be defined in the .proto file but really only this #define DEVICESTATE_CUR_VER 11 #define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER -#ifndef NO_ESP32 +#ifdef PORTDUINO +// Portduino version +#include "PortduinoFS.h" +#define FS PortduinoFS +#define FSBegin() true +#define FILE_O_WRITE "w" +#define FILE_O_READ "r" +#elif !defined(NO_ESP32) // ESP32 version #include "SPIFFS.h" #define FS SPIFFS diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index b83fab3c..3d1884ac 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -1,7 +1,6 @@ #include "PacketHistory.h" #include "configuration.h" #include "mesh-pb-constants.h" -#include "../timing.h" PacketHistory::PacketHistory() { @@ -19,7 +18,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate) return false; // Not a floodable message ID, so we don't care } - uint32_t now = timing::millis(); + uint32_t now = millis(); for (size_t i = 0; i < recentPackets.size();) { PacketRecord &r = recentPackets[i]; diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 2e8800c1..caadf856 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -4,7 +4,6 @@ #include "NodeDB.h" #include "PowerFSM.h" #include "RadioInterface.h" -#include "timing.h" #include PhoneAPI::PhoneAPI() @@ -21,7 +20,7 @@ void PhoneAPI::init() void PhoneAPI::checkConnectionTimeout() { if (isConnected) { - bool newConnected = (timing::millis() - lastContactMsec < radioConfig.preferences.phone_timeout_secs * 1000L); + bool newConnected = (millis() - lastContactMsec < radioConfig.preferences.phone_timeout_secs * 1000L); if (!newConnected) { isConnected = false; onConnectionChanged(isConnected); @@ -35,7 +34,7 @@ void PhoneAPI::checkConnectionTimeout() void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) { powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // As long as the phone keeps talking to us, don't let the radio go to sleep - lastContactMsec = timing::millis(); + lastContactMsec = millis(); if (!isConnected) { isConnected = true; onConnectionChanged(isConnected); diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index ae4ef421..1a08f282 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -6,7 +6,6 @@ #include "assert.h" #include "configuration.h" #include "sleep.h" -#include "timing.h" #include #include #include @@ -178,7 +177,7 @@ size_t RadioInterface::beginSending(MeshPacket *p) // DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad()); assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now - lastTxStart = timing::millis(); + lastTxStart = millis(); PacketHeader *h = (PacketHeader *)radiobuf; diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 174c184a..acec6b7f 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -2,7 +2,6 @@ #include "MeshTypes.h" #include "configuration.h" #include "mesh-pb-constants.h" -#include "timing.h" // ReliableRouter::ReliableRouter() {} @@ -163,7 +162,7 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p) */ void ReliableRouter::doRetransmissions() { - uint32_t now = timing::millis(); + uint32_t now = millis(); // FIXME, we should use a better datastructure rather than walking through this map. // for(auto el: pending) { diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index 04974feb..f2e8774d 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -2,7 +2,6 @@ #include "FloodingRouter.h" #include "../concurrency/PeriodicTask.h" -#include "../timing.h" #include /** @@ -49,7 +48,7 @@ struct PendingPacket { PendingPacket() {} PendingPacket(MeshPacket *p); - void setNextTx() { nextTxMsec = timing::millis() + random(20 * 1000L, 22 * 1000L); } + void setNextTx() { nextTxMsec = millis() + random(20 * 1000L, 22 * 1000L); } }; class GlobalPacketIdHashFunction diff --git a/src/mesh/TypedQueue.h b/src/mesh/TypedQueue.h index 90ed07f1..a2b82626 100644 --- a/src/mesh/TypedQueue.h +++ b/src/mesh/TypedQueue.h @@ -53,7 +53,7 @@ template class TypedQueue public: TypedQueue(int maxElements) {} - // int numFree() { return uxQueueSpacesAvailable(h); } + int numFree() { return 1; } // Always claim 1 free, because we can grow to any size bool isEmpty() { return q.empty(); } diff --git a/src/mesh/mesh-pb-constants.cpp b/src/mesh/mesh-pb-constants.cpp index dc0d188a..337e585d 100644 --- a/src/mesh/mesh-pb-constants.cpp +++ b/src/mesh/mesh-pb-constants.cpp @@ -6,10 +6,10 @@ #include #include -#ifdef NO_ESP32 +#ifdef ARDUINO_ARCH_NRF52 #include "Adafruit_LittleFS.h" using namespace Adafruit_LittleFS_Namespace; // To get File type -#endif +#endif /// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic /// returns the encoded packet size @@ -49,7 +49,7 @@ bool readcb(pb_istream_t *stream, uint8_t *buf, size_t count) return count == 0; } - status = (file->read(buf, count) == (int) count); + status = (file->read(buf, count) == (int)count); if (file->available() == 0) stream->bytes_left = 0; diff --git a/src/portduino/PortduinoGlue.cpp b/src/portduino/PortduinoGlue.cpp new file mode 100644 index 00000000..690af607 --- /dev/null +++ b/src/portduino/PortduinoGlue.cpp @@ -0,0 +1,32 @@ +#include "CryptoEngine.h" +#include "target_specific.h" +#include + +// FIXME - move getMacAddr/setBluetoothEnable into a HALPlatform class + +uint32_t hwId; // fixme move into portduino + +void getMacAddr(uint8_t *dmac) +{ + if (!hwId) { + notImplemented("getMacAddr"); + hwId = random(); + } + + dmac[0] = 0x80; + dmac[1] = 0; + dmac[2] = 0; + dmac[3] = hwId >> 16; + dmac[4] = hwId >> 8; + dmac[5] = hwId & 0xff; +} + +void setBluetoothEnable(bool on) +{ + notImplemented("setBluetoothEnable"); +} + +// FIXME - implement real crypto for linux +CryptoEngine *crypto = new CryptoEngine(); + +void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel"); \ No newline at end of file diff --git a/src/sleep.cpp b/src/sleep.cpp index 886886b5..731273c9 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -7,7 +7,6 @@ #include "error.h" #include "main.h" #include "target_specific.h" -#include "timing.h" #ifndef NO_ESP32 #include "esp32/pm.h" @@ -123,11 +122,11 @@ bool doPreflightSleep() /// Tell devices we are going to sleep and wait for them to handle things static void waitEnterSleep() { - uint32_t now = timing::millis(); + uint32_t now = millis(); while (!doPreflightSleep()) { delay(100); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives) - if (timing::millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep + if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep recordCriticalError(ErrSleepEnterWait); assert(0); // FIXME - for now we just restart, need to fix bug #167 break; diff --git a/src/target_specific.h b/src/target_specific.h index 6acca364..1e79df51 100644 --- a/src/target_specific.h +++ b/src/target_specific.h @@ -1,6 +1,10 @@ #pragma once +#include + // Functions that are unique to particular target types (esp32, bare, nrf52 etc...) // Enable/disable bluetooth. -void setBluetoothEnable(bool on); \ No newline at end of file +void setBluetoothEnable(bool on); + +void getMacAddr(uint8_t *dmac); \ No newline at end of file diff --git a/src/timing.cpp b/src/timing.cpp deleted file mode 100644 index f7cffaa6..00000000 --- a/src/timing.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "timing.h" -#include "freertosinc.h" - -namespace timing { - - uint32_t millis() { - return xTaskGetTickCount(); - } - -} // namespace timing diff --git a/src/timing.h b/src/timing.h deleted file mode 100644 index 7f741d45..00000000 --- a/src/timing.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -namespace timing { - - uint32_t millis(); - -} // namespace timing \ No newline at end of file