diff --git a/bin/dump-ram-users.sh b/bin/dump-ram-users.sh new file mode 100755 index 000000000..f0438834e --- /dev/null +++ b/bin/dump-ram-users.sh @@ -0,0 +1,3 @@ +arm-none-eabi-readelf -s -e .pio/build/nrf52dk/firmware.elf | head -80 + +nm -CSr --size-sort .pio/build/nrf52dk/firmware.elf | grep '^200' diff --git a/docs/hardware/cubecell-TODO.md b/docs/hardware/cubecell-TODO.md new file mode 100644 index 000000000..b96acbb36 --- /dev/null +++ b/docs/hardware/cubecell-TODO.md @@ -0,0 +1,6 @@ + +https://heltec-automation-docs.readthedocs.io/en/latest/cubecell/index.html + +https://github.com/HelTecAutomation/ASR650x-Arduino?utm_source=platformio.org&utm_medium=docs + +* Either portfreertos or make not theaded versions of Lock, WorkerThread, Queue (probably the latter). diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 7bf428816..a47d73e64 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -1,8 +1,8 @@ # High priority - nrf52 free memory https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/hathach-memory-map -- modem sleep should work if we lower serial rate to 115kb? - encryption review findings writeup +- NRF52 BLE - cubecell - DSR @@ -43,6 +43,7 @@ During the beta timeframe the following improvements 'would be nice' Items after the first final candidate release. +- dynamic frequency scaling could save a lot of power on ESP32, but it seems to corrupt uart (even with ref_tick set correctly) - Change back to using a fixed sized MemoryPool rather than MemoryDynamic (see bug #149) - scan to find channels with low background noise? (Use CAD mode of the RF95 to automatically find low noise channels) - If the phone doesn't read fromradio mailbox within X seconds, assume the phone is gone and we can stop queing location msgs diff --git a/docs/software/nrf52-TODO.md b/docs/software/nrf52-TODO.md index 1836f64bc..d6d91868f 100644 --- a/docs/software/nrf52-TODO.md +++ b/docs/software/nrf52-TODO.md @@ -2,6 +2,11 @@ ## Misc work items +RAM investigation. +nRF52832-QFAA 64KB ram, 512KB flash vs +nrf52832-QFAB 32KB ram, 512kb flash +nrf52840 256KB RAM, 1MB flash + platform.json "framework-arduinoadafruitnrf52": { diff --git a/docs/software/ramusage-nrf52.txt b/docs/software/ramusage-nrf52.txt new file mode 100644 index 000000000..9969806e4 --- /dev/null +++ b/docs/software/ramusage-nrf52.txt @@ -0,0 +1,200 @@ +23K + messages ++ heap of 70ish packets, 300ish bytes per packet: 20KB ++ 14KB soft device RAM + +With max length Data inside the packet +Size of NodeInfo 104 +Size of SubPacket 272 +Size of MeshPacket 304 + +If Data was smaller: for 70 data packets we would save 7KB. We would need to make SubPacket.data and MeshPacket.encrypted into "type:FT_POINTER" - variably sized mallocs +Size of NodeInfo 104 +Size of SubPacket 96 +Size of MeshPacket 292 (could have been much smaller but I forgot to shrink MeshPacket.encrypted) + +therefore: +a) we should store all ToPhone message queued messages compressed as protobufs (since they will become that anyways) +b) shrink packet pool size because none of that storage will be used for ToPhone packets +c) don't allocate any storage in RAM for the tophone messages we save inside device state, instead just use nanopb callbacks to save/load those +d) a smarter MeshPacket in memory representation would save about 7KB of RAM. call pb_release before freeing each freshly malloced MeshPacket + +2000790c 00003558 B devicestate // 16KB +2000b53c 00001000 b _cache_buffer // 4KB flash filesystem support +20003b1c 000006b0 B console +2000d5f4 00000400 b vApplicationGetTimerTaskMemory::uxTimerTaskStack +2000da04 00000400 b _acUpBuffer +2000c558 0000036c B Bluefruit +2000c8d8 00000358 b _cdcd_itf +2000e54c 00000258 B _midid_itf +2000d0dc 00000200 b ucStaticTimerQueueStorage.9390 +2000e044 00000200 b _mscd_buf +2000e284 000001cc b _vendord_itf +2000d410 00000190 b vApplicationGetIdleTaskMemory::uxIdleTaskStack +2000374c 0000016c D __global_locale +2000de48 0000012c B USBDevice +2000afa4 00000100 b Router::send(_MeshPacket*)::bytes +2000aea4 00000100 b Router::perhapsDecode(_MeshPacket*)::bytes +200039b0 000000f4 B powerFSM +20004258 000000f0 B screen +2000cd7c 000000c4 b _dcd +2000cc68 000000c0 b _usbd_qdef_buf +2000b3c4 000000bc B Wire +2000cef4 000000a8 B Serial2 +2000ce4c 000000a8 B Serial1 +2000e498 000000a8 B _SEGGER_RTT +2000b498 000000a4 B InternalFS +2000dfb8 0000008c b _hidd_itf +2000b260 00000088 b meshtastic::normalFrames +2000cfdc 00000064 b pxReadyTasksLists +2000b340 00000060 b meshtastic::drawTextMessageFrame(OLEDDisplay*, OLEDDisplayUiState*, short, short)::tempBuf +200036ec 00000060 d impure_data +2000b104 00000060 B bledfu +2000b0a4 00000060 B blebas +20003684 00000058 D _usbd_qdef +200038c0 00000058 d tzinfo +2000d5a0 00000054 b vApplicationGetTimerTaskMemory::xTimerTaskTCB +2000d3bc 00000054 b vApplicationGetIdleTaskMemory::xIdleTaskTCB +2000d308 00000050 b xStaticTimerQueue.9389 +2000b1f4 00000050 B hrmc +2000b1a4 00000050 B bslc +20004360 0000004c B service +2000d374 00000048 b m_cb +2000df74 00000042 b _desc_str +2000cd3c 00000040 b _usbd_ctrl_buf +20004214 00000040 B realRouter +2000e244 00000040 b _mscd_itf +2000b164 00000040 B bledis +20003634 00000038 d _InternalFSConfig +2000cc30 00000031 b _usbd_dev +2000398c 00000020 B periodicScheduler +2000cfa4 00000020 b callbacksInt +2000de10 0000001f b fw_str.13525 +20003974 00000018 b object.9934 +2000ae68 00000018 B nodeDB +2000366c 00000018 d _cache +2000b314 00000014 b meshtastic::drawNodeInfo(OLEDDisplay*, OLEDDisplayUiState*, short, short)::signalStr +2000b300 00000014 b meshtastic::drawNodeInfo(OLEDDisplay*, OLEDDisplayUiState*, short, short)::lastStr +2000b2ec 00000014 b meshtastic::drawNodeInfo(OLEDDisplay*, OLEDDisplayUiState*, short, short)::distStr +200041e0 00000014 b getDeviceName()::name +2000d0b8 00000014 b xTasksWaitingTermination +2000d0a4 00000014 b xSuspendedTaskList +2000d08c 00000014 b xPendingReadyList +2000d06c 00000014 b xDelayedTaskList2 +2000d058 00000014 b xDelayedTaskList1 +2000d2f0 00000014 b xActiveTimerList2 +2000d2dc 00000014 b xActiveTimerList1 +2000b480 00000014 B SPI +2000c8c4 00000014 B Serial +2000cd28 00000014 b _ctrl_xfer +2000de30 00000011 b serial_str.13534 +2000c544 00000010 b BLEAdvertising::_start(unsigned short, unsigned short)::gap_adv +20003614 00000010 d meshtastic::btPIN +2000434c 00000010 b sendOwnerPeriod +2000ae8c 00000010 b staticPool +2000e484 00000010 B xQueueRegistry +20003b04 00000010 B stateSERIAL +20003af4 00000010 B stateSDS +20003ae4 00000010 B stateON +20003ad4 00000010 B stateNB +20003ac4 00000010 B stateLS +20003ab4 00000010 B stateDARK +20003aa4 00000010 B stateBOOT +200041f8 00000010 B ledPeriodic +2000b244 00000010 B hrms +2000d9f4 00000010 b _acDownBuffer +2000b3b8 0000000c B preflightSleep +20004208 0000000c B powerStatus +2000e540 0000000c B nrf_nvic_state +2000b3ac 0000000c B notifySleep +2000b3a0 0000000c B notifyDeepSleep +2000e463 0000000b b __tzname_std +2000e458 0000000b b __tzname_dst +2000b338 00000008 b meshtastic::estimatedHeading(double, double)::oldLon +2000b330 00000008 b meshtastic::estimatedHeading(double, double)::oldLat +200041d0 00000008 b zeroOffsetSecs +2000ae80 00000008 b spiSettings +200038b8 00000008 D _tzname +20003b14 00000008 B noopPrint +2000cfc4 00000008 b channelMap +2000cf9c 00000008 b callbackDeferred +200043ac 00000006 b ourMacAddr +2000435c 00000004 b MeshService::onGPSChanged(void*)::lastGpsSend +2000b32c 00000004 b meshtastic::estimatedHeading(double, double)::b +2000b328 00000004 b meshtastic::drawNodeInfo(OLEDDisplay*, OLEDDisplayUiState*, short, short)::simRadian +2000362c 00000004 d meshtastic::Screen::setup()::bootFrames +20003628 00000004 d meshtastic::Screen::handleStartBluetoothPinScreen(unsigned long)::btFrames +200039ac 00000004 b onEnter()::lastPingMs +2000ae9c 00000004 b generatePacketId()::i +2000ae88 00000004 B RadioLibInterface::instance +2000b2e8 00000004 b meshtastic::nodeIndex +20003610 00000004 d meshtastic::targetFramerate +2000c554 00000004 B BLEService::lastService +200041cc 00000004 b timeStartMsec +200036dc 00000004 d sbrk_heap_top +2000d364 00000004 b _loopHandle +2000c540 00000004 b guard variable for BLEAdvertising::_start(unsigned short, unsigned short)::gap_adv +2000d0d0 00000004 b xYieldPending +2000d35c 00000004 b xTimerTaskHandle +2000d358 00000004 b xTimerQueue +2000d0cc 00000004 b xTickCount +2000d0a0 00000004 b xSchedulerRunning +2000d088 00000004 b xNumOfOverflows +2000d084 00000004 b xNextTaskUnblockTime +2000d304 00000004 b xLastTime.9343 +2000d080 00000004 b xIdleTaskHandle +2000d054 00000004 b uxTopReadyPriority +2000d050 00000004 b uxTaskNumber +2000d04c 00000004 b uxSchedulerSuspended +2000d048 00000004 b uxPendedTicks +2000d044 00000004 b uxDeletedTasksWaitingCleanUp +2000d040 00000004 b uxCurrentNumberOfTasks +2000d360 00000004 b uxCriticalNesting +2000cc64 00000004 b _usbd_q +2000e478 00000004 B _timezone +200036e0 00000004 D SystemCoreClock +2000c53c 00000004 b _sem +2000d0d8 00000004 b pxOverflowTimerList +2000cfd8 00000004 b pxOverflowDelayedTaskList +2000cfd4 00000004 b pxDelayedTaskList +2000d0d4 00000004 b pxCurrentTimerList +2000cfd0 00000004 B pxCurrentTCB +2000e470 00000004 b prev_tzenv +2000360c 00000004 D preftmp +20003608 00000004 D preffile +2000b25c 00000004 B nrf52Bluetooth +2000d370 00000004 b m_usbevt_handler +2000d36c 00000004 b m_sleepevt_handler +2000d368 00000004 b m_pofwarn_handler +2000e454 00000004 B __malloc_sbrk_start +2000e450 00000004 B __malloc_free_list +2000e480 00000004 B MAIN_MonCnt +2000e47c 00000004 b initial_env +200036e8 00000004 D _impure_ptr +200041d8 00000004 B gps +2000e7a4 00000004 B errno +20003918 00000004 D environ +2000cfcc 00000004 b enabled +2000ae64 00000004 B displayedNodeNum +2000e474 00000004 B _daylight +2000b254 00000004 B crypto +2000ce44 00000004 B count_duration +2000de0c 00000004 b _cb_task +2000de08 00000004 b _cb_queue +2000de04 00000004 b _cb_qdepth +2000de44 00000004 B bootloaderVersion +200041f5 00000001 b ledBlinker()::ledOn +20003604 00000001 d loop::showingBootScreen +200041f4 00000001 b loop::wasPressed +2000b494 00000001 b DefaultFontTableLookup(unsigned char)::LASTCHAR +2000aea0 00000001 b generatePacketId()::didInit +20003624 00000001 d meshtastic::prevFrame +2000b258 00000001 b bleOn +200041dc 00000001 B timeSetFromGPS +20004348 00000001 B ssd1306_found +2000ce49 00000001 B pin_sound +2000e494 00000001 B nrfx_power_irq_enabled +2000ce48 00000001 B no_stop +20003630 00000001 D neo6M +2000ce40 00000001 b _initialized +200036e4 00000001 D __fdlib_version +20003970 00000001 b completed.9929 diff --git a/lib/nanopb/include/pb.h b/lib/nanopb/include/pb.h index 8e87b6263..45504e992 100644 --- a/lib/nanopb/include/pb.h +++ b/lib/nanopb/include/pb.h @@ -11,7 +11,7 @@ *****************************************************************/ /* Enable support for dynamically allocated fields */ -/* #define PB_ENABLE_MALLOC 1 */ +#define PB_ENABLE_MALLOC 1 /* Define this if your CPU / compiler combination does not support * unaligned memory access to packed structures. */ diff --git a/linker/nrf52840_s140_sim832.ld b/linker/nrf52840_s140_sim832.ld new file mode 100644 index 000000000..273746683 --- /dev/null +++ b/linker/nrf52840_s140_sim832.ld @@ -0,0 +1,46 @@ +/* Linker script to configure memory regions. + +geeksville: modified this to simulate a nrf52832 but with a sd140 soft device. So I can +see how the memory footprint works on this lower end CPU. Note: to work with sd140 in my bootloader +I need to start ram at 0x6000 (instead of the correct 0x3600 for sd132) - so I have less +RAM available than on a real 832. +*/ + +SEARCH_DIR(.) +GROUP(-lgcc -lc -lnosys) + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0x6D000 - 0x26000 + /* FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0xED000 - 0x26000 */ + + /* SRAM required by S132 depend on + * - Attribute Table Size + * - Vendor UUID count + * - Max ATT MTU + * - Concurrent connection peripheral + central + secure links + * - Event Len, HVN queue, Write CMD queue + */ + /* RAM (rwx) : ORIGIN = 0x20003600, LENGTH = 0x20010000 - 0x20003600 */ + RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20010000 - 0x20006000 +} + +SECTIONS +{ + . = ALIGN(4); + .svc_data : + { + PROVIDE(__start_svc_data = .); + KEEP(*(.svc_data)) + PROVIDE(__stop_svc_data = .); + } > RAM + + .fs_data : + { + PROVIDE(__start_fs_data = .); + KEEP(*(.fs_data)) + PROVIDE(__stop_fs_data = .); + } > RAM +} INSERT AFTER .data; + +INCLUDE "nrf52_common.ld" diff --git a/platformio.ini b/platformio.ini index f0f63bc31..4ac4fa25f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -125,6 +125,18 @@ board = ttgo-lora32-v1 build_flags = ${esp32_base.build_flags} -D TTGO_LORA_V2 +; The Heltec Cubecell plus +; IMPORTANT NOTE: This target doesn't yet work and probably won't ever work. I'm keeping it around for now. +; For more details see my post in the forum. +[env:cubecellplus] +platform = https://github.com/HelTecAutomation/platform-asrmicro650x.git ; we use top-of-tree because stable version has too many bugs - asrmicro650x +framework = arduino +board = cubecell_board_plus +; FIXME, bug in cubecell arduino - they are supposed to set ARDUINO +build_flags = ${env.build_flags} -DARDUINO=100 -Isrc/cubecell +src_filter = + ${env.src_filter} - - + ; Common settings for NRF52 based targets [nrf52_base] platform = nordicnrf52 @@ -133,7 +145,7 @@ 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 -Isrc/nrf52 -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3 + ${env.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} - @@ -157,6 +169,9 @@ debug_init_break = extends = nrf52_base board = nrf52840_dk_modified +# For experimenting with RAM sizes +# board_build.ldscript = linker/nrf52840_s140_sim832.ld + ; The PPR board [env:ppr] extends = nrf52_base diff --git a/proto b/proto index e7f181ef6..72cbde93f 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit e7f181ef6fd4e38c40e0d0be552149f8bbe75a66 +Subproject commit 72cbde93ffbc2ee917f9d7328558475e02a91cba diff --git a/src/WorkerThread.cpp b/src/WorkerThread.cpp index bf38a9266..3c7ea4c9a 100644 --- a/src/WorkerThread.cpp +++ b/src/WorkerThread.cpp @@ -2,6 +2,8 @@ #include "debug.h" #include +#ifdef configUSE_PREEMPTION + void Thread::start(const char *name, size_t stackSize, uint32_t priority) { auto r = xTaskCreate(callRun, name, stackSize, this, priority, &taskHandle); @@ -43,3 +45,5 @@ void NotifiedWorkerThread::block() xTaskNotifyWait(0, // don't clear notification on entry clearOnRead, ¬ification, portMAX_DELAY); // Wait forever } + +#endif \ No newline at end of file diff --git a/src/WorkerThread.h b/src/WorkerThread.h index 655e316f8..ab1864869 100644 --- a/src/WorkerThread.h +++ b/src/WorkerThread.h @@ -1,4 +1,7 @@ #include +#include "freertosinc.h" + +#ifdef HAS_FREE_RTOS class Thread { @@ -88,4 +91,6 @@ class NotifiedWorkerThread : public WorkerThread * A method that should block execution - either waiting ona queue/mutex or a "task notification" */ virtual void block(); -}; \ No newline at end of file +}; + +#endif \ No newline at end of file diff --git a/src/configuration.h b/src/configuration.h index a85ff5f5f..09132fd41 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -73,6 +73,20 @@ along with this program. If not, see . #define BUTTON_PIN PIN_BUTTON1 // FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets) +#elif defined(CubeCell_BoardPlus) + +// +// Standard definitions for CubeCell targets +// + +#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 + #else // @@ -173,7 +187,7 @@ along with this program. If not, see . #define HW_VENDOR "heltec" // the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine. -//Tested on Neo6m module. +// Tested on Neo6m module. #undef GPS_RX_PIN #undef GPS_TX_PIN #define GPS_RX_PIN 36 @@ -267,7 +281,8 @@ along with this program. If not, see . #define DEBUG_PORT console // Serial debug port -#ifdef NO_ESP32 +// What platforms should use SEGGER? +#ifdef NRF52_SERIES #define USE_SEGGER #else #define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32 diff --git a/src/cubecell/FS.h b/src/cubecell/FS.h new file mode 100644 index 000000000..3f72219a1 --- /dev/null +++ b/src/cubecell/FS.h @@ -0,0 +1 @@ +// Placeholder FIXME \ No newline at end of file diff --git a/src/freertosinc.h b/src/freertosinc.h index 0d86ee2c9..818eae6b3 100644 --- a/src/freertosinc.h +++ b/src/freertosinc.h @@ -1,16 +1,30 @@ #pragma once -// 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 +// 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 +#define HAS_FREE_RTOS #include -#include -#include #include +#include +#include #else +// not yet supported on cubecell +#ifndef CubeCell_BoardPlus +#define HAS_FREE_RTOS #include -#include -#include #include +#include +#include +#else + +#include + +typedef uint32_t TickType_t; +typedef uint32_t BaseType_t; + +#define portMAX_DELAY UINT32_MAX + +#endif #endif \ No newline at end of file diff --git a/src/lock.cpp b/src/lock.cpp index 8041799ea..4a8d28cf5 100644 --- a/src/lock.cpp +++ b/src/lock.cpp @@ -5,6 +5,7 @@ namespace meshtastic { +#ifdef configUSE_PREEMPTION Lock::Lock() { handle = xSemaphoreCreateBinary(); @@ -21,6 +22,20 @@ void Lock::unlock() { assert(xSemaphoreGive(handle)); } +#else +Lock::Lock() +{ +} + +void Lock::lock() +{ +} + +void Lock::unlock() +{ +} +#endif + LockGuard::LockGuard(Lock *lock) : lock(lock) { diff --git a/src/lock.h b/src/lock.h index a6afa2f6c..6a90c61b1 100644 --- a/src/lock.h +++ b/src/lock.h @@ -25,7 +25,9 @@ class Lock void unlock(); private: +#ifdef configUSE_PREEMPTION SemaphoreHandle_t handle; +#endif }; // RAII lock guard. diff --git a/src/main.cpp b/src/main.cpp index e6820e841..16aa20998 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,6 +44,13 @@ #include "BluetoothUtil.h" #endif +#include "RF95Interface.h" +#include "SX1262Interface.h" + +#ifdef NRF52_SERIES +#include "variant.h" +#endif + // We always create a screen object, but we only init it if we find the hardware meshtastic::Screen screen(SSD1306_ADDRESS); @@ -117,12 +124,7 @@ static uint32_t ledBlinker() Periodic ledPeriodic(ledBlinker); -#include "RF95Interface.h" -#include "SX1262Interface.h" -#ifdef NO_ESP32 -#include "variant.h" -#endif void setup() { diff --git a/src/mesh/MemoryPool.h b/src/mesh/MemoryPool.h index 4fefb4c4d..dc6305d17 100644 --- a/src/mesh/MemoryPool.h +++ b/src/mesh/MemoryPool.h @@ -107,6 +107,7 @@ template class MemoryPool : public Allocator maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool } +#ifdef HAS_FREE_RTOS /// Return a buffer from an ISR, if higherPriWoken is set to true you have some work to do ;-) void releaseFromISR(T *p, BaseType_t *higherPriWoken) { @@ -115,6 +116,7 @@ template class MemoryPool : public Allocator (size_t)(p - buf) < maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool } +#endif protected: /// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 4e87ac773..9bebda112 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -3,7 +3,6 @@ #include #include "FS.h" -#include "SPIFFS.h" #include "CryptoEngine.h" #include "GPS.h" @@ -34,11 +33,14 @@ DeviceState versions used to be defined in the .proto file but really only this #define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER #ifndef NO_ESP32 +// ESP32 version +#include "SPIFFS.h" #define FS SPIFFS #define FSBegin() FS.begin(true) #define FILE_O_WRITE "w" #define FILE_O_READ "r" #else +// NRF52 version #include "InternalFileSystem.h" #define FS InternalFS #define FSBegin() FS.begin() @@ -110,8 +112,10 @@ void NodeDB::resetRadioConfig() */ } -void NodeDB::init() +void NodeDB::installDefaultDeviceState() { + memset(&devicestate, 0, sizeof(devicestate)); + // init our devicestate with valid flags so protobuf writing/reading will work devicestate.has_my_node = true; devicestate.has_radio = true; @@ -119,7 +123,7 @@ void NodeDB::init() devicestate.radio.has_channel_settings = true; devicestate.radio.has_preferences = true; devicestate.node_db_count = 0; - devicestate.receive_queue_count = 0; + devicestate.receive_queue_count = 0; // Not yet implemented FIXME resetRadioConfig(); @@ -139,12 +143,17 @@ void NodeDB::init() pickNewNodeNum(); // Note: we will repick later, just in case the settings are corrupted, but we need a valid // owner.short_name now sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]); - sprintf(owner.short_name, "?%02X", myNodeInfo.my_node_num & 0xff); + sprintf(owner.short_name, "?%02X", (unsigned)(myNodeInfo.my_node_num & 0xff)); +} + +void NodeDB::init() +{ + installDefaultDeviceState(); if (!FSBegin()) // FIXME - do this in main? { DEBUG_MSG("ERROR filesystem mount Failed\n"); - // FIXME - report failure to phone + assert(0); // FIXME - report failure to phone } // saveToDisk(); @@ -210,7 +219,7 @@ const char *preftmp = "/db.proto.tmp"; void NodeDB::loadFromDisk() { #ifdef FS - static DeviceState scratch; + // static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM auto f = FS.open(preffile); if (f) { @@ -219,16 +228,17 @@ void NodeDB::loadFromDisk() // DEBUG_MSG("Preload channel name=%s\n", channelSettings.name); - memset(&scratch, 0, sizeof(scratch)); - if (!pb_decode(&stream, DeviceState_fields, &scratch)) { + memset(&devicestate, 0, sizeof(devicestate)); + if (!pb_decode(&stream, DeviceState_fields, &devicestate)) { DEBUG_MSG("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream)); + installDefaultDeviceState(); // Our in RAM copy might now be corrupt // FIXME - report failure to phone } else { - if (scratch.version < DEVICESTATE_MIN_VER) + if (devicestate.version < DEVICESTATE_MIN_VER) { DEBUG_MSG("Warn: devicestate is old, discarding\n"); - else { - DEBUG_MSG("Loaded saved preferences version %d\n", scratch.version); - devicestate = scratch; + installDefaultDeviceState(); + } else { + DEBUG_MSG("Loaded saved preferences version %d\n", devicestate.version); } // DEBUG_MSG("Postload channel name=%s\n", channelSettings.name); @@ -238,6 +248,7 @@ void NodeDB::loadFromDisk() } else { DEBUG_MSG("No saved preferences found\n"); } + #else DEBUG_MSG("ERROR: Filesystem not implemented\n"); #endif diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 0171228a8..611024e22 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -93,6 +93,9 @@ class NodeDB /// read our db from flash void loadFromDisk(); + + /// Reinit device state from scratch (not loading from disk) + void installDefaultDeviceState(); }; /** diff --git a/src/mesh/PacketHistory.h b/src/mesh/PacketHistory.h index 3cc81084f..d390915a2 100644 --- a/src/mesh/PacketHistory.h +++ b/src/mesh/PacketHistory.h @@ -35,9 +35,8 @@ class PacketRecordOrderFunction // If the timer ticks have rolled over the difference between times will be _enormous_. Handle that case specially uint32_t t1 = p1.rxTimeMsec, t2 = p2.rxTimeMsec; - if (abs(t1 - t2) > - UINT32_MAX / - 2) { // time must have rolled over, swap them because the new little number is 'bigger' than the old big number + if (t1 - t2 > UINT32_MAX / 2) { + // time must have rolled over, swap them because the new little number is 'bigger' than the old big number t1 = t2; t2 = p1.rxTimeMsec; } diff --git a/src/mesh/PointerQueue.h b/src/mesh/PointerQueue.h index ef97eac41..b587ac649 100644 --- a/src/mesh/PointerQueue.h +++ b/src/mesh/PointerQueue.h @@ -18,6 +18,7 @@ template class PointerQueue : public TypedQueue return this->dequeue(&p, maxWait) ? p : nullptr; } +#ifdef HAS_FREE_RTOS // returns a ptr or null if the queue was empty T *dequeuePtrFromISR(BaseType_t *higherPriWoken) { @@ -25,4 +26,5 @@ template class PointerQueue : public TypedQueue return this->dequeueFromISR(&p, higherPriWoken) ? p : nullptr; } +#endif }; diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 706fcdf0d..cb6991d43 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -3,6 +3,10 @@ #include "PeriodicTask.h" #include "RadioInterface.h" +#ifdef CubeCell_BoardPlus +#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED +#endif + #include // ESP32 has special rules about ISR code diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index 51cb587a8..beb58a8ed 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -48,7 +48,7 @@ struct PendingPacket { PendingPacket() {} PendingPacket(MeshPacket *p); - void setNextTx() { nextTxMsec = millis() + random(20 * 1000, 22 * 1000); } + void setNextTx() { nextTxMsec = millis() + random(20 * 1000L, 22 * 1000L); } }; class GlobalPacketIdHashFunction diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 444ccc7ad..fa425ddbe 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -34,7 +34,12 @@ Allocator &packetPool = staticPool; * * Currently we only allow one interface, that may change in the future */ -Router::Router() : fromRadioQueue(MAX_RX_FROMRADIO) {} +Router::Router() : fromRadioQueue(MAX_RX_FROMRADIO) +{ + DEBUG_MSG("Size of NodeInfo %d\n", sizeof(NodeInfo)); + DEBUG_MSG("Size of SubPacket %d\n", sizeof(SubPacket)); + DEBUG_MSG("Size of MeshPacket %d\n", sizeof(MeshPacket)); +} /** * do idle processing diff --git a/src/mesh/SX1262Interface.cpp b/src/mesh/SX1262Interface.cpp index 3fe4afa30..e9ec8e7f5 100644 --- a/src/mesh/SX1262Interface.cpp +++ b/src/mesh/SX1262Interface.cpp @@ -25,7 +25,7 @@ bool SX1262Interface::init() float tcxoVoltage = 0; // None - we use an XTAL #else float tcxoVoltage = - 2.4; // E22 uses DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575 + 1.8; // E22 uses DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575 #endif bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC? @@ -35,7 +35,7 @@ bool SX1262Interface::init() int res = lora.begin(freq, bw, sf, cr, syncWord, power, currentLimit, preambleLength, tcxoVoltage, useRegulatorLDO); DEBUG_MSG("LORA init result %d\n", res); -#ifdef SX1262_RXEN +#ifdef SX1262_TXEN // lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX if (res == ERR_NONE) res = lora.setDio2AsRfSwitch(false); @@ -101,7 +101,7 @@ void SX1262Interface::setStandby() #ifdef SX1262_RXEN // we have RXEN/TXEN control - turn off RX and TX power digitalWrite(SX1262_RXEN, LOW); -#endif +#endif #ifdef SX1262_TXEN digitalWrite(SX1262_TXEN, LOW); #endif diff --git a/src/mesh/TypedQueue.h b/src/mesh/TypedQueue.h index a16e624f9..90ed07f10 100644 --- a/src/mesh/TypedQueue.h +++ b/src/mesh/TypedQueue.h @@ -5,6 +5,8 @@ #include "freertosinc.h" +#ifdef HAS_FREE_RTOS + /** * A wrapper for freertos queues. Note: each element object should be small * and POD (Plain Old Data type) as elements are memcpied by value. @@ -35,3 +37,45 @@ template class TypedQueue bool dequeueFromISR(T *p, BaseType_t *higherPriWoken) { return xQueueReceiveFromISR(h, p, higherPriWoken); } }; + +#else + +#include + +/** + * A wrapper for freertos queues. Note: each element object should be small + * and POD (Plain Old Data type) as elements are memcpied by value. + */ +template class TypedQueue +{ + std::queue q; + + public: + TypedQueue(int maxElements) {} + + // int numFree() { return uxQueueSpacesAvailable(h); } + + bool isEmpty() { return q.empty(); } + + bool enqueue(T x, TickType_t maxWait = portMAX_DELAY) + { + q.push(x); + return true; + } + + // bool enqueueFromISR(T x, BaseType_t *higherPriWoken) { return xQueueSendToBackFromISR(h, &x, higherPriWoken) == pdTRUE; } + + bool dequeue(T *p, TickType_t maxWait = portMAX_DELAY) + { + if (isEmpty()) + return false; + else { + *p = q.front(); + q.pop(); + return true; + } + } + + // bool dequeueFromISR(T *p, BaseType_t *higherPriWoken) { return xQueueReceiveFromISR(h, p, higherPriWoken); } +}; +#endif diff --git a/src/mesh/mesh-pb-constants.h b/src/mesh/mesh-pb-constants.h index baa9f5b55..789eb14ab 100644 --- a/src/mesh/mesh-pb-constants.h +++ b/src/mesh/mesh-pb-constants.h @@ -8,7 +8,9 @@ #define member_size(type, member) sizeof(((type *)0)->member) /// max number of packets which can be waiting for delivery to android - note, this value comes from mesh.options protobuf -#define MAX_RX_TOPHONE (member_size(DeviceState, receive_queue) / member_size(DeviceState, receive_queue[0])) +// FIXME - max_count is actually 32 but we save/load this as one long string of preencoded MeshPacket bytes - not a big array in RAM +// #define MAX_RX_TOPHONE (member_size(DeviceState, receive_queue) / member_size(DeviceState, receive_queue[0])) +#define MAX_RX_TOPHONE 32 /// max number of nodes allowed in the mesh #define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0])) diff --git a/src/mesh/mesh.pb.c b/src/mesh/mesh.pb.c index 88db1a219..ddc720cf3 100644 --- a/src/mesh/mesh.pb.c +++ b/src/mesh/mesh.pb.c @@ -39,7 +39,7 @@ PB_BIND(NodeInfo, NodeInfo, AUTO) PB_BIND(MyNodeInfo, MyNodeInfo, AUTO) -PB_BIND(DeviceState, DeviceState, 4) +PB_BIND(DeviceState, DeviceState, 2) PB_BIND(DebugString, DebugString, 2) diff --git a/src/mesh/mesh.pb.h b/src/mesh/mesh.pb.h index 8e4ba34bb..2651d6cb6 100644 --- a/src/mesh/mesh.pb.h +++ b/src/mesh/mesh.pb.h @@ -183,7 +183,7 @@ typedef struct _DeviceState { pb_size_t node_db_count; NodeInfo node_db[32]; pb_size_t receive_queue_count; - MeshPacket receive_queue[32]; + MeshPacket receive_queue[1]; bool has_rx_text_message; MeshPacket rx_text_message; uint32_t version; @@ -244,7 +244,7 @@ typedef struct _ToRadio { #define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0} -#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default}, false, MeshPacket_init_default, 0} +#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0} #define DebugString_init_default {""} #define FromRadio_init_default {0, 0, {MeshPacket_init_default}} #define ToRadio_init_default {0, {MeshPacket_init_default}} @@ -260,7 +260,7 @@ typedef struct _ToRadio { #define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0} -#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero}, false, MeshPacket_init_zero, 0} +#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0} #define DebugString_init_zero {""} #define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}} #define ToRadio_init_zero {0, {MeshPacket_init_zero}} @@ -596,7 +596,7 @@ extern const pb_msgdesc_t ManufacturingData_msg; #define RadioConfig_UserPreferences_size 93 #define NodeInfo_size 132 #define MyNodeInfo_size 110 -#define DeviceState_size 15100 +#define DeviceState_size 5305 #define DebugString_size 258 #define FromRadio_size 322 #define ToRadio_size 316 diff --git a/src/nrf52/PmuBQ25703A.cpp b/src/nrf52/PmuBQ25703A.cpp deleted file mode 100644 index c369ca2b1..000000000 --- a/src/nrf52/PmuBQ25703A.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#ifdef ARDUINO_NRF52840_PPR -#include "PmuBQ25703A.h" -#include - -// Default address for device. Note, it is without read/write bit. When read with analyser, -// this will appear 1 bit shifted to the left -#define BQ25703ADevaddr 0xD6 - -const byte Lorro_BQ25703A::BQ25703Aaddr = BQ25703ADevaddr; - -void PmuBQ25703A::init() -{ - // Set the watchdog timer to not have a timeout - regs.chargeOption0.set_WDTMR_ADJ(0); - assert(writeRegEx(regs.chargeOption0)); // FIXME, instead log a critical hw failure and reboot - delay(15); // FIXME, why are these delays required? - check datasheet - - // Set the ADC on IBAT and PSYS to record values - // When changing bitfield values, call the writeRegEx function - // This is so you can change all the bits you want before sending out the byte. - regs.chargeOption1.set_EN_IBAT(1); - regs.chargeOption1.set_EN_PSYS(1); - assert(writeRegEx(regs.chargeOption1)); - delay(15); - - // Set ADC to make continuous readings. (uses more power) - regs.aDCOption.set_ADC_CONV(1); - // Set individual ADC registers to read. All have default off. - regs.aDCOption.set_EN_ADC_VBUS(1); - regs.aDCOption.set_EN_ADC_PSYS(1); - regs.aDCOption.set_EN_ADC_IDCHG(1); - regs.aDCOption.set_EN_ADC_ICHG(1); - regs.aDCOption.set_EN_ADC_VSYS(1); - regs.aDCOption.set_EN_ADC_VBAT(1); - // Once bits have been twiddled, send bytes to device - assert(writeRegEx(regs.aDCOption)); - delay(15); -} - -#endif - -/* - - -//Initialise the device and library -Lorro_BQ25703A BQ25703A; - -//Instantiate with reference to global set -extern Lorro_BQ25703A::Regt BQ25703Areg; - -uint32_t previousMillis; -uint16_t loopInterval = 1000; - -void setup() { - - Serial.begin(115200); - - -} - -void loop() { - - uint32_t currentMillis = millis(); - - if( currentMillis - previousMillis > loopInterval ){ - previousMillis = currentMillis; - - Serial.print( "Voltage of VBUS: " ); - Serial.print( BQ25703Areg.aDCVBUSPSYS.get_VBUS() ); - Serial.println( "mV" ); - delay( 15 ); - - Serial.print( "System power usage: " ); - Serial.print( BQ25703Areg.aDCVBUSPSYS.get_sysPower() ); - Serial.println( "W" ); - delay( 15 ); - - Serial.print( "Voltage of VBAT: " ); - Serial.print( BQ25703Areg.aDCVSYSVBAT.get_VBAT() ); - Serial.println( "mV" ); - delay( 15 ); - - Serial.print( "Voltage of VSYS: " ); - Serial.print( BQ25703Areg.aDCVSYSVBAT.get_VSYS() ); - Serial.println( "mV" ); - delay( 15 ); - - Serial.print( "Charging current: " ); - Serial.print( BQ25703Areg.aDCIBAT.get_ICHG() ); - Serial.println( "mA" ); - delay( 15 ); - - Serial.print( "Voltage of VSYS: " ); - Serial.print( BQ25703Areg.aDCIBAT.get_IDCHG() ); - Serial.println( "mA" ); - delay( 15 ); - - } - -}*/ \ No newline at end of file diff --git a/src/nrf52/PmuBQ25703A.h b/src/nrf52/PmuBQ25703A.h deleted file mode 100644 index 804b85bf9..000000000 --- a/src/nrf52/PmuBQ25703A.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -class PmuBQ25703A : private Lorro_BQ25703A -{ - Lorro_BQ25703A::Regt regs; - - public: - /** - * Configure the PMU for our board - */ - void init(); - - // Methods to have a common API with AXP192 - bool isBatteryConnect() { return true; } // FIXME - bool isVBUSPlug() { return true; } - bool isChargeing() { return true; } // FIXME, intentional misspelling - - /// battery voltage in mV - int getBattVoltage() { return 3200; } -}; diff --git a/src/nrf52/SPIFFS.h b/src/nrf52/SPIFFS.h deleted file mode 100644 index 819693660..000000000 --- a/src/nrf52/SPIFFS.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -// FIXME - make a FS abstraction for NRF52 \ No newline at end of file