From a491ceefcda593a6c900f2b5c79a74c0162a551a Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 1 Jun 2023 07:14:55 -0500 Subject: [PATCH] Wio-e5 wip (#2265) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Wio-e5 / STM32WL wip * Stubbing some FS stuff out * Wio-e5 / STM32WL wip * Stubbing some FS stuff out * Wio-e5 / STM32WL wip * Stubbing some FS stuff out * Wio-e5 / STM32WL wip * Stubbing some FS stuff out * LittleFS compiles. Can't check with actual device. * make cppcheck happy again * Guard against accelerometer thread * Missed a spot * Upload via ST-LINK * Derive MAC address from UID * upload port * Trunk it * Guard it * Maybe fix the cache error on startup. * Latest RadioLib ref to fix SubGHZ * revert nasty Sub-GHz Hack * Boots and radio inits with RadioLib 6.0, LittleFS doesn't seem to work --------- Co-authored-by: Thomas Göttgens Co-authored-by: GUVWAF --- arch/stm32/stm32wl5e.ini | 17 +- boards/generic_wl5e.json | 2 +- platformio.ini | 3 +- src/FSCommon.cpp | 2 +- src/FSCommon.h | 9 +- src/freertosinc.h | 2 +- src/main.cpp | 22 +- src/mesh/InterfacesTemplates.cpp | 3 + src/mesh/RadioLibInterface.h | 17 + src/mesh/STM32WLE5JCInterface.cpp | 45 +++ src/mesh/STM32WLE5JCInterface.h | 31 ++ src/modules/ExternalNotificationModule.h | 2 +- src/platform/stm32wl/InternalFileSystem.cpp | 141 ++++++++ src/platform/stm32wl/InternalFileSystem.h | 54 +++ src/platform/stm32wl/LittleFS.cpp | 258 ++++++++++++++ src/platform/stm32wl/LittleFS.h | 85 +++++ src/platform/stm32wl/LittleFS_File.cpp | 362 ++++++++++++++++++++ src/platform/stm32wl/LittleFS_File.h | 82 +++++ src/platform/stm32wl/architecture.h | 17 +- src/platform/stm32wl/layer.c | 65 ---- src/platform/stm32wl/main-stm32wl.cpp | 14 +- src/shutdown.h | 2 +- src/xmodem.h | 2 +- variants/wio-e5/platformio.ini | 10 +- variants/wio-e5/variant.h | 14 +- 25 files changed, 1153 insertions(+), 108 deletions(-) create mode 100644 src/mesh/STM32WLE5JCInterface.cpp create mode 100644 src/mesh/STM32WLE5JCInterface.h create mode 100644 src/platform/stm32wl/InternalFileSystem.cpp create mode 100644 src/platform/stm32wl/InternalFileSystem.h create mode 100644 src/platform/stm32wl/LittleFS.cpp create mode 100644 src/platform/stm32wl/LittleFS.h create mode 100644 src/platform/stm32wl/LittleFS_File.cpp create mode 100644 src/platform/stm32wl/LittleFS_File.h delete mode 100644 src/platform/stm32wl/layer.c diff --git a/arch/stm32/stm32wl5e.ini b/arch/stm32/stm32wl5e.ini index b610bf40b..d3d577a9f 100644 --- a/arch/stm32/stm32wl5e.ini +++ b/arch/stm32/stm32wl5e.ini @@ -1,20 +1,29 @@ [stm32wl5e_base] -platform = platformio/ststm32@^15.4.1 +platform_packages = platformio/framework-arduinoststm32 @ https://github.com/stm32duino/Arduino_Core_STM32.git#6e3f9910d0122e82a6c3438507dfac3d2fd80a39 +platform = ststm32 board = generic_wl5e framework = arduino build_type = debug -build_flags = + +build_flags = ${arduino_base.build_flags} -Isrc/platform/stm32wl -g + -DconfigUSE_CMSIS_RTOS_V2=1 + -DVECT_TAB_OFFSET=0x08000000 + +build_src_filter = + ${arduino_base.build_src_filter} - - - - - - - - - - - - - -build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - - - - - - +board_upload.offset_address = 0x08000000 +upload_protocol = stlink lib_deps = ${env.lib_deps} jgromes/RadioLib@^6.0.0 https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b + https://github.com/littlefs-project/littlefs.git#v2.5.1 + https://github.com/stm32duino/STM32FreeRTOS.git#10.3.1 lib_ignore = https://github.com/mathertel/OneButton#2.1.0 diff --git a/boards/generic_wl5e.json b/boards/generic_wl5e.json index 433c55b59..5c4bc24a7 100644 --- a/boards/generic_wl5e.json +++ b/boards/generic_wl5e.json @@ -20,7 +20,7 @@ "maximum_ram_size": 65536, "maximum_size": 262144, "protocol": "cmsis-dap", - "protocols": ["cmsis-dap"] + "protocols": ["cmsis-dap", "stlink"] }, "url": "https://www.st.com/en/microcontrollers-microprocessors/stm32wl-series.html", "vendor": "ST" diff --git a/platformio.ini b/platformio.ini index 156eb0076..9abb56b7a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2,7 +2,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = tbeam +;default_envs = tbeam ;default_envs = pico ;default_envs = tbeam-s3-core ;default_envs = tbeam0.7 @@ -25,6 +25,7 @@ default_envs = tbeam ;default_envs = meshtastic-dr-dev ;default_envs = m5stack-coreink ;default_envs = rak4631 +default_envs = wio-e5 extra_configs = arch/*/*.ini diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index cc99caed8..150391237 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -57,7 +57,7 @@ bool renameFile(const char *pathFrom, const char *pathTo) #endif } -void listDir(const char *dirname, uint8_t levels, boolean del = false) +void listDir(const char *dirname, uint8_t levels, bool del = false) { #ifdef FSCom #if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)) diff --git a/src/FSCommon.h b/src/FSCommon.h index 98d3911d7..ef1d3e4c1 100644 --- a/src/FSCommon.h +++ b/src/FSCommon.h @@ -13,6 +13,13 @@ #define FILE_O_READ "r" #endif +#if defined(ARCH_STM32WL) +#include "platform/stm32wl/InternalFileSystem.h" // STM32WL version +#define FSCom InternalFS +#define FSBegin() FSCom.begin() +using namespace LittleFS_Namespace; +#endif + #if defined(ARCH_RP2040) // RP2040 #include "LittleFS.h" @@ -42,6 +49,6 @@ using namespace Adafruit_LittleFS_Namespace; void fsInit(); bool copyFile(const char *from, const char *to); bool renameFile(const char *pathFrom, const char *pathTo); -void listDir(const char *dirname, uint8_t levels, boolean del); +void listDir(const char *dirname, uint8_t levels, bool del); void rmDir(const char *dirname); void setupSDCard(); \ No newline at end of file diff --git a/src/freertosinc.h b/src/freertosinc.h index c5dfddc8e..dbe7c4001 100644 --- a/src/freertosinc.h +++ b/src/freertosinc.h @@ -12,7 +12,7 @@ #include #endif -#if defined(ARDUINO_NRF52_ADAFRUIT) +#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_STM32) #define HAS_FREE_RTOS #include diff --git a/src/main.cpp b/src/main.cpp index 5120cb269..e7ce565c5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -59,6 +59,9 @@ NRF52Bluetooth *nrf52Bluetooth; #include "SX1262Interface.h" #include "SX1268Interface.h" #include "SX1280Interface.h" +#ifdef ARCH_STM32WL +#include "STM32WLE5JCInterface.h" +#endif #if !HAS_RADIO && defined(ARCH_PORTDUINO) #include "platform/portduino/SimRadio.h" #endif @@ -68,7 +71,7 @@ NRF52Bluetooth *nrf52Bluetooth; #endif #include "PowerFSMThread.h" -#if !defined(ARCH_PORTDUINO) +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) #include "AccelerometerThread.h" #endif @@ -347,10 +350,11 @@ void setup() * nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field * "found". */ + // Only one supported RGB LED currently rgb_found = i2cScanner->find(ScanI2C::DeviceType::NCP5623); -#if !defined(ARCH_PORTDUINO) +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) auto acc_info = i2cScanner->firstAccelerometer(); accelerometer_found = acc_info.type != ScanI2C::DeviceType::NONE ? acc_info.address : accelerometer_found; LOG_DEBUG("acc_info = %i\n", acc_info.type); @@ -439,7 +443,7 @@ void setup() screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // keep dimension of 128x64 #endif -#if !defined(ARCH_PORTDUINO) +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) if (acc_info.type != ScanI2C::DeviceType::NONE) { accelerometerThread = new AccelerometerThread(acc_info.type); } @@ -530,6 +534,18 @@ void setup() #endif // radio init MUST BE AFTER service.init, so we have our radio config settings (from nodedb init) +#if defined(USE_STM32WLx) + if (!rIf) { + rIf = new STM32WLE5JCInterface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY); + if (!rIf->init()) { + LOG_WARN("Failed to find STM32WL radio\n"); + delete rIf; + rIf = NULL; + } else { + LOG_INFO("STM32WL Radio init succeeded, using STM32WL radio\n"); + } + } +#endif #if !HAS_RADIO && defined(ARCH_PORTDUINO) if (!rIf) { diff --git a/src/mesh/InterfacesTemplates.cpp b/src/mesh/InterfacesTemplates.cpp index 73b0bdfbc..c732829e9 100644 --- a/src/mesh/InterfacesTemplates.cpp +++ b/src/mesh/InterfacesTemplates.cpp @@ -10,6 +10,9 @@ template class SX126xInterface; template class SX126xInterface; template class SX126xInterface; template class SX128xInterface; +#ifdef ARCH_STM32WL +template class SX126xInterface; +#endif #if HAS_ETHERNET #include "api/ethServerAPI.h" diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 6635089e5..4634ca7ee 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -27,6 +27,19 @@ class LockingArduinoHal : public ArduinoHal void spiEndTransaction() override; }; +#if defined(USE_STM32WLx) +/** + * A wrapper for the RadioLib STM32WLx_Module class, that doesn't connect any pins as they are virtual + */ +class STM32WLx_ModuleWrapper : public STM32WLx_Module +{ + public: + STM32WLx_ModuleWrapper(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, + RADIOLIB_PIN_TYPE busy) + : STM32WLx_Module(){}; +}; +#endif + class RadioLibInterface : public RadioInterface, protected concurrency::NotifiedWorkerThread { /// Used as our notification from the ISR @@ -56,7 +69,11 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified float currentLimit = 100; // 100mA OCP - Should be acceptable for RFM95/SX127x chipset. +#if !defined(USE_STM32WLx) Module module; // The HW interface to the radio +#else + STM32WLx_ModuleWrapper module; +#endif /** * provides lowest common denominator RadioLib API diff --git a/src/mesh/STM32WLE5JCInterface.cpp b/src/mesh/STM32WLE5JCInterface.cpp new file mode 100644 index 000000000..5b6fd0844 --- /dev/null +++ b/src/mesh/STM32WLE5JCInterface.cpp @@ -0,0 +1,45 @@ +#include "STM32WLE5JCInterface.h" +#include "configuration.h" +#include "error.h" + +#ifndef STM32WLx_MAX_POWER +#define STM32WLx_MAX_POWER 22 +#endif + +#ifdef ARCH_STM32WL + +STM32WLE5JCInterface::STM32WLE5JCInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, + RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy) + : SX126xInterface(hal, cs, irq, rst, busy) +{ +} + +bool STM32WLE5JCInterface::init() +{ + RadioLibInterface::init(); + + lora.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + if (power == 0) + power = STM32WLx_MAX_POWER; + + if (power > STM32WLx_MAX_POWER) // This chip has lower power limits than some + power = STM32WLx_MAX_POWER; + + limitPower(); + + int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage); + + LOG_INFO("STM32WLx init result %d\n", res); + + LOG_INFO("Frequency set to %f\n", getFreq()); + LOG_INFO("Bandwidth set to %f\n", bw); + LOG_INFO("Power output set to %d\n", power); + + if (res == RADIOLIB_ERR_NONE) + startReceive(); // start receiving + + return res == RADIOLIB_ERR_NONE; +} + +#endif // ARCH_STM32WL diff --git a/src/mesh/STM32WLE5JCInterface.h b/src/mesh/STM32WLE5JCInterface.h new file mode 100644 index 000000000..73d53d92f --- /dev/null +++ b/src/mesh/STM32WLE5JCInterface.h @@ -0,0 +1,31 @@ +#pragma once + +#include "SX126xInterface.h" + +#ifdef ARCH_STM32WL + +/** + * Our adapter for STM32WLE5JC radios + */ +class STM32WLE5JCInterface : public SX126xInterface +{ + public: + STM32WLE5JCInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, + RADIOLIB_PIN_TYPE busy); + + virtual bool init() override; +}; + +// https://github.com/Seeed-Studio/LoRaWan-E5-Node/blob/main/Middlewares/Third_Party/SubGHz_Phy/stm32_radio_driver/radio_driver.c +static const float tcxoVoltage = 1.7; + +/* https://wiki.seeedstudio.com/LoRa-E5_STM32WLE5JC_Module/ + * Wio-E5 module ONLY transmits through RFO_HP + * Receive: PA4=1, PA5=0 + * Transmit(high output power, SMPS mode): PA4=0, PA5=1 */ +static const RADIOLIB_PIN_TYPE rfswitch_pins[3] = {PA4, PA5, RADIOLIB_NC}; + +static const Module::RfSwitchMode_t rfswitch_table[4] = { + {STM32WLx::MODE_IDLE, {LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, LOW}}, {STM32WLx::MODE_TX_HP, {LOW, HIGH}}, END_OF_MODE_TABLE}; + +#endif // ARCH_STM32WL \ No newline at end of file diff --git a/src/modules/ExternalNotificationModule.h b/src/modules/ExternalNotificationModule.h index 7d4f54c2f..f8ec053dd 100644 --- a/src/modules/ExternalNotificationModule.h +++ b/src/modules/ExternalNotificationModule.h @@ -3,7 +3,7 @@ #include "SinglePortModule.h" #include "concurrency/OSThread.h" #include "configuration.h" -#ifndef ARCH_PORTDUINO +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) #include #else // Noop class for portduino. diff --git a/src/platform/stm32wl/InternalFileSystem.cpp b/src/platform/stm32wl/InternalFileSystem.cpp new file mode 100644 index 000000000..950ceb0cd --- /dev/null +++ b/src/platform/stm32wl/InternalFileSystem.cpp @@ -0,0 +1,141 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 hathach for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "InternalFileSystem.h" +#include + +//--------------------------------------------------------------------+ +// LFS Disk IO +//--------------------------------------------------------------------+ + +static inline uint32_t lba2addr(uint32_t block) +{ + return ((uint32_t)LFS_FLASH_ADDR) + block * LFS_BLOCK_SIZE; +} + +static int _internal_flash_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) +{ + (void)c; + + uint32_t addr = lba2addr(block) + off; + uint8_t prom; + + for (int i = 0; i < size; i++) { + prom = EEPROM.read(addr + i); + memcpy((char *)buffer + i, &prom, 1); + } + return 0; +} + +// Program a region in a block. The block must have previously +// been erased. Negative error codes are propogated to the user. +// May return LFS_ERR_CORRUPT if the block should be considered bad. +static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) +{ + (void)c; + + uint32_t addr = lba2addr(block) + off; + uint8_t prom; + + for (int i = 0; i < size; i++) { + memcpy(&prom, (char *)buffer + i, 1); + EEPROM.update(addr + i, prom); + } + return 0; +} + +// Erase a block. A block must be erased before being programmed. +// The state of an erased block is undefined. Negative error codes +// are propogated to the user. +// May return LFS_ERR_CORRUPT if the block should be considered bad. +static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block) +{ + (void)c; + + uint32_t addr = lba2addr(block); + + // implement as write 0xff to whole block address + for (int i = 0; i < LFS_BLOCK_SIZE; i++) { + EEPROM.update(addr, 0xff); + } + + return 0; +} + +// Sync the state of the underlying block device. Negative error codes +// are propogated to the user. +static int _internal_flash_sync(const struct lfs_config *c) +{ + // we don't use a ram cache, this is a noop + return 0; +} + +static struct lfs_config _InternalFSConfig = {.context = NULL, + + .read = _internal_flash_read, + .prog = _internal_flash_prog, + .erase = _internal_flash_erase, + .sync = _internal_flash_sync, + + .read_size = LFS_CACHE_SIZE, + .prog_size = LFS_CACHE_SIZE, + .block_size = LFS_BLOCK_SIZE, + .block_count = LFS_FLASH_TOTAL_SIZE / LFS_BLOCK_SIZE, + .block_cycles = + 500, // protection against wear leveling (suggested values between 100-1000) + .cache_size = LFS_CACHE_SIZE, + .lookahead_size = LFS_CACHE_SIZE, + + .read_buffer = lfs_read_buffer, + .prog_buffer = lfs_prog_buffer, + .lookahead_buffer = lfs_lookahead_buffer}; + +InternalFileSystem InternalFS; + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +InternalFileSystem::InternalFileSystem(void) : LittleFS(&_InternalFSConfig) {} + +bool InternalFileSystem::begin(void) +{ + // failed to mount, erase all sector then format and mount again + if (!LittleFS::begin()) { + // Erase all sectors of internal flash region for Filesystem. + // implement as write 0xff to whole block address + for (uint32_t addr = LFS_FLASH_ADDR; addr < (LFS_FLASH_ADDR + LFS_FLASH_TOTAL_SIZE); addr++) { + EEPROM.update(addr, 0xff); + } + + // lfs format + this->format(); + + // mount again if still failed, give up + if (!LittleFS::begin()) + return false; + } + + return true; +} diff --git a/src/platform/stm32wl/InternalFileSystem.h b/src/platform/stm32wl/InternalFileSystem.h new file mode 100644 index 000000000..66344194e --- /dev/null +++ b/src/platform/stm32wl/InternalFileSystem.h @@ -0,0 +1,54 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 hathach for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef INTERNALFILESYSTEM_H_ +#define INTERNALFILESYSTEM_H_ + +#include "LittleFS.h" + +// The EEPROM Library assumes our usable flash area starts at logical 0 +#define LFS_FLASH_ADDR 0 + +// use the built in EEPROM emulation. Total Size is 2Kbyte +#define LFS_BLOCK_SIZE 128 // min. block size is 128 to fit CTZ pointers +#define LFS_CACHE_SIZE 16 + +#define LFS_FLASH_TOTAL_SIZE FLASH_PAGE_SIZE + +static uint8_t lfs_read_buffer[LFS_CACHE_SIZE] = {0}; +static uint8_t lfs_prog_buffer[LFS_CACHE_SIZE] = {0}; +static uint8_t lfs_lookahead_buffer[LFS_CACHE_SIZE] = {0}; + +class InternalFileSystem : public LittleFS +{ + public: + InternalFileSystem(void); + + // overwrite to also perform low level format (sector erase of whole flash region) + bool begin(void); +}; + +extern InternalFileSystem InternalFS; + +#endif /* INTERNALFILESYSTEM_H_ */ diff --git a/src/platform/stm32wl/LittleFS.cpp b/src/platform/stm32wl/LittleFS.cpp new file mode 100644 index 000000000..b1267d88a --- /dev/null +++ b/src/platform/stm32wl/LittleFS.cpp @@ -0,0 +1,258 @@ +#include +#include + +#include "LittleFS.h" + +using namespace LittleFS_Namespace; + +//--------------------------------------------------------------------+ +// Implementation +//--------------------------------------------------------------------+ + +LittleFS::LittleFS(void) : LittleFS(NULL) {} + +LittleFS::LittleFS(struct lfs_config *cfg) +{ + memset(&_lfs, 0, sizeof(_lfs)); + _lfs_cfg = cfg; + _mounted = false; + _mutex = xSemaphoreCreateMutexStatic(&this->_MutexStorageSpace); +} + +LittleFS::~LittleFS() {} + +// Initialize and mount the file system +// Return true if mounted successfully else probably corrupted. +// User should format the disk and try again +bool LittleFS::begin(struct lfs_config *cfg) +{ + _lockFS(); + + bool ret; + // not a loop, just an quick way to short-circuit on error + do { + if (_mounted) { + ret = true; + break; + } + if (cfg) { + _lfs_cfg = cfg; + } + if (nullptr == _lfs_cfg) { + ret = false; + break; + } + // actually attempt to mount, and log error if one occurs + int err = lfs_mount(&_lfs, _lfs_cfg); + PRINT_LFS_ERR(err); + _mounted = (err == LFS_ERR_OK); + ret = _mounted; + } while (0); + + _unlockFS(); + return ret; +} + +// Tear down and unmount file system +void LittleFS::end(void) +{ + _lockFS(); + + if (_mounted) { + _mounted = false; + int err = lfs_unmount(&_lfs); + PRINT_LFS_ERR(err); + (void)err; + } + + _unlockFS(); +} + +bool LittleFS::format(void) +{ + _lockFS(); + + int err = LFS_ERR_OK; + bool attemptMount = _mounted; + // not a loop, just an quick way to short-circuit on error + do { + // if already mounted: umount first -> format -> remount + if (_mounted) { + _mounted = false; + err = lfs_unmount(&_lfs); + if (LFS_ERR_OK != err) { + PRINT_LFS_ERR(err); + break; + } + } + err = lfs_format(&_lfs, _lfs_cfg); + if (LFS_ERR_OK != err) { + PRINT_LFS_ERR(err); + break; + } + + if (attemptMount) { + err = lfs_mount(&_lfs, _lfs_cfg); + if (LFS_ERR_OK != err) { + PRINT_LFS_ERR(err); + break; + } + _mounted = true; + } + // success! + } while (0); + + _unlockFS(); + return LFS_ERR_OK == err; +} + +// Open a file or folder +LittleFS_Namespace::File LittleFS::open(char const *filepath, uint8_t mode) +{ + // No lock is required here ... the File() object will synchronize with the mutex provided + return LittleFS_Namespace::File(filepath, mode, *this); +} + +// Check if file or folder exists +bool LittleFS::exists(char const *filepath) +{ + struct lfs_info info; + _lockFS(); + + bool ret = (0 == lfs_stat(&_lfs, filepath, &info)); + + _unlockFS(); + return ret; +} + +// Create a directory, create intermediate parent if needed +bool LittleFS::mkdir(char const *filepath) +{ + bool ret = true; + const char *slash = filepath; + if (slash[0] == '/') + slash++; // skip root '/' + + _lockFS(); + + // make intermediate parent directory(ies) + while (NULL != (slash = strchr(slash, '/'))) { + char parent[slash - filepath + 1] = {0}; + memcpy(parent, filepath, slash - filepath); + + int rc = lfs_mkdir(&_lfs, parent); + if (rc != LFS_ERR_OK && rc != LFS_ERR_EXIST) { + PRINT_LFS_ERR(rc); + ret = false; + break; + } + slash++; + } + // make the final requested directory + if (ret) { + int rc = lfs_mkdir(&_lfs, filepath); + if (rc != LFS_ERR_OK && rc != LFS_ERR_EXIST) { + PRINT_LFS_ERR(rc); + ret = false; + } + } + + _unlockFS(); + return ret; +} + +// Remove a file +bool LittleFS::remove(char const *filepath) +{ + _lockFS(); + + int err = lfs_remove(&_lfs, filepath); + PRINT_LFS_ERR(err); + + _unlockFS(); + return LFS_ERR_OK == err; +} + +// Rename a file +bool LittleFS::rename(char const *oldfilepath, char const *newfilepath) +{ + _lockFS(); + + int err = lfs_rename(&_lfs, oldfilepath, newfilepath); + PRINT_LFS_ERR(err); + + _unlockFS(); + return LFS_ERR_OK == err; +} + +// Remove a folder +bool LittleFS::rmdir(char const *filepath) +{ + _lockFS(); + + int err = lfs_remove(&_lfs, filepath); + PRINT_LFS_ERR(err); + + _unlockFS(); + return LFS_ERR_OK == err; +} + +// Remove a folder recursively +bool LittleFS::rmdir_r(char const *filepath) +{ + /* adafruit: lfs is modified to remove non-empty folder, + According to below issue, comment these 2 line won't corrupt filesystem + at least when using LFS v1. If moving to LFS v2, see tracked issue + to see if issues (such as the orphans in threaded linked list) are resolved. + https://github.com/ARMmbed/littlefs/issues/43 + */ + _lockFS(); + + int err = lfs_remove(&_lfs, filepath); + PRINT_LFS_ERR(err); + + _unlockFS(); + return LFS_ERR_OK == err; +} + +//------------- Debug -------------// +#if CFG_DEBUG + +const char *dbg_strerr_lfs(int32_t err) +{ + switch (err) { + case LFS_ERR_OK: + return "LFS_ERR_OK"; + case LFS_ERR_IO: + return "LFS_ERR_IO"; + case LFS_ERR_CORRUPT: + return "LFS_ERR_CORRUPT"; + case LFS_ERR_NOENT: + return "LFS_ERR_NOENT"; + case LFS_ERR_EXIST: + return "LFS_ERR_EXIST"; + case LFS_ERR_NOTDIR: + return "LFS_ERR_NOTDIR"; + case LFS_ERR_ISDIR: + return "LFS_ERR_ISDIR"; + case LFS_ERR_NOTEMPTY: + return "LFS_ERR_NOTEMPTY"; + case LFS_ERR_BADF: + return "LFS_ERR_BADF"; + case LFS_ERR_INVAL: + return "LFS_ERR_INVAL"; + case LFS_ERR_NOSPC: + return "LFS_ERR_NOSPC"; + case LFS_ERR_NOMEM: + return "LFS_ERR_NOMEM"; + + default: + static char errcode[10]; + sprintf(errcode, "%ld", err); + return errcode; + } + + return NULL; +} + +#endif diff --git a/src/platform/stm32wl/LittleFS.h b/src/platform/stm32wl/LittleFS.h new file mode 100644 index 000000000..4a0b01af2 --- /dev/null +++ b/src/platform/stm32wl/LittleFS.h @@ -0,0 +1,85 @@ + +#ifndef LITTLEFS_H_ +#define LITTLEFS_H_ + +#include + +#include "lfs.h" + +#include "LittleFS_File.h" + +#include "FreeRTOS.h" // tied to FreeRTOS for serialization +#include "semphr.h" + +class LittleFS +{ + public: + LittleFS(void); + explicit LittleFS(struct lfs_config *cfg); + virtual ~LittleFS(); + + bool begin(struct lfs_config *cfg = NULL); + void end(void); + + // Open the specified file/directory with the supplied mode (e.g. read or + // write, etc). Returns a File object for interacting with the file. + // Note that currently only one file can be open at a time. + LittleFS_Namespace::File open(char const *filename, uint8_t mode = LittleFS_Namespace::FILE_O_READ); + + // Methods to determine if the requested file path exists. + bool exists(char const *filepath); + + // Create the requested directory hierarchy--if intermediate directories + // do not exist they will be created. + bool mkdir(char const *filepath); + + // Delete the file. + bool remove(char const *filepath); + + // Rename the file. + bool rename(char const *oldfilepath, char const *newfilepath); + + // Delete a folder (must be empty) + bool rmdir(char const *filepath); + + // Delete a folder (recursively) + bool rmdir_r(char const *filepath); + + // format file system + bool format(void); + + /*------------------------------------------------------------------*/ + /* INTERNAL USAGE ONLY + * Although declare as public, it is meant to be invoked by internal + * code. User should not call these directly + *------------------------------------------------------------------*/ + lfs_t *_getFS(void) { return &_lfs; } + void _lockFS(void) { xSemaphoreTake(_mutex, portMAX_DELAY); } + void _unlockFS(void) { xSemaphoreGive(_mutex); } + + protected: + bool _mounted; + struct lfs_config *_lfs_cfg; + lfs_t _lfs; + SemaphoreHandle_t _mutex; + + private: + StaticSemaphore_t _MutexStorageSpace; +}; + +#if !CFG_DEBUG +#define VERIFY_LFS(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, NULL) +#define PRINT_LFS_ERR(_err) +#else +#define VERIFY_LFS(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, dbg_strerr_lfs) +#define PRINT_LFS_ERR(_err) \ + do { \ + if (_err) { \ + VERIFY_MESS((long int)_err, dbg_strerr_lfs); \ + } \ + } while (0) // LFS_ERR are of type int, VERIFY_MESS expects long_int + +const char *dbg_strerr_lfs(int32_t err); +#endif + +#endif /* LITTLEFS_H_ */ diff --git a/src/platform/stm32wl/LittleFS_File.cpp b/src/platform/stm32wl/LittleFS_File.cpp new file mode 100644 index 000000000..cffb924e1 --- /dev/null +++ b/src/platform/stm32wl/LittleFS_File.cpp @@ -0,0 +1,362 @@ +#include + +#include "LittleFS.h" + +#include + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + +using namespace LittleFS_Namespace; + +File::File(LittleFS &fs) +{ + _fs = &fs; + _is_dir = false; + _name[0] = 0; + _dir_path = NULL; + + _dir = NULL; + _file = NULL; +} + +File::File(char const *filename, uint8_t mode, LittleFS &fs) : File(fs) +{ + // public constructor calls public API open(), which will obtain the mutex + this->open(filename, mode); +} + +bool File::_open_file(char const *filepath, uint8_t mode) +{ + int flags = (mode == FILE_O_READ) ? LFS_O_RDONLY : (mode == FILE_O_WRITE) ? (LFS_O_RDWR | LFS_O_CREAT) : 0; + + if (flags) { + _file = (lfs_file_t *)malloc(sizeof(lfs_file_t)); + if (!_file) + return false; + + int rc = lfs_file_open(_fs->_getFS(), _file, filepath, flags); + + if (rc) { + // failed to open + PRINT_LFS_ERR(rc); + return false; + } + + // move to end of file + if (mode == FILE_O_WRITE) + lfs_file_seek(_fs->_getFS(), _file, 0, LFS_SEEK_END); + + _is_dir = false; + } + + return true; +} + +bool File::_open_dir(char const *filepath) +{ + _dir = (lfs_dir_t *)malloc(sizeof(lfs_dir_t)); + if (!_dir) + return false; + + int rc = lfs_dir_open(_fs->_getFS(), _dir, filepath); + + if (rc) { + // failed to open + PRINT_LFS_ERR(rc); + return false; + } + + _is_dir = true; + + _dir_path = (char *)malloc(strlen(filepath) + 1); + strcpy(_dir_path, filepath); + + return true; +} + +bool File::open(char const *filepath, uint8_t mode) +{ + bool ret = false; + _fs->_lockFS(); + + ret = this->_open(filepath, mode); + + _fs->_unlockFS(); + return ret; +} + +bool File::_open(char const *filepath, uint8_t mode) +{ + bool ret = false; + + // close if currently opened + if (this->isOpen()) + _close(); + + struct lfs_info info; + int rc = lfs_stat(_fs->_getFS(), filepath, &info); + + if (LFS_ERR_OK == rc) { + // file existed, open file or directory accordingly + ret = (info.type == LFS_TYPE_REG) ? _open_file(filepath, mode) : _open_dir(filepath); + } else if (LFS_ERR_NOENT == rc) { + // file not existed, only proceed with FILE_O_WRITE mode + if (mode == FILE_O_WRITE) + ret = _open_file(filepath, mode); + } else { + PRINT_LFS_ERR(rc); + } + + // save bare file name + if (ret) { + char const *splash = strrchr(filepath, '/'); + strncpy(_name, splash ? (splash + 1) : filepath, LFS_NAME_MAX); + } + return ret; +} + +size_t File::write(uint8_t ch) +{ + return write(&ch, 1); +} + +size_t File::write(uint8_t const *buf, size_t size) +{ + lfs_ssize_t wrcount = 0; + _fs->_lockFS(); + + if (!this->_is_dir) { + wrcount = lfs_file_write(_fs->_getFS(), _file, buf, size); + if (wrcount < 0) { + wrcount = 0; + } + } + + _fs->_unlockFS(); + return wrcount; +} + +int File::read(void) +{ + // this thin wrapper relies on called function to synchronize + int ret = -1; + uint8_t ch; + if (read(&ch, 1) > 0) { + ret = static_cast(ch); + } + return ret; +} + +int File::read(void *buf, uint16_t nbyte) +{ + int ret = 0; + _fs->_lockFS(); + + if (!this->_is_dir) { + ret = lfs_file_read(_fs->_getFS(), _file, buf, nbyte); + } + + _fs->_unlockFS(); + return ret; +} + +int File::peek(void) +{ + int ret = -1; + _fs->_lockFS(); + + if (!this->_is_dir) { + uint32_t pos = lfs_file_tell(_fs->_getFS(), _file); + uint8_t ch = 0; + if (lfs_file_read(_fs->_getFS(), _file, &ch, 1) > 0) { + ret = static_cast(ch); + } + (void)lfs_file_seek(_fs->_getFS(), _file, pos, LFS_SEEK_SET); + } + + _fs->_unlockFS(); + return ret; +} + +int File::available(void) +{ + int ret = 0; + _fs->_lockFS(); + + if (!this->_is_dir) { + uint32_t size = lfs_file_size(_fs->_getFS(), _file); + uint32_t pos = lfs_file_tell(_fs->_getFS(), _file); + ret = size - pos; + } + + _fs->_unlockFS(); + return ret; +} + +bool File::seek(uint32_t pos) +{ + bool ret = false; + _fs->_lockFS(); + + if (!this->_is_dir) { + ret = lfs_file_seek(_fs->_getFS(), _file, pos, LFS_SEEK_SET) >= 0; + } + + _fs->_unlockFS(); + return ret; +} + +uint32_t File::position(void) +{ + uint32_t ret = 0; + _fs->_lockFS(); + + if (!this->_is_dir) { + ret = lfs_file_tell(_fs->_getFS(), _file); + } + + _fs->_unlockFS(); + return ret; +} + +uint32_t File::size(void) +{ + uint32_t ret = 0; + _fs->_lockFS(); + + if (!this->_is_dir) { + ret = lfs_file_size(_fs->_getFS(), _file); + } + + _fs->_unlockFS(); + return ret; +} + +bool File::truncate(uint32_t pos) +{ + int32_t ret = LFS_ERR_ISDIR; + _fs->_lockFS(); + if (!this->_is_dir) { + ret = lfs_file_truncate(_fs->_getFS(), _file, pos); + } + _fs->_unlockFS(); + return (ret == 0); +} + +bool File::truncate(void) +{ + int32_t ret = LFS_ERR_ISDIR; + _fs->_lockFS(); + if (!this->_is_dir) { + uint32_t pos = lfs_file_tell(_fs->_getFS(), _file); + ret = lfs_file_truncate(_fs->_getFS(), _file, pos); + } + _fs->_unlockFS(); + return (ret == 0); +} + +void File::flush(void) +{ + _fs->_lockFS(); + + if (!this->_is_dir) { + lfs_file_sync(_fs->_getFS(), _file); + } + + _fs->_unlockFS(); + return; +} + +void File::close(void) +{ + _fs->_lockFS(); + this->_close(); + _fs->_unlockFS(); +} + +void File::_close(void) +{ + if (this->isOpen()) { + if (this->_is_dir) { + lfs_dir_close(_fs->_getFS(), _dir); + free(_dir); + _dir = NULL; + + if (this->_dir_path) + free(_dir_path); + _dir_path = NULL; + } else { + lfs_file_close(this->_fs->_getFS(), _file); + free(_file); + _file = NULL; + } + } +} + +File::operator bool(void) +{ + return isOpen(); +} + +bool File::isOpen(void) +{ + return (_file != NULL) || (_dir != NULL); +} + +// WARNING -- although marked as `const`, the values pointed +// to may change. For example, if the same File +// object has `open()` called with a different +// file or directory name, this same pointer will +// suddenly (unexpectedly?) have different values. +char const *File::name(void) +{ + return this->_name; +} + +bool File::isDirectory(void) +{ + return this->_is_dir; +} + +File File::openNextFile(uint8_t mode) +{ + _fs->_lockFS(); + + File ret(*_fs); + if (this->_is_dir) { + struct lfs_info info; + int rc; + + // lfs_dir_read returns 0 when reaching end of directory, 1 if found an entry + // Skip the "." and ".." entries ... + do { + rc = lfs_dir_read(_fs->_getFS(), _dir, &info); + } while (rc == 1 && (!strcmp(".", info.name) || !strcmp("..", info.name))); + + if (rc == 1) { + // string cat name with current folder + char filepath[strlen(_dir_path) + 1 + strlen(info.name) + 1]; // potential for significant stack usage + strcpy(filepath, _dir_path); + if (!(_dir_path[0] == '/' && _dir_path[1] == 0)) + strcat(filepath, "/"); // only add '/' if cwd is not root + strcat(filepath, info.name); + + (void)ret._open(filepath, mode); // return value is ignored ... caller is expected to check isOpened() + } else if (rc < 0) { + PRINT_LFS_ERR(rc); + } + } + _fs->_unlockFS(); + return ret; +} + +void File::rewindDirectory(void) +{ + _fs->_lockFS(); + if (this->_is_dir) { + lfs_dir_rewind(_fs->_getFS(), _dir); + } + _fs->_unlockFS(); +} diff --git a/src/platform/stm32wl/LittleFS_File.h b/src/platform/stm32wl/LittleFS_File.h new file mode 100644 index 000000000..e88a2790d --- /dev/null +++ b/src/platform/stm32wl/LittleFS_File.h @@ -0,0 +1,82 @@ +#ifndef LITTLEFS_FILE_H_ +#define LITTLEFS_FILE_H_ + +// Forward declaration +class LittleFS; + +namespace LittleFS_Namespace +{ + +// avoid conflict with other FileSystem FILE_READ/FILE_WRITE +enum { + FILE_O_READ = 0, + FILE_O_WRITE = 1, +}; + +class File : public Stream +{ + public: + explicit File(LittleFS &fs); + File(char const *filename, uint8_t mode, LittleFS &fs); + + public: + bool open(char const *filename, uint8_t mode); + + //------------- Stream API -------------// + virtual size_t write(uint8_t ch); + virtual size_t write(uint8_t const *buf, size_t size); + size_t write(const char *str) + { + if (str == NULL) + return 0; + return write((const uint8_t *)str, strlen(str)); + } + size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); } + + virtual int read(void); + int read(void *buf, uint16_t nbyte); + + virtual int peek(void); + virtual int available(void); + virtual void flush(void); + + bool seek(uint32_t pos); + uint32_t position(void); + uint32_t size(void); + + bool truncate(uint32_t pos); + bool truncate(void); + + void close(void); + + operator bool(void); + + bool isOpen(void); + char const *name(void); + + bool isDirectory(void); + File openNextFile(uint8_t mode = FILE_O_READ); + void rewindDirectory(void); + + private: + LittleFS *_fs; + + bool _is_dir; + + union { + lfs_file_t *_file; + lfs_dir_t *_dir; + }; + + char *_dir_path; + char _name[LFS_NAME_MAX + 1]; + + bool _open(char const *filepath, uint8_t mode); + bool _open_file(char const *filepath, uint8_t mode); + bool _open_dir(char const *filepath); + void _close(void); +}; + +} // namespace LittleFS_Namespace + +#endif /* LITTLEFS_FILE_H_ */ diff --git a/src/platform/stm32wl/architecture.h b/src/platform/stm32wl/architecture.h index dc7adc5ff..1c021903a 100644 --- a/src/platform/stm32wl/architecture.h +++ b/src/platform/stm32wl/architecture.h @@ -6,24 +6,19 @@ // defaults for STM32WL architecture // +#ifndef HAS_RADIO +#define HAS_RADIO 1 +#endif + // // set HW_VENDOR // #ifndef HW_VENDOR -#define HW_VENDOR HardwareModel_PRIVATE_HW +#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW #endif -#ifdef __cplusplus -extern "C" { -#endif -void stm32wl_emulate_digitalWrite(long unsigned int pin, long unsigned int value); -int stm32wl_emulate_digitalRead(long unsigned int pin); -#ifdef __cplusplus -} -#endif - -/* virtual pins for stm32wl_emulate_digitalWrite() / stm32wl_emulate_digitalRead() to recognize */ +/* virtual pins */ #define SX126X_CS 1000 #define SX126X_DIO1 1001 #define SX126X_RESET 1003 diff --git a/src/platform/stm32wl/layer.c b/src/platform/stm32wl/layer.c deleted file mode 100644 index d6f073200..000000000 --- a/src/platform/stm32wl/layer.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "architecture.h" -#include "stm32wlxx.h" -#include "stm32wlxx_hal.h" -#include - -void HardFault_Handler(void) -{ - asm("bkpt"); -} - -void stm32wl_emulate_digitalWrite(long unsigned int pin, long unsigned int value) -{ - switch (pin) { - case SX126X_CS: /* active low */ - if (value) - LL_PWR_UnselectSUBGHZSPI_NSS(); - else - LL_PWR_SelectSUBGHZSPI_NSS(); - break; - case SX126X_RESET: /* active low */ - if (value) - LL_RCC_RF_DisableReset(); - else { - LL_RCC_RF_EnableReset(); - LL_RCC_HSE_EnableTcxo(); - LL_RCC_HSE_Enable(); - while (!LL_RCC_HSE_IsReady()) - ; - } - break; - default: - asm("bkpt"); - break; - } -} - -static bool irq_happened; - -void SUBGHZ_Radio_IRQHandler(void) -{ - NVIC_DisableIRQ(SUBGHZ_Radio_IRQn); - irq_happened = true; -} - -int stm32wl_emulate_digitalRead(long unsigned int pin) -{ - int outcome = 0; - - switch (pin) { - case SX126X_BUSY: - // return ((LL_PWR_IsActiveFlag_RFBUSYMS() & LL_PWR_IsActiveFlag_RFBUSYS()) == 1UL); - outcome = LL_PWR_IsActiveFlag_RFBUSYS(); - break; - case SX126X_DIO1: - default: - NVIC_ClearPendingIRQ(SUBGHZ_Radio_IRQn); - irq_happened = false; - NVIC_EnableIRQ(SUBGHZ_Radio_IRQn); - for (int i = 0; i < 64; i++) - asm("nop"); - outcome = irq_happened; - break; - } - return outcome; -} diff --git a/src/platform/stm32wl/main-stm32wl.cpp b/src/platform/stm32wl/main-stm32wl.cpp index 8ebcb029e..f57928c60 100644 --- a/src/platform/stm32wl/main-stm32wl.cpp +++ b/src/platform/stm32wl/main-stm32wl.cpp @@ -11,8 +11,18 @@ void updateBatteryLevel(uint8_t level) {} void getMacAddr(uint8_t *dmac) { - for (int i = 0; i < 6; i++) - dmac[i] = i; + // https://flit.github.io/2020/06/06/mcu-unique-id-survey.html + const uint32_t uid0 = HAL_GetUIDw0(); // X/Y coordinate on wafer + const uint32_t uid1 = HAL_GetUIDw1(); // [31:8] Lot number (23:0), [7:0] Wafer number + const uint32_t uid2 = HAL_GetUIDw2(); // Lot number (55:24) + + // Need to go from 96-bit to 48-bit unique ID + dmac[5] = (uint8_t)uid0; + dmac[4] = (uint8_t)(uid0 >> 16); + dmac[3] = (uint8_t)uid1; + dmac[2] = (uint8_t)(uid1 >> 8); + dmac[1] = (uint8_t)uid2; + dmac[0] = (uint8_t)(uid2 >> 8); } void cpuDeepSleep(uint32_t msecToWake) {} diff --git a/src/shutdown.h b/src/shutdown.h index b08478a1e..ee63422dd 100644 --- a/src/shutdown.h +++ b/src/shutdown.h @@ -26,8 +26,8 @@ void powerCommandsCheck() if (shutdownAtMsec && millis() > shutdownAtMsec) { LOG_INFO("Shutting down from admin command\n"); - playShutdownMelody(); #if defined(ARCH_NRF52) || defined(ARCH_ESP32) + playShutdownMelody(); power->shutdown(); #else LOG_WARN("FIXME implement shutdown for this platform"); diff --git a/src/xmodem.h b/src/xmodem.h index 848e926bd..2ba0bb39f 100644 --- a/src/xmodem.h +++ b/src/xmodem.h @@ -59,7 +59,7 @@ class XModemAdapter uint16_t packetno = 0; -#if defined(ARCH_NRF52) +#if defined(ARCH_NRF52) || defined(ARCH_STM32WL) File file = File(FSCom); #else File file; diff --git a/variants/wio-e5/platformio.ini b/variants/wio-e5/platformio.ini index 32436dae8..07f6efa6d 100644 --- a/variants/wio-e5/platformio.ini +++ b/variants/wio-e5/platformio.ini @@ -1,5 +1,11 @@ [env:wio-e5] extends = stm32wl5e_base board_level = extra -build_flags = ${stm32wl5e_base.build_flags} -Ivariants/wio-e5 -DHAL_DAC_MODULE_ONLY - -DSERIAL_UART_INSTANCE=1 -DPIN_SERIAL_RX=PB7 -DPIN_SERIAL_TX=PB6 +build_flags = + ${stm32wl5e_base.build_flags} + -Ivariants/wio-e5 + -DHAL_DAC_MODULE_ONLY + -DSERIAL_UART_INSTANCE=1 + -DPIN_SERIAL_RX=PB7 + -DPIN_SERIAL_TX=PB6 +upload_port = stlink \ No newline at end of file diff --git a/variants/wio-e5/variant.h b/variants/wio-e5/variant.h index b1f7556b4..86e58bcb2 100644 --- a/variants/wio-e5/variant.h +++ b/variants/wio-e5/variant.h @@ -12,18 +12,6 @@ Do not expect a working Meshtastic device with this target. #ifndef _VARIANT_WIOE5_ #define _VARIANT_WIOE5_ -// Arduino/PlatformIO support for SUBGHZSPI is not currently available -//#define USE_SX1262 - -#ifdef USE_SX1262 -#define HAS_RADIO 1 - -/* module only transmits through RFO_HP */ -#define SX126X_RXEN PA5 -#define SX126X_TXEN PA4 - -/* TCXO fed by internal LDO option behind PB0 pin */ -#define SX126X_E22 -#endif +#define USE_STM32WLx #endif \ No newline at end of file