kopia lustrzana https://github.com/meshtastic/firmware
Merge branch 'thinknode-m2' of https://github.com/meshtastic/firmware into thinknode-m2
commit
2a968a77d4
|
@ -29,6 +29,7 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|||
gpg \
|
||||
gnupg2 \
|
||||
libusb-1.0-0-dev \
|
||||
libuv1-dev \
|
||||
libi2c-dev \
|
||||
libxcb-xkb-dev \
|
||||
libxkbcommon-dev \
|
||||
|
|
|
@ -72,6 +72,15 @@ body:
|
|||
validations:
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: mui
|
||||
attributes:
|
||||
label: Is this bug report about any UI component firmware like InkHUD or Meshtatic UI (MUI)?
|
||||
options:
|
||||
- label: Meshtastic UI aka MUI colorTFT
|
||||
- label: InkHUD ePaper
|
||||
- label: OLED slide UI on any display
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
|
|
|
@ -11,4 +11,4 @@ runs:
|
|||
- name: Install libs needed for native build
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
|
||||
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev libuv1-dev
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
## 🙏 Thank you for sending in a pull request, here's some tips to get started!
|
||||
|
||||
### ❌ (Please delete all these tips and replace them with your text) ❌
|
||||
|
||||
## Thank you for sending in a pull request, here's some tips to get started!
|
||||
|
||||
- Before starting on some new big chunk of code, it it is optional but highly recommended to open an issue first
|
||||
to say "Hey, I think this idea X should be implemented and I'm starting work on it. My general plan is Y, any feedback
|
||||
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
|
||||
|
@ -12,4 +11,17 @@
|
|||
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
|
||||
- If your other co-developers have comments on your PR please tweak as needed.
|
||||
- Please also enable "Allow edits by maintainers".
|
||||
- Please do not submit untested code.
|
||||
- If you do not have the affected hardware to test your code changes adequately against regressions, please indicate this, so that contributors and commnunity members can help test your changes.
|
||||
- If your PR gets accepted you can request a "Contributor" role in the Meshtastic Discord
|
||||
|
||||
|
||||
## 🤝 Attestations
|
||||
- [ ] I have tested that my proposed changes behave as described.
|
||||
- [ ] I have tested that my proposed changes do not cause any obvious regressions on the following devices:
|
||||
- [ ] Heltec (Lora32) V3
|
||||
- [ ] LilyGo T-Deck
|
||||
- [ ] LilyGo T-Beam
|
||||
- [ ] RAK WisBlock 4631
|
||||
- [ ] Seeed Studio T-1000E tracker card
|
||||
- [ ] Other (please specify below)
|
||||
|
|
|
@ -9,14 +9,14 @@ plugins:
|
|||
lint:
|
||||
enabled:
|
||||
- prettier@3.5.3
|
||||
- trufflehog@3.88.17
|
||||
- yamllint@1.36.2
|
||||
- trufflehog@3.88.18
|
||||
- yamllint@1.37.0
|
||||
- bandit@1.8.3
|
||||
- checkov@3.2.386
|
||||
- checkov@3.2.392
|
||||
- terrascan@1.19.9
|
||||
- trivy@0.60.0
|
||||
- taplo@0.9.3
|
||||
- ruff@0.11.0
|
||||
- ruff@0.11.2
|
||||
- isort@6.0.1
|
||||
- markdownlint@0.44.0
|
||||
- oxipng@9.1.4
|
||||
|
@ -28,7 +28,7 @@ lint:
|
|||
- shellcheck@0.10.0
|
||||
- black@25.1.0
|
||||
- git-diff-check
|
||||
- gitleaks@8.24.0
|
||||
- gitleaks@8.24.2
|
||||
- clang-format@16.0.3
|
||||
ignore:
|
||||
- linters: [ALL]
|
||||
|
|
|
@ -13,7 +13,7 @@ ENV TZ=Etc/UTC
|
|||
ENV PIP_ROOT_USER_ACTION=ignore
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
wget g++ zip git ca-certificates \
|
||||
libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev \
|
||||
libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev libuv1-dev \
|
||||
libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev pkg-config \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
|
||||
&& pip install --no-cache-dir -U platformio \
|
||||
|
@ -38,7 +38,7 @@ ENV TZ=Etc/UTC
|
|||
USER root
|
||||
|
||||
RUN apt-get update && apt-get --no-install-recommends -y install \
|
||||
libc-bin libc6 libgpiod2 libyaml-cpp0.7 libi2c0 libulfius2.7 libusb-1.0-0-dev liborcania2.3 libssl3 \
|
||||
libc-bin libc6 libgpiod2 libyaml-cpp0.7 libi2c0 libuv1 libusb-1.0-0-dev liborcania2.3 libulfius2.7 libssl3 \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p /var/lib/meshtasticd \
|
||||
&& mkdir -p /etc/meshtasticd/config.d \
|
||||
|
|
|
@ -9,7 +9,7 @@ FROM python:3.13-alpine3.21 AS builder
|
|||
ENV PIP_ROOT_USER_ACTION=ignore
|
||||
RUN apk --no-cache add \
|
||||
bash g++ libstdc++-dev linux-headers zip git ca-certificates libgpiod-dev yaml-cpp-dev bluez-dev \
|
||||
libusb-dev i2c-tools-dev openssl-dev pkgconf argp-standalone \
|
||||
libusb-dev i2c-tools-dev libuv-dev openssl-dev pkgconf argp-standalone \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& pip install --no-cache-dir -U platformio \
|
||||
&& mkdir /tmp/firmware
|
||||
|
@ -32,7 +32,7 @@ FROM alpine:3.21
|
|||
USER root
|
||||
|
||||
RUN apk --no-cache add \
|
||||
libstdc++ libgpiod yaml-cpp libusb i2c-tools \
|
||||
libstdc++ libgpiod yaml-cpp libusb i2c-tools libuv \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& mkdir -p /var/lib/meshtasticd \
|
||||
&& mkdir -p /etc/meshtasticd/config.d \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
; The Portduino based 'native' environment. Currently supported on Linux targets with real LoRa hardware (or simulated).
|
||||
[portduino_base]
|
||||
platform = https://github.com/meshtastic/platform-native.git#562d189828f09fbf4c4093b3c0104bae9d8e9ff9
|
||||
platform = https://github.com/meshtastic/platform-native.git#e82ba1a19b6cd1dc55cbde29b33ea8dd0640014f
|
||||
framework = arduino
|
||||
|
||||
build_src_filter =
|
||||
|
@ -34,10 +34,12 @@ build_flags =
|
|||
-Isrc/platform/portduino
|
||||
-DRADIOLIB_EEPROM_UNSUPPORTED
|
||||
-DPORTDUINO_LINUX_HARDWARE
|
||||
-DHAS_UDP_MULTICAST
|
||||
-lpthread
|
||||
-lstdc++fs
|
||||
-lbluetooth
|
||||
-lgpiod
|
||||
-lyaml-cpp
|
||||
-li2c
|
||||
-luv
|
||||
-std=c++17
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
[stm32_base]
|
||||
extends = arduino_base
|
||||
platform = platformio/ststm32
|
||||
platform_packages = platformio/framework-arduinoststm32@^4.20900.0
|
||||
platform = ststm32
|
||||
platform_packages = platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32.git#2.9.0
|
||||
extra_scripts =
|
||||
${env.extra_scripts}
|
||||
post:extra_scripts/extra_stm32.py
|
||||
|
||||
build_type = release
|
||||
|
||||
;board_build.flash_offset = 0x08000000
|
||||
|
||||
build_flags =
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
-flto
|
||||
-Isrc/platform/stm32wl -g
|
||||
|
@ -18,27 +19,24 @@ build_flags =
|
|||
-DMESHTASTIC_EXCLUDE_SCREEN
|
||||
-DMESHTASTIC_EXCLUDE_MQTT
|
||||
-DMESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
-DMESHTASTIC_EXCLUDE_PKI
|
||||
-DMESHTASTIC_EXCLUDE_GPS
|
||||
; -DVECT_TAB_OFFSET=0x08000000
|
||||
-DconfigUSE_CMSIS_RTOS_V2=1
|
||||
; -DSPI_MODE_0=SPI_MODE0
|
||||
;-DDEBUG_MUTE
|
||||
-fmerge-all-constants
|
||||
-ffunction-sections
|
||||
-fdata-sections
|
||||
|
||||
build_src_filter =
|
||||
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/RemoteHardwareModule.cpp> -<platform/nrf52> -<platform/portduino> -<platform/rp2xx0> -<mesh/raspihttp>
|
||||
|
||||
board_upload.offset_address = 0x08000000
|
||||
upload_protocol = stlink
|
||||
debug_tool = stlink
|
||||
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
charlesbaynham/OSFS@^1.2.3
|
||||
jgromes/RadioLib@7.0.2
|
||||
https://github.com/caveman99/Crypto.git#f61ae26a53f7a2d0ba5511625b8bf8eff3a35d5e
|
||||
${radiolib_base.lib_deps}
|
||||
https://github.com/caveman99/Crypto.git#eae9c768054118a9399690f8af202853d1ae8516
|
||||
|
||||
lib_ignore =
|
||||
mathertel/OneButton@2.6.1
|
||||
Wire
|
||||
Wire
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Module: RF95 # Adafruit RFM9x
|
||||
# Reset: 25
|
||||
# CS: 7
|
||||
# IRQ: 22
|
||||
# Busy: 23
|
||||
Lora:
|
||||
Module: RF95 # Adafruit RFM9x
|
||||
Reset: 25
|
||||
CS: 7
|
||||
IRQ: 22
|
||||
# Busy: 23
|
||||
|
|
|
@ -17,8 +17,8 @@ SET "LOGCOUNTER=0"
|
|||
SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone"
|
||||
SET "C3=esp32c3"
|
||||
@REM FIXME: Determine flash size from PlatformIO variant, this is unmaintainable.
|
||||
SET "BIGDB_8MB=picomputer-s3 unphone seeed-sensecap-indicator crowpanel-esp32s3 heltec_capsule_sensor_v3 heltec-v3 heltec-vision-master-e213 heltec-vision-master-e290 heltec-vision-master-t190 heltec-wireless-paper heltec-wireless-tracker heltec-wsl-v3 icarus seeed-xiao-s3 tbeam-s3-core tracksenger"
|
||||
SET "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite t-watch-s3"
|
||||
SET "BIGDB_8MB=picomputer-s3 unphone seeed-sensecap-indicator crowpanel-esp32s3 heltec_capsule_sensor_v3 heltec-v3 heltec-vision-master-e213 heltec-vision-master-e290 heltec-vision-master-t190 heltec-wireless-paper heltec-wireless-tracker heltec-wsl-v3 icarus seeed-xiao-s3 tbeam-s3-core t-watch-s3 tracksenger"
|
||||
SET "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite"
|
||||
|
||||
GOTO getopts
|
||||
:help
|
||||
|
|
|
@ -22,6 +22,7 @@ BIGDB_8MB=(
|
|||
"icarus"
|
||||
"seeed-xiao-s3"
|
||||
"tbeam-s3-core"
|
||||
"t-watch-s3"
|
||||
"tracksenger"
|
||||
)
|
||||
BIGDB_16MB=(
|
||||
|
@ -33,7 +34,6 @@ BIGDB_16MB=(
|
|||
"m5stack-cores3"
|
||||
"station-g2"
|
||||
"t-eth-elite"
|
||||
"t-watch-s3"
|
||||
)
|
||||
S3_VARIANTS=(
|
||||
"s3"
|
||||
|
|
|
@ -17,6 +17,7 @@ Build-Depends: debhelper-compat (= 13),
|
|||
libbluetooth-dev,
|
||||
libusb-1.0-0-dev,
|
||||
libi2c-dev,
|
||||
libuv1-dev,
|
||||
openssl,
|
||||
libssl-dev,
|
||||
libulfius-dev,
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# trunk-ignore-all(ruff/F821)
|
||||
# trunk-ignore-all(flake8/F821): For SConstruct imports
|
||||
|
||||
Import("env")
|
||||
# Custom HEX from ELF
|
||||
env.AddPostAction(
|
||||
"$BUILD_DIR/${PROGNAME}.elf",
|
||||
env.VerboseAction(
|
||||
" ".join(
|
||||
[
|
||||
"$OBJCOPY",
|
||||
"-O",
|
||||
"ihex",
|
||||
"-R",
|
||||
".eeprom",
|
||||
"$BUILD_DIR/${PROGNAME}.elf",
|
||||
"$BUILD_DIR/${PROGNAME}.hex",
|
||||
]
|
||||
),
|
||||
"Building $BUILD_DIR/${PROGNAME}.hex",
|
||||
),
|
||||
)
|
|
@ -36,6 +36,7 @@ BuildRequires: pkgconfig(libgpiod)
|
|||
BuildRequires: pkgconfig(bluez)
|
||||
BuildRequires: pkgconfig(libusb-1.0)
|
||||
BuildRequires: libi2c-devel
|
||||
BuildRequires: pkgconfig(libuv)
|
||||
# Web components:
|
||||
BuildRequires: pkgconfig(openssl)
|
||||
BuildRequires: pkgconfig(liborcania)
|
||||
|
|
|
@ -94,7 +94,7 @@ lib_deps =
|
|||
|
||||
[device-ui_base]
|
||||
lib_deps =
|
||||
https://github.com/meshtastic/device-ui.git#74e739ed4532ca10393df9fc89ae5a22f0bab2b1
|
||||
https://github.com/meshtastic/device-ui.git#b1e862e8b2a604a8d911e9d7a27f6e80f1176c21
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
; (not included in native / portduino)
|
||||
|
|
|
@ -41,10 +41,8 @@ class AudioThread : public concurrency::OSThread
|
|||
delete i2sRtttl;
|
||||
i2sRtttl = nullptr;
|
||||
}
|
||||
if (rtttlFile != nullptr) {
|
||||
delete rtttlFile;
|
||||
rtttlFile = nullptr;
|
||||
}
|
||||
delete rtttlFile;
|
||||
rtttlFile = nullptr;
|
||||
|
||||
setCPUFast(false);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
|
|||
#ifdef USERPREFS_BUTTON_PIN
|
||||
int pin = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN; // Resolved button pin
|
||||
#endif
|
||||
#if defined(HELTEC_CAPSULE_SENSOR_V3)
|
||||
#if defined(HELTEC_CAPSULE_SENSOR_V3) || defined(HELTEC_SENSOR_HUB)
|
||||
this->userButton = OneButton(pin, false, false);
|
||||
#elif defined(BUTTON_ACTIVE_LOW)
|
||||
this->userButton = OneButton(pin, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP);
|
||||
|
|
|
@ -29,30 +29,6 @@ SPIClass SPI1(HSPI);
|
|||
|
||||
#endif // HAS_SDCARD
|
||||
|
||||
#if defined(ARCH_STM32WL)
|
||||
|
||||
uint16_t OSFS::startOfEEPROM = 1;
|
||||
uint16_t OSFS::endOfEEPROM = 2048;
|
||||
|
||||
// 3) How do I read from the medium?
|
||||
void OSFS::readNBytes(uint16_t address, unsigned int num, byte *output)
|
||||
{
|
||||
for (uint16_t i = address; i < address + num; i++) {
|
||||
*output = EEPROM.read(i);
|
||||
output++;
|
||||
}
|
||||
}
|
||||
|
||||
// 4) How to I write to the medium?
|
||||
void OSFS::writeNBytes(uint16_t address, unsigned int num, const byte *input)
|
||||
{
|
||||
for (uint16_t i = address; i < address + num; i++) {
|
||||
EEPROM.update(i, *input);
|
||||
input++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Copies a file from one location to another.
|
||||
*
|
||||
|
@ -62,33 +38,7 @@ void OSFS::writeNBytes(uint16_t address, unsigned int num, const byte *input)
|
|||
*/
|
||||
bool copyFile(const char *from, const char *to)
|
||||
{
|
||||
#ifdef ARCH_STM32WL
|
||||
unsigned char cbuffer[2048];
|
||||
|
||||
// Var to hold the result of actions
|
||||
OSFS::result r;
|
||||
|
||||
r = OSFS::getFile(from, cbuffer);
|
||||
|
||||
if (r == notfound) {
|
||||
LOG_ERROR("Failed to open source file %s", from);
|
||||
return false;
|
||||
} else if (r == noerr) {
|
||||
r = OSFS::newFile(to, cbuffer, true);
|
||||
if (r == noerr) {
|
||||
return true;
|
||||
} else {
|
||||
LOG_ERROR("OSFS Error %d", r);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG_ERROR("OSFS Error %d", r);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
#elif defined(FSCom)
|
||||
#ifdef FSCom
|
||||
// take SPI Lock
|
||||
concurrency::LockGuard g(spiLock);
|
||||
unsigned char cbuffer[16];
|
||||
|
@ -127,13 +77,7 @@ bool copyFile(const char *from, const char *to)
|
|||
*/
|
||||
bool renameFile(const char *pathFrom, const char *pathTo)
|
||||
{
|
||||
#ifdef ARCH_STM32WL
|
||||
if (copyFile(pathFrom, pathTo) && (OSFS::deleteFile(pathFrom) == OSFS::result::NO_ERROR)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#elif defined(FSCom)
|
||||
#ifdef FSCom
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// take SPI Lock
|
||||
|
|
|
@ -15,13 +15,11 @@
|
|||
#endif
|
||||
|
||||
#if defined(ARCH_STM32WL)
|
||||
// STM32WL series 2 Kbytes (8 rows of 256 bytes)
|
||||
#include <EEPROM.h>
|
||||
#include <OSFS.h>
|
||||
|
||||
// Useful consts
|
||||
const OSFS::result noerr = OSFS::result::NO_ERROR;
|
||||
const OSFS::result notfound = OSFS::result::FILE_NOT_FOUND;
|
||||
// STM32WL
|
||||
#include "LittleFS.h"
|
||||
#define FSCom InternalFS
|
||||
#define FSBegin() FSCom.begin()
|
||||
using namespace STM32_LittleFS_Namespace;
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_RP2040)
|
||||
|
|
|
@ -391,7 +391,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||
virtual bool isVbusIn() override
|
||||
{
|
||||
#ifdef EXT_PWR_DETECT
|
||||
#ifdef HELTEC_CAPSULE_SENSOR_V3
|
||||
#if defined(HELTEC_CAPSULE_SENSOR_V3) || defined(HELTEC_SENSOR_HUB)
|
||||
// if external powered that pin will be pulled down
|
||||
if (digitalRead(EXT_PWR_DETECT) == LOW) {
|
||||
return true;
|
||||
|
@ -541,7 +541,7 @@ Power::Power() : OSThread("Power")
|
|||
bool Power::analogInit()
|
||||
{
|
||||
#ifdef EXT_PWR_DETECT
|
||||
#ifdef HELTEC_CAPSULE_SENSOR_V3
|
||||
#if defined(HELTEC_CAPSULE_SENSOR_V3) || defined(HELTEC_SENSOR_HUB)
|
||||
pinMode(EXT_PWR_DETECT, INPUT_PULLUP);
|
||||
#else
|
||||
pinMode(EXT_PWR_DETECT, INPUT);
|
||||
|
|
|
@ -1200,12 +1200,12 @@ GnssModel_t GPS::probe(int serialSpeed)
|
|||
PROBE_SIMPLE("LC86", "$PQTMVERNO*58", "$PQTMVERNO,LC86", GNSS_MODEL_AG3352, 500);
|
||||
PROBE_SIMPLE("L76K", "$PCAS06,0*1B", "$GPTXT,01,01,02,SW=", GNSS_MODEL_MTK, 500);
|
||||
|
||||
// Close all NMEA sentences, valid for L76B MTK platform (Waveshare Pico GPS)
|
||||
// Close all NMEA sentences, valid for MTK3333 and MTK3339 platforms
|
||||
_serial_gps->write("$PMTK514,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2E\r\n");
|
||||
delay(20);
|
||||
std::vector<ChipInfo> mtk = {{"L76B", "Quectel-L76B", GNSS_MODEL_MTK_L76B},
|
||||
{"PA1616S", "1616S", GNSS_MODEL_MTK_PA1616S},
|
||||
{"LS20031", "MC-1513", GNSS_MODEL_LS20031}};
|
||||
{"LS20031", "MC-1513", GNSS_MODEL_MTK_L76B}};
|
||||
PROBE_FAMILY("MTK Family", "$PMTK605*31", mtk, 500);
|
||||
|
||||
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
|
||||
|
|
|
@ -166,7 +166,8 @@ bool EInkDisplay::connect()
|
|||
}
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || \
|
||||
defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER)
|
||||
defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \
|
||||
defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
|
||||
{
|
||||
// Start HSPI
|
||||
hspi = new SPIClass(HSPI);
|
||||
|
@ -182,7 +183,7 @@ bool EInkDisplay::connect()
|
|||
// Init GxEPD2
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(3);
|
||||
#if defined(CROWPANEL_ESP32S3_5_EPAPER)
|
||||
#if defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER)
|
||||
adafruitDisplay->setRotation(0);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -68,7 +68,8 @@ class EInkDisplay : public OLEDDisplay
|
|||
|
||||
// If display uses HSPI
|
||||
#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \
|
||||
defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER)
|
||||
defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \
|
||||
defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
|
||||
SPIClass *hspi = NULL;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ void tftSetup(void)
|
|||
#ifdef ARCH_ESP32
|
||||
tftSleepObserver.observe(¬ifyLightSleep);
|
||||
endSleepObserver.observe(¬ifyLightSleepEnd);
|
||||
xTaskCreatePinnedToCore(tft_task_handler, "tft", 8192, NULL, 1, NULL, 0);
|
||||
xTaskCreatePinnedToCore(tft_task_handler, "tft", 10240, NULL, 1, NULL, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -827,6 +827,13 @@ void setup()
|
|||
#ifdef HAS_UDP_MULTICAST
|
||||
LOG_DEBUG("Start multicast thread");
|
||||
udpThread = new UdpMulticastThread();
|
||||
#ifdef ARCH_PORTDUINO
|
||||
// FIXME: portduino does not ever call onNetworkConnected so call it here because I don't know what happen if I call
|
||||
// onNetworkConnected there
|
||||
if (config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
|
||||
udpThread->start();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
service = new MeshService();
|
||||
service->init();
|
||||
|
|
|
@ -347,7 +347,7 @@ bool Channels::anyMqttEnabled()
|
|||
{
|
||||
#if USERPREFS_EVENT_MODE
|
||||
// Don't publish messages on the public MQTT broker if we are in event mode
|
||||
if (mqtt && mqtt.isUsingDefaultServer()) {
|
||||
if (mqtt && mqtt->isUsingDefaultServer()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -161,10 +161,8 @@ void CryptoEngine::hash(uint8_t *bytes, size_t numBytes)
|
|||
|
||||
void CryptoEngine::aesSetKey(const uint8_t *key_bytes, size_t key_len)
|
||||
{
|
||||
if (aes) {
|
||||
delete aes;
|
||||
aes = nullptr;
|
||||
}
|
||||
delete aes;
|
||||
aes = nullptr;
|
||||
if (key_len != 0) {
|
||||
aes = new AESSmall256();
|
||||
aes->setKey(key_bytes, key_len);
|
||||
|
@ -225,10 +223,8 @@ void CryptoEngine::decrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes
|
|||
// Generic implementation of AES-CTR encryption.
|
||||
void CryptoEngine::encryptAESCtr(CryptoKey _key, uint8_t *_nonce, size_t numBytes, uint8_t *bytes)
|
||||
{
|
||||
if (ctr) {
|
||||
delete ctr;
|
||||
ctr = nullptr;
|
||||
}
|
||||
delete ctr;
|
||||
ctr = nullptr;
|
||||
if (_key.length == 16)
|
||||
ctr = new CTR<AES128>();
|
||||
else
|
||||
|
|
|
@ -309,7 +309,10 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p)
|
|||
}
|
||||
}
|
||||
|
||||
assert(toPhoneQueue.enqueue(p, 0));
|
||||
if (toPhoneQueue.enqueue(p, 0) == false) {
|
||||
LOG_CRIT("Failed to queue a packet into toPhoneQueue!");
|
||||
abort();
|
||||
}
|
||||
fromNum++;
|
||||
}
|
||||
|
||||
|
@ -323,7 +326,10 @@ void MeshService::sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage
|
|||
releaseMqttClientProxyMessageToPool(d);
|
||||
}
|
||||
|
||||
assert(toPhoneMqttProxyQueue.enqueue(m, 0));
|
||||
if (toPhoneMqttProxyQueue.enqueue(m, 0) == false) {
|
||||
LOG_CRIT("Failed to queue a packet into toPhoneMqttProxyQueue!");
|
||||
abort();
|
||||
}
|
||||
fromNum++;
|
||||
}
|
||||
|
||||
|
@ -337,7 +343,10 @@ void MeshService::sendClientNotification(meshtastic_ClientNotification *n)
|
|||
releaseClientNotificationToPool(d);
|
||||
}
|
||||
|
||||
assert(toPhoneClientNotificationQueue.enqueue(n, 0));
|
||||
if (toPhoneClientNotificationQueue.enqueue(n, 0) == false) {
|
||||
LOG_CRIT("Failed to queue a notification into toPhoneClientNotificationQueue!");
|
||||
abort();
|
||||
}
|
||||
fromNum++;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@
|
|||
#include <utility/bonding.h>
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI
|
||||
#include <WiFiOTA.h>
|
||||
#endif
|
||||
|
||||
NodeDB *nodeDB = nullptr;
|
||||
|
||||
// we have plenty of ram so statically alloc this tempbuf (for now)
|
||||
|
@ -624,6 +628,27 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
|||
meshtastic_Config_PositionConfig_PositionFlags_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING |
|
||||
meshtastic_Config_PositionConfig_PositionFlags_DOP | meshtastic_Config_PositionConfig_PositionFlags_SATINVIEW);
|
||||
|
||||
// Set default value for 'Mesh via UDP'
|
||||
#if HAS_UDP_MULTICAST
|
||||
#ifdef USERPREFS_NETWORK_ENABLED_PROTOCOLS
|
||||
config.network.enabled_protocols = USERPREFS_NETWORK_ENABLED_PROTOCOLS;
|
||||
#else
|
||||
config.network.enabled_protocols = 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USERPREFS_NETWORK_WIFI_ENABLED
|
||||
config.network.wifi_enabled = USERPREFS_NETWORK_WIFI_ENABLED;
|
||||
#endif
|
||||
|
||||
#ifdef USERPREFS_NETWORK_WIFI_SSID
|
||||
strncpy(config.network.wifi_ssid, USERPREFS_NETWORK_WIFI_SSID, sizeof(config.network.wifi_ssid));
|
||||
#endif
|
||||
|
||||
#ifdef USERPREFS_NETWORK_WIFI_PSK
|
||||
strncpy(config.network.wifi_psk, USERPREFS_NETWORK_WIFI_PSK, sizeof(config.network.wifi_psk));
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_FLIP_SCREEN
|
||||
config.display.flip_screen = true;
|
||||
#endif
|
||||
|
@ -635,6 +660,12 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
|||
config.display.wake_on_tap_or_motion = true;
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI
|
||||
if (WiFiOTA::isUpdated()) {
|
||||
WiFiOTA::recoverConfig(&config.network);
|
||||
}
|
||||
#endif
|
||||
|
||||
initConfigIntervals();
|
||||
}
|
||||
|
||||
|
@ -1427,13 +1458,14 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
|
|||
#if !(MESHTASTIC_EXCLUDE_PKI)
|
||||
if (p.public_key.size > 0) {
|
||||
printBytes("Incoming Pubkey: ", p.public_key.bytes, 32);
|
||||
if (info->user.public_key.size > 0) { // if we have a key for this user already, don't overwrite with a new one
|
||||
LOG_INFO("Public Key set for node, not updating!");
|
||||
// we copy the key into the incoming packet, to prevent overwrite
|
||||
memcpy(p.public_key.bytes, info->user.public_key.bytes, 32);
|
||||
} else {
|
||||
LOG_INFO("Update Node Pubkey!");
|
||||
}
|
||||
}
|
||||
if (info->user.public_key.size > 0) { // if we have a key for this user already, don't overwrite with a new one
|
||||
LOG_INFO("Public Key set for node, not updating!");
|
||||
// we copy the key into the incoming packet, to prevent overwrite
|
||||
p.public_key.size = 32;
|
||||
memcpy(p.public_key.bytes, info->user.public_key.bytes, 32);
|
||||
} else if (p.public_key.size > 0) {
|
||||
LOG_INFO("Update Node Pubkey!");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@ bool STM32WLE5JCInterface::init()
|
|||
{
|
||||
RadioLibInterface::init();
|
||||
|
||||
// https://github.com/Seeed-Studio/LoRaWan-E5-Node/blob/main/Middlewares/Third_Party/SubGHz_Phy/stm32_radio_driver/radio_driver.c
|
||||
// https://github.com/Seeed-Studio/LoRaWan-E5-Node/blob/main/Middlewares/Third_Party/SubGHz_Phy/stm32_radio_driver/radio_driver.c
|
||||
#if (!defined(_VARIANT_RAK3172_))
|
||||
setTCXOVoltage(1.7);
|
||||
#endif
|
||||
|
||||
lora.setRfSwitchTable(rfswitch_pins, rfswitch_table);
|
||||
|
||||
|
@ -42,4 +44,4 @@ bool STM32WLE5JCInterface::init()
|
|||
return res == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
|
||||
#endif // ARCH_STM32WL
|
||||
#endif // ARCH_STM32WL
|
||||
|
|
|
@ -235,6 +235,8 @@ typedef enum _meshtastic_HardwareModel {
|
|||
meshtastic_HardwareModel_THINKNODE_M2 = 90,
|
||||
/* Lilygo T-ETH-Elite */
|
||||
meshtastic_HardwareModel_T_ETH_ELITE = 91,
|
||||
/* Heltec HRI-3621 industrial probe */
|
||||
meshtastic_HardwareModel_HELTEC_SENSOR_HUB = 92,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
|
|
|
@ -23,7 +23,12 @@ class UdpMulticastThread : public concurrency::OSThread
|
|||
void start()
|
||||
{
|
||||
if (udp.listenMulticast(udpIpAddress, UDP_MULTICAST_DEFAUL_PORT, 64)) {
|
||||
#ifndef ARCH_PORTDUINO
|
||||
// FIXME(PORTDUINO): arduino lacks IPAddress::toString()
|
||||
LOG_DEBUG("UDP Listening on IP: %s", WiFi.localIP().toString().c_str());
|
||||
#else
|
||||
LOG_DEBUG("UDP Listening");
|
||||
#endif
|
||||
udp.onPacket([this](AsyncUDPPacket packet) { onReceive(packet); });
|
||||
} else {
|
||||
LOG_DEBUG("Failed to listen on UDP");
|
||||
|
@ -33,7 +38,10 @@ class UdpMulticastThread : public concurrency::OSThread
|
|||
void onReceive(AsyncUDPPacket packet)
|
||||
{
|
||||
size_t packetLength = packet.length();
|
||||
#ifndef ARCH_PORTDUINO
|
||||
// FIXME(PORTDUINO): arduino lacks IPAddress::toString()
|
||||
LOG_DEBUG("UDP broadcast from: %s, len=%u", packet.remoteIP().toString().c_str(), packetLength);
|
||||
#endif
|
||||
meshtastic_MeshPacket mp;
|
||||
LOG_DEBUG("Decoding MeshPacket from UDP len=%u", packetLength);
|
||||
bool isPacketDecoded = pb_decode_from_bytes(packet.data(), packetLength, &meshtastic_MeshPacket_msg, &mp);
|
||||
|
@ -48,9 +56,14 @@ class UdpMulticastThread : public concurrency::OSThread
|
|||
|
||||
bool onSend(const meshtastic_MeshPacket *mp)
|
||||
{
|
||||
if (!mp || WiFi.status() != WL_CONNECTED) {
|
||||
if (!mp || !udp) {
|
||||
return false;
|
||||
}
|
||||
#ifndef ARCH_PORTDUINO
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
LOG_DEBUG("Broadcasting packet over UDP (id=%u)", mp->id);
|
||||
uint8_t buffer[meshtastic_MeshPacket_size];
|
||||
size_t encodedLength = pb_encode_to_bytes(buffer, sizeof(buffer), &meshtastic_MeshPacket_msg, mp);
|
||||
|
@ -70,4 +83,4 @@ class UdpMulticastThread : public concurrency::OSThread
|
|||
IPAddress udpIpAddress;
|
||||
AsyncUDP udp;
|
||||
};
|
||||
#endif // ARCH_ESP32
|
||||
#endif // HAS_UDP_MULTICAST
|
|
@ -133,7 +133,7 @@ static void onNetworkConnected()
|
|||
}
|
||||
|
||||
#if HAS_UDP_MULTICAST
|
||||
if (udpThread) {
|
||||
if (udpThread && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
|
||||
udpThread->start();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
#include "BleOta.h"
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI
|
||||
#include "WiFiOTA.h"
|
||||
#endif
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
|
@ -194,19 +197,23 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
|||
}
|
||||
case meshtastic_AdminMessage_reboot_ota_seconds_tag: {
|
||||
int32_t s = r->reboot_ota_seconds;
|
||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
if (BleOta::getOtaAppVersion().isEmpty()) {
|
||||
LOG_INFO("No OTA firmware available, scheduling regular reboot in %d seconds", s);
|
||||
screen->startAlert("Rebooting...");
|
||||
} else {
|
||||
#if defined(ARCH_ESP32)
|
||||
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
if (!BleOta::getOtaAppVersion().isEmpty()) {
|
||||
screen->startFirmwareUpdateScreen();
|
||||
BleOta::switchToOtaApp();
|
||||
LOG_INFO("Reboot to OTA in %d seconds", s);
|
||||
LOG_INFO("Rebooting to BLE OTA");
|
||||
}
|
||||
#else
|
||||
LOG_INFO("Not on ESP32, scheduling regular reboot in %d seconds", s);
|
||||
screen->startAlert("Rebooting...");
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_WIFI
|
||||
if (WiFiOTA::trySwitchToOTA()) {
|
||||
screen->startFirmwareUpdateScreen();
|
||||
WiFiOTA::saveConfig(&config.network);
|
||||
LOG_INFO("Rebooting to WiFi OTA");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
LOG_INFO("Reboot in %d seconds", s);
|
||||
rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
#include "input/SerialKeyboardImpl.h"
|
||||
#include "input/TrackballInterruptImpl1.h"
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#if !MESHTASTIC_EXCLUDE_I2C
|
||||
#include "input/cardKbI2cImpl.h"
|
||||
#endif
|
||||
#include "input/kbMatrixImpl.h"
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_ADMIN
|
||||
|
|
|
@ -31,7 +31,7 @@ uint32_t packetSequence = 0;
|
|||
|
||||
int32_t RangeTestModule::runOnce()
|
||||
{
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_PORTDUINO)
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the module
|
||||
|
@ -130,7 +130,7 @@ void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
|||
|
||||
ProcessMessage RangeTestModuleRadio::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_PORTDUINO)
|
||||
|
||||
if (moduleConfig.range_test.enabled) {
|
||||
|
||||
|
|
|
@ -468,81 +468,83 @@ void SerialModule::processWXSerial()
|
|||
// Extract the current line
|
||||
char line[meshtastic_Constants_DATA_PAYLOAD_LEN];
|
||||
memset(line, '\0', sizeof(line));
|
||||
memcpy(line, &serialBytes[lineStart], lineEnd - lineStart);
|
||||
if (strstr(line, "Wind") != NULL) // we have a wind line
|
||||
{
|
||||
gotwind = true;
|
||||
// Find the positions of "=" signs in the line
|
||||
char *windDirPos = strstr(line, "WindDir = ");
|
||||
char *windSpeedPos = strstr(line, "WindSpeed = ");
|
||||
char *windGustPos = strstr(line, "WindGust = ");
|
||||
if (lineEnd - lineStart < sizeof(line) - 1) {
|
||||
memcpy(line, &serialBytes[lineStart], lineEnd - lineStart);
|
||||
if (strstr(line, "Wind") != NULL) // we have a wind line
|
||||
{
|
||||
gotwind = true;
|
||||
// Find the positions of "=" signs in the line
|
||||
char *windDirPos = strstr(line, "WindDir = ");
|
||||
char *windSpeedPos = strstr(line, "WindSpeed = ");
|
||||
char *windGustPos = strstr(line, "WindGust = ");
|
||||
|
||||
if (windDirPos != NULL) {
|
||||
// Extract data after "=" for WindDir
|
||||
strcpy(windDir, windDirPos + 15); // Add 15 to skip "WindDir = "
|
||||
double radians = GeoCoord::toRadians(strtof(windDir, nullptr));
|
||||
dir_sum_sin += sin(radians);
|
||||
dir_sum_cos += cos(radians);
|
||||
dirCount++;
|
||||
} else if (windSpeedPos != NULL) {
|
||||
// Extract data after "=" for WindSpeed
|
||||
strcpy(windVel, windSpeedPos + 15); // Add 15 to skip "WindSpeed = "
|
||||
float newv = strtof(windVel, nullptr);
|
||||
velSum += newv;
|
||||
velCount++;
|
||||
if (newv < lull || lull == -1)
|
||||
lull = newv;
|
||||
if (windDirPos != NULL) {
|
||||
// Extract data after "=" for WindDir
|
||||
strlcpy(windDir, windDirPos + 15, sizeof(windDir)); // Add 15 to skip "WindDir = "
|
||||
double radians = GeoCoord::toRadians(strtof(windDir, nullptr));
|
||||
dir_sum_sin += sin(radians);
|
||||
dir_sum_cos += cos(radians);
|
||||
dirCount++;
|
||||
} else if (windSpeedPos != NULL) {
|
||||
// Extract data after "=" for WindSpeed
|
||||
strlcpy(windVel, windSpeedPos + 15, sizeof(windVel)); // Add 15 to skip "WindSpeed = "
|
||||
float newv = strtof(windVel, nullptr);
|
||||
velSum += newv;
|
||||
velCount++;
|
||||
if (newv < lull || lull == -1)
|
||||
lull = newv;
|
||||
|
||||
} else if (windGustPos != NULL) {
|
||||
strcpy(windGust, windGustPos + 15); // Add 15 to skip "WindSpeed = "
|
||||
float newg = strtof(windGust, nullptr);
|
||||
if (newg > gust)
|
||||
gust = newg;
|
||||
}
|
||||
} else if (windGustPos != NULL) {
|
||||
strlcpy(windGust, windGustPos + 15, sizeof(windGust)); // Add 15 to skip "WindSpeed = "
|
||||
float newg = strtof(windGust, nullptr);
|
||||
if (newg > gust)
|
||||
gust = newg;
|
||||
}
|
||||
|
||||
// these are also voltage data we care about possibly
|
||||
} else if (strstr(line, "BatVoltage") != NULL) { // we have a battVoltage line
|
||||
char *batVoltagePos = strstr(line, "BatVoltage = ");
|
||||
if (batVoltagePos != NULL) {
|
||||
strcpy(batVoltage, batVoltagePos + 17); // 18 for ws 80, 17 for ws85
|
||||
batVoltageF = strtof(batVoltage, nullptr);
|
||||
break; // last possible data we want so break
|
||||
}
|
||||
} else if (strstr(line, "CapVoltage") != NULL) { // we have a cappVoltage line
|
||||
char *capVoltagePos = strstr(line, "CapVoltage = ");
|
||||
if (capVoltagePos != NULL) {
|
||||
strcpy(capVoltage, capVoltagePos + 17); // 18 for ws 80, 17 for ws85
|
||||
capVoltageF = strtof(capVoltage, nullptr);
|
||||
}
|
||||
// GXTS04Temp = 24.4
|
||||
} else if (strstr(line, "GXTS04Temp") != NULL) { // we have a temperature line
|
||||
char *tempPos = strstr(line, "GXTS04Temp = ");
|
||||
if (tempPos != NULL) {
|
||||
strcpy(temperature, tempPos + 15); // 15 spaces for ws85
|
||||
temperatureF = strtof(temperature, nullptr);
|
||||
}
|
||||
// these are also voltage data we care about possibly
|
||||
} else if (strstr(line, "BatVoltage") != NULL) { // we have a battVoltage line
|
||||
char *batVoltagePos = strstr(line, "BatVoltage = ");
|
||||
if (batVoltagePos != NULL) {
|
||||
strlcpy(batVoltage, batVoltagePos + 17, sizeof(batVoltage)); // 18 for ws 80, 17 for ws85
|
||||
batVoltageF = strtof(batVoltage, nullptr);
|
||||
break; // last possible data we want so break
|
||||
}
|
||||
} else if (strstr(line, "CapVoltage") != NULL) { // we have a cappVoltage line
|
||||
char *capVoltagePos = strstr(line, "CapVoltage = ");
|
||||
if (capVoltagePos != NULL) {
|
||||
strlcpy(capVoltage, capVoltagePos + 17, sizeof(capVoltage)); // 18 for ws 80, 17 for ws85
|
||||
capVoltageF = strtof(capVoltage, nullptr);
|
||||
}
|
||||
// GXTS04Temp = 24.4
|
||||
} else if (strstr(line, "GXTS04Temp") != NULL) { // we have a temperature line
|
||||
char *tempPos = strstr(line, "GXTS04Temp = ");
|
||||
if (tempPos != NULL) {
|
||||
strlcpy(temperature, tempPos + 15, sizeof(temperature)); // 15 spaces for ws85
|
||||
temperatureF = strtof(temperature, nullptr);
|
||||
}
|
||||
|
||||
} else if (strstr(line, "RainIntSum") != NULL) { // we have a rainsum line
|
||||
// LOG_INFO(line);
|
||||
char *pos = strstr(line, "RainIntSum = ");
|
||||
if (pos != NULL) {
|
||||
strcpy(rainStr, pos + 17); // 17 spaces for ws85
|
||||
rainSum = int(strtof(rainStr, nullptr));
|
||||
}
|
||||
|
||||
} else if (strstr(line, "Rain") != NULL) { // we have a rain line
|
||||
if (strstr(line, "WaveRain") == NULL) { // skip WaveRain lines though.
|
||||
} else if (strstr(line, "RainIntSum") != NULL) { // we have a rainsum line
|
||||
// LOG_INFO(line);
|
||||
char *pos = strstr(line, "Rain = ");
|
||||
char *pos = strstr(line, "RainIntSum = ");
|
||||
if (pos != NULL) {
|
||||
strcpy(rainStr, pos + 17); // 17 spaces for ws85
|
||||
rain = strtof(rainStr, nullptr);
|
||||
strlcpy(rainStr, pos + 17, sizeof(rainStr)); // 17 spaces for ws85
|
||||
rainSum = int(strtof(rainStr, nullptr));
|
||||
}
|
||||
|
||||
} else if (strstr(line, "Rain") != NULL) { // we have a rain line
|
||||
if (strstr(line, "WaveRain") == NULL) { // skip WaveRain lines though.
|
||||
// LOG_INFO(line);
|
||||
char *pos = strstr(line, "Rain = ");
|
||||
if (pos != NULL) {
|
||||
strlcpy(rainStr, pos + 17, sizeof(rainStr)); // 17 spaces for ws85
|
||||
rain = strtof(rainStr, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update lineStart for the next line
|
||||
lineStart = lineEnd + 1;
|
||||
// Update lineStart for the next line
|
||||
lineStart = lineEnd + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -98,7 +98,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
|||
// moduleConfig.telemetry.environment_screen_enabled = 1;
|
||||
// moduleConfig.telemetry.environment_update_interval = 15;
|
||||
|
||||
if (!(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled)) {
|
||||
if (!(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled ||
|
||||
ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE)) {
|
||||
// If this module is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it
|
||||
return disable();
|
||||
}
|
||||
|
@ -107,7 +108,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
|||
// This is the first time the OSThread library has called this function, so do some setup
|
||||
firstTime = 0;
|
||||
|
||||
if (moduleConfig.telemetry.environment_measurement_enabled) {
|
||||
if (moduleConfig.telemetry.environment_measurement_enabled || ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE) {
|
||||
LOG_INFO("Environment Telemetry: init");
|
||||
#ifdef SENSECAP_INDICATOR
|
||||
result = indicatorSensor.runOnce();
|
||||
|
@ -178,7 +179,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
|||
return result == UINT32_MAX ? disable() : setStartDelay();
|
||||
} else {
|
||||
// if we somehow got to a second run of this module with measurement disabled, then just wait forever
|
||||
if (!moduleConfig.telemetry.environment_measurement_enabled) {
|
||||
if (!moduleConfig.telemetry.environment_measurement_enabled && !ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE) {
|
||||
return disable();
|
||||
} else {
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE
|
||||
#define ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE 0
|
||||
#endif
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "NodeDB.h"
|
||||
#include "ProtobufModule.h"
|
||||
|
|
|
@ -160,13 +160,11 @@ class AccelerometerThread : public concurrency::OSThread
|
|||
void clean()
|
||||
{
|
||||
isInitialised = false;
|
||||
if (sensor != nullptr) {
|
||||
delete sensor;
|
||||
sensor = nullptr;
|
||||
}
|
||||
delete sensor;
|
||||
sensor = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
#include "WiFiOTA.h"
|
||||
#include "configuration.h"
|
||||
#include <Preferences.h>
|
||||
#include <esp_ota_ops.h>
|
||||
|
||||
namespace WiFiOTA
|
||||
{
|
||||
|
||||
static const char *nvsNamespace = "ota-wifi";
|
||||
static const char *appProjectName = "OTA-WiFi";
|
||||
|
||||
static bool updated = false;
|
||||
|
||||
bool isUpdated()
|
||||
{
|
||||
return updated;
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
Preferences prefs;
|
||||
prefs.begin(nvsNamespace);
|
||||
if (prefs.getBool("updated")) {
|
||||
LOG_INFO("First boot after OTA update");
|
||||
updated = true;
|
||||
prefs.putBool("updated", false);
|
||||
}
|
||||
prefs.end();
|
||||
}
|
||||
|
||||
void recoverConfig(meshtastic_Config_NetworkConfig *network)
|
||||
{
|
||||
LOG_INFO("Recovering WiFi settings after OTA update");
|
||||
|
||||
Preferences prefs;
|
||||
prefs.begin(nvsNamespace, true);
|
||||
String ssid = prefs.getString("ssid");
|
||||
String psk = prefs.getString("psk");
|
||||
prefs.end();
|
||||
|
||||
network->wifi_enabled = true;
|
||||
strncpy(network->wifi_ssid, ssid.c_str(), sizeof(network->wifi_ssid));
|
||||
strncpy(network->wifi_psk, psk.c_str(), sizeof(network->wifi_psk));
|
||||
}
|
||||
|
||||
void saveConfig(meshtastic_Config_NetworkConfig *network)
|
||||
{
|
||||
LOG_INFO("Saving WiFi settings for upcoming OTA update");
|
||||
|
||||
Preferences prefs;
|
||||
prefs.begin(nvsNamespace);
|
||||
prefs.putString("ssid", network->wifi_ssid);
|
||||
prefs.putString("psk", network->wifi_psk);
|
||||
prefs.putBool("updated", false);
|
||||
prefs.end();
|
||||
}
|
||||
|
||||
const esp_partition_t *getAppPartition()
|
||||
{
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL);
|
||||
}
|
||||
|
||||
bool getAppDesc(const esp_partition_t *part, esp_app_desc_t *app_desc)
|
||||
{
|
||||
if (esp_ota_get_partition_description(part, app_desc) != ESP_OK)
|
||||
return false;
|
||||
if (strcmp(app_desc->project_name, appProjectName) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool trySwitchToOTA()
|
||||
{
|
||||
const esp_partition_t *part = getAppPartition();
|
||||
esp_app_desc_t app_desc;
|
||||
if (!getAppDesc(part, &app_desc))
|
||||
return false;
|
||||
if (esp_ota_set_boot_partition(part) != ESP_OK)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
String getVersion()
|
||||
{
|
||||
const esp_partition_t *part = getAppPartition();
|
||||
esp_app_desc_t app_desc;
|
||||
if (!getAppDesc(part, &app_desc))
|
||||
return String();
|
||||
return String(app_desc.version);
|
||||
}
|
||||
|
||||
} // namespace WiFiOTA
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef WIFIOTA_H
|
||||
#define WIFIOTA_H
|
||||
|
||||
#include "mesh-pb-constants.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
namespace WiFiOTA
|
||||
{
|
||||
void initialize();
|
||||
bool isUpdated();
|
||||
|
||||
void recoverConfig(meshtastic_Config_NetworkConfig *network);
|
||||
void saveConfig(meshtastic_Config_NetworkConfig *network);
|
||||
bool trySwitchToOTA();
|
||||
String getVersion();
|
||||
} // namespace WiFiOTA
|
||||
|
||||
#endif // WIFIOTA_H
|
|
@ -180,6 +180,8 @@
|
|||
#define HW_VENDOR meshtastic_HardwareModel_MESH_TAB
|
||||
#elif defined(T_ETH_ELITE)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_ETH_ELITE
|
||||
#elif defined(HELTEC_SENSOR_HUB)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_SENSOR_HUB
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "nimble/NimbleBluetooth.h"
|
||||
#endif
|
||||
|
||||
#include <WiFiOTA.h>
|
||||
|
||||
#if HAS_WIFI
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#endif
|
||||
|
@ -144,12 +146,19 @@ void esp32Setup()
|
|||
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
String BLEOTA = BleOta::getOtaAppVersion();
|
||||
if (BLEOTA.isEmpty()) {
|
||||
LOG_INFO("No OTA firmware available");
|
||||
LOG_INFO("No BLE OTA firmware available");
|
||||
} else {
|
||||
LOG_INFO("OTA firmware version %s", BLEOTA.c_str());
|
||||
LOG_INFO("BLE OTA firmware version %s", BLEOTA.c_str());
|
||||
}
|
||||
#else
|
||||
LOG_INFO("No OTA firmware available");
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_WIFI
|
||||
String version = WiFiOTA::getVersion();
|
||||
if (version.isEmpty()) {
|
||||
LOG_INFO("No WiFi OTA firmware available");
|
||||
} else {
|
||||
LOG_INFO("WiFi OTA firmware version %s", version.c_str());
|
||||
}
|
||||
WiFiOTA::initialize();
|
||||
#endif
|
||||
|
||||
// enableModemSleep();
|
||||
|
|
|
@ -75,6 +75,8 @@
|
|||
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
|
||||
#elif defined(HELTEC_T114)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_NODE_T114
|
||||
#elif defined(MESHLINK)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_MESHLINK
|
||||
#elif defined(SEEED_XIAO_NRF52840_KIT)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_XIAO_NRF52_KIT
|
||||
#else
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* 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 "LittleFS.h"
|
||||
#include "stm32wlxx_hal_flash.h"
|
||||
|
||||
/**********************************************************************************************************************
|
||||
* Macro definitions
|
||||
**********************************************************************************************************************/
|
||||
/** This macro is used to suppress compiler messages about a parameter not being used in a function. */
|
||||
#define LFS_UNUSED(p) (void)((p))
|
||||
|
||||
#define STM32WL_PAGE_SIZE (FLASH_PAGE_SIZE)
|
||||
#define STM32WL_PAGE_COUNT (FLASH_PAGE_NB)
|
||||
#define STM32WL_FLASH_BASE (FLASH_BASE)
|
||||
|
||||
/*
|
||||
* FLASH_SIZE from stm32wle5xx.h will read the actual FLASH size from the chip.
|
||||
* FLASH_END_ADDR is calculated from FLASH_SIZE.
|
||||
* Use the last 28 KiB of the FLASH
|
||||
*/
|
||||
#define LFS_FLASH_TOTAL_SIZE (14 * 2048) /* needs to be a multiple of LFS_BLOCK_SIZE */
|
||||
#define LFS_BLOCK_SIZE (2048)
|
||||
#define LFS_FLASH_ADDR_END (FLASH_END_ADDR)
|
||||
#define LFS_FLASH_ADDR_BASE (LFS_FLASH_ADDR_END - LFS_FLASH_TOTAL_SIZE + 1)
|
||||
|
||||
#if !CFG_DEBUG
|
||||
#define _LFS_DBG(fmt, ...)
|
||||
#else
|
||||
#define _LFS_DBG(fmt, ...) printf("%s:%d (%s): " fmt "\n", __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// LFS Disk IO
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static int _internal_flash_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
|
||||
{
|
||||
LFS_UNUSED(c);
|
||||
|
||||
if (!buffer || !size) {
|
||||
_LFS_DBG("%s Invalid parameter!\r\n", __func__);
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
|
||||
lfs_block_t address = LFS_FLASH_ADDR_BASE + (block * STM32WL_PAGE_SIZE + off);
|
||||
|
||||
memcpy(buffer, (void *)address, size);
|
||||
|
||||
return LFS_ERR_OK;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
lfs_block_t address = LFS_FLASH_ADDR_BASE + (block * STM32WL_PAGE_SIZE + off);
|
||||
HAL_StatusTypeDef hal_rc = HAL_OK;
|
||||
uint32_t dw_count = size / 8;
|
||||
uint64_t *bufp = (uint64_t *)buffer;
|
||||
|
||||
LFS_UNUSED(c);
|
||||
|
||||
_LFS_DBG("Programming %d bytes/%d doublewords at address 0x%08x/block %d, offset %d.", size, dw_count, address, block, off);
|
||||
if (HAL_FLASH_Unlock() != HAL_OK) {
|
||||
return LFS_ERR_IO;
|
||||
}
|
||||
for (uint32_t i = 0; i < dw_count; i++) {
|
||||
if ((address < LFS_FLASH_ADDR_BASE) || (address > LFS_FLASH_ADDR_END)) {
|
||||
_LFS_DBG("Wanted to program out of bound of FLASH: 0x%08x.\n", address);
|
||||
HAL_FLASH_Lock();
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
hal_rc = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, *bufp);
|
||||
if (hal_rc != HAL_OK) {
|
||||
/* Error occurred while writing data in Flash memory.
|
||||
* User can add here some code to deal with this error.
|
||||
*/
|
||||
_LFS_DBG("Program error at (0x%08x), 0x%X, error: 0x%08x\n", address, hal_rc, HAL_FLASH_GetError());
|
||||
}
|
||||
address += 8;
|
||||
bufp += 1;
|
||||
}
|
||||
if (HAL_FLASH_Lock() != HAL_OK) {
|
||||
return LFS_ERR_IO;
|
||||
}
|
||||
|
||||
return hal_rc == HAL_OK ? LFS_ERR_OK : LFS_ERR_IO; // If HAL_OK, return LFS_ERR_OK, else return LFS_ERR_IO
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
lfs_block_t address = LFS_FLASH_ADDR_BASE + (block * STM32WL_PAGE_SIZE);
|
||||
HAL_StatusTypeDef hal_rc;
|
||||
FLASH_EraseInitTypeDef EraseInitStruct = {.TypeErase = FLASH_TYPEERASE_PAGES, .Page = 0, .NbPages = 1};
|
||||
uint32_t PAGEError = 0;
|
||||
|
||||
LFS_UNUSED(c);
|
||||
|
||||
if ((address < LFS_FLASH_ADDR_BASE) || (address > LFS_FLASH_ADDR_END)) {
|
||||
_LFS_DBG("Wanted to erase out of bound of FLASH: 0x%08x.\n", address);
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
/* calculate the absolute page, i.e. what the ST wants */
|
||||
EraseInitStruct.Page = (address - STM32WL_FLASH_BASE) / STM32WL_PAGE_SIZE;
|
||||
_LFS_DBG("Erasing block %d at 0x%08x... ", block, address);
|
||||
HAL_FLASH_Unlock();
|
||||
hal_rc = HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
|
||||
HAL_FLASH_Lock();
|
||||
|
||||
return hal_rc == HAL_OK ? LFS_ERR_OK : LFS_ERR_IO; // If HAL_OK, return LFS_ERR_OK, else return LFS_ERR_IO
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
LFS_UNUSED(c);
|
||||
// write function performs no caching. No need for sync.
|
||||
|
||||
return LFS_ERR_OK;
|
||||
}
|
||||
|
||||
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_BLOCK_SIZE,
|
||||
.prog_size = LFS_BLOCK_SIZE,
|
||||
.block_size = LFS_BLOCK_SIZE,
|
||||
.block_count = LFS_FLASH_TOTAL_SIZE / LFS_BLOCK_SIZE,
|
||||
.lookahead = 128,
|
||||
|
||||
.read_buffer = NULL,
|
||||
.prog_buffer = NULL,
|
||||
.lookahead_buffer = NULL,
|
||||
.file_buffer = NULL};
|
||||
|
||||
LittleFS InternalFS;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
LittleFS::LittleFS(void) : STM32_LittleFS(&_InternalFSConfig) {}
|
||||
|
||||
bool LittleFS::begin(void)
|
||||
{
|
||||
if (FLASH_BASE >= LFS_FLASH_ADDR_BASE) {
|
||||
/* There is not enough space on this device for a filesystem. */
|
||||
return false;
|
||||
}
|
||||
// failed to mount, erase all pages then format and mount again
|
||||
if (!STM32_LittleFS::begin()) {
|
||||
// Erase all pages of internal flash region for Filesystem.
|
||||
for (uint32_t addr = LFS_FLASH_ADDR_BASE; addr < (LFS_FLASH_ADDR_END + 1); addr += STM32WL_PAGE_SIZE) {
|
||||
_internal_flash_erase(&_InternalFSConfig, (addr - LFS_FLASH_ADDR_BASE) / STM32WL_PAGE_SIZE);
|
||||
}
|
||||
|
||||
// lfs format
|
||||
this->format();
|
||||
|
||||
// mount again if still failed, give up
|
||||
if (!STM32_LittleFS::begin())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 "STM32_LittleFS.h"
|
||||
|
||||
class LittleFS : public STM32_LittleFS
|
||||
{
|
||||
public:
|
||||
LittleFS(void);
|
||||
|
||||
// overwrite to also perform low level format (sector erase of whole flash region)
|
||||
bool begin(void);
|
||||
};
|
||||
|
||||
extern LittleFS InternalFS;
|
||||
|
||||
#endif /* INTERNALFILESYSTEM_H_ */
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach 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 "STM32_LittleFS.h"
|
||||
#include <Arduino.h>
|
||||
#include <string.h>
|
||||
|
||||
#define memclr(buffer, size) memset(buffer, 0, size)
|
||||
#define varclr(_var) memclr(_var, sizeof(*(_var)))
|
||||
|
||||
using namespace STM32_LittleFS_Namespace;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Implementation
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
STM32_LittleFS::STM32_LittleFS(void) : STM32_LittleFS(NULL) {}
|
||||
|
||||
STM32_LittleFS::STM32_LittleFS(struct lfs_config *cfg)
|
||||
{
|
||||
varclr(&_lfs);
|
||||
_lfs_cfg = cfg;
|
||||
_mounted = false;
|
||||
}
|
||||
|
||||
STM32_LittleFS::~STM32_LittleFS() {}
|
||||
|
||||
// Initialize and mount the file system
|
||||
// Return true if mounted successfully else probably corrupted.
|
||||
// User should format the disk and try again
|
||||
bool STM32_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 STM32_LittleFS::end(void)
|
||||
{
|
||||
_lockFS();
|
||||
|
||||
if (_mounted) {
|
||||
_mounted = false;
|
||||
int err = lfs_unmount(&_lfs);
|
||||
PRINT_LFS_ERR(err);
|
||||
(void)err;
|
||||
}
|
||||
|
||||
_unlockFS();
|
||||
}
|
||||
|
||||
bool STM32_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
|
||||
STM32_LittleFS_Namespace::File STM32_LittleFS::open(char const *filepath, uint8_t mode)
|
||||
{
|
||||
// No lock is required here ... the File() object will synchronize with the mutex provided
|
||||
return STM32_LittleFS_Namespace::File(filepath, mode, *this);
|
||||
}
|
||||
|
||||
// Check if file or folder exists
|
||||
bool STM32_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 STM32_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 STM32_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 STM32_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 STM32_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 STM32_LittleFS::rmdir_r(char const *filepath)
|
||||
{
|
||||
/* 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
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach 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 STM32_LITTLEFS_H_
|
||||
#define STM32_LITTLEFS_H_
|
||||
|
||||
#include <Stream.h>
|
||||
|
||||
// Internal Flash uses ARM Little FileSystem
|
||||
// https://github.com/ARMmbed/littlefs
|
||||
#include "../../freertosinc.h" // tied to FreeRTOS for serialization
|
||||
#include "STM32_LittleFS_File.h"
|
||||
#include "littlefs/lfs.h"
|
||||
|
||||
class STM32_LittleFS
|
||||
{
|
||||
public:
|
||||
STM32_LittleFS(void);
|
||||
STM32_LittleFS(struct lfs_config *cfg);
|
||||
virtual ~STM32_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.
|
||||
STM32_LittleFS_Namespace::File open(char const *filename, uint8_t mode = STM32_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)
|
||||
{ /* no-op */
|
||||
}
|
||||
void _unlockFS(void)
|
||||
{ /* no-op */
|
||||
}
|
||||
|
||||
protected:
|
||||
bool _mounted;
|
||||
struct lfs_config *_lfs_cfg;
|
||||
lfs_t _lfs;
|
||||
};
|
||||
|
||||
#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) { \
|
||||
printf("%s:%d, LFS error: %d\n", __FILE__, __LINE__, _err); \
|
||||
} \
|
||||
} while (0) // LFS_ERR are of type int, VERIFY_MESS expects long_int
|
||||
|
||||
const char *dbg_strerr_lfs(int32_t err);
|
||||
#endif
|
||||
|
||||
#endif /* STM32_LITTLEFS_H_ */
|
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach 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 "STM32_LittleFS.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#define rtos_malloc malloc
|
||||
#define rtos_free free
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
using namespace STM32_LittleFS_Namespace;
|
||||
|
||||
File::File(STM32_LittleFS &fs)
|
||||
{
|
||||
_fs = &fs;
|
||||
_is_dir = false;
|
||||
_name[0] = 0;
|
||||
_name[LFS_NAME_MAX] = 0;
|
||||
_dir_path = NULL;
|
||||
|
||||
_dir = NULL;
|
||||
_file = NULL;
|
||||
}
|
||||
|
||||
File::File(char const *filename, uint8_t mode, STM32_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 *)rtos_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);
|
||||
// free memory
|
||||
rtos_free(_file);
|
||||
_file = NULL;
|
||||
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 *)rtos_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);
|
||||
// free memory
|
||||
rtos_free(_dir);
|
||||
_dir = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
_is_dir = true;
|
||||
|
||||
_dir_path = (char *)rtos_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<int>(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<int>(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;
|
||||
uint32_t pos;
|
||||
_fs->_lockFS();
|
||||
if (!this->_is_dir) {
|
||||
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);
|
||||
rtos_free(_dir);
|
||||
_dir = NULL;
|
||||
|
||||
if (this->_dir_path)
|
||||
rtos_free(_dir_path);
|
||||
_dir_path = NULL;
|
||||
} else {
|
||||
lfs_file_close(this->_fs->_getFS(), _file);
|
||||
rtos_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();
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach 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 STM32_LITTLEFS_FILE_H_
|
||||
#define STM32_LITTLEFS_FILE_H_
|
||||
|
||||
#include "littlefs/lfs.h"
|
||||
|
||||
// Forward declaration
|
||||
class STM32_LittleFS;
|
||||
|
||||
namespace STM32_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:
|
||||
File(STM32_LittleFS &fs);
|
||||
File(char const *filename, uint8_t mode, STM32_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:
|
||||
STM32_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 STM32_LittleFS_Namespace
|
||||
|
||||
#endif /* STM32_LITTLEFS_FILE_H_ */
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
* The little filesystem
|
||||
*
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef LFS_H
|
||||
#define LFS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Version info ///
|
||||
|
||||
// Software library version
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// Minor (bottom-nibble), incremented on feature additions
|
||||
#define LFS_VERSION 0x00010006
|
||||
#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
|
||||
#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0))
|
||||
|
||||
// Version of On-disk data structures
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// Minor (bottom-nibble), incremented on feature additions
|
||||
#define LFS_DISK_VERSION 0x00010001
|
||||
#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16))
|
||||
#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0))
|
||||
|
||||
/// Definitions ///
|
||||
|
||||
// Type definitions
|
||||
typedef uint32_t lfs_size_t;
|
||||
typedef uint32_t lfs_off_t;
|
||||
|
||||
typedef int32_t lfs_ssize_t;
|
||||
typedef int32_t lfs_soff_t;
|
||||
|
||||
typedef uint32_t lfs_block_t;
|
||||
|
||||
// Max name size in bytes
|
||||
#ifndef LFS_NAME_MAX
|
||||
#define LFS_NAME_MAX 255
|
||||
#endif
|
||||
|
||||
// Possible error codes, these are negative to allow
|
||||
// valid positive return values
|
||||
enum lfs_error {
|
||||
LFS_ERR_OK = 0, // No error
|
||||
LFS_ERR_IO = -5, // Error during device operation
|
||||
LFS_ERR_CORRUPT = -52, // Corrupted
|
||||
LFS_ERR_NOENT = -2, // No directory entry
|
||||
LFS_ERR_EXIST = -17, // Entry already exists
|
||||
LFS_ERR_NOTDIR = -20, // Entry is not a dir
|
||||
LFS_ERR_ISDIR = -21, // Entry is a dir
|
||||
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
|
||||
LFS_ERR_BADF = -9, // Bad file number
|
||||
LFS_ERR_INVAL = -22, // Invalid parameter
|
||||
LFS_ERR_NOSPC = -28, // No space left on device
|
||||
LFS_ERR_NOMEM = -12, // No more memory available
|
||||
};
|
||||
|
||||
// File types
|
||||
enum lfs_type {
|
||||
LFS_TYPE_REG = 0x11,
|
||||
LFS_TYPE_DIR = 0x22,
|
||||
LFS_TYPE_SUPERBLOCK = 0x2e,
|
||||
};
|
||||
|
||||
// File open flags
|
||||
enum lfs_open_flags {
|
||||
// open flags
|
||||
LFS_O_RDONLY = 1, // Open a file as read only
|
||||
LFS_O_WRONLY = 2, // Open a file as write only
|
||||
LFS_O_RDWR = 3, // Open a file as read and write
|
||||
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
|
||||
LFS_O_EXCL = 0x0200, // Fail if a file already exists
|
||||
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
||||
LFS_O_APPEND = 0x0800, // Move to end of file on every write
|
||||
|
||||
// internally used flags
|
||||
LFS_F_DIRTY = 0x10000, // File does not match storage
|
||||
LFS_F_WRITING = 0x20000, // File has been written since last flush
|
||||
LFS_F_READING = 0x40000, // File has been read since last flush
|
||||
LFS_F_ERRED = 0x80000, // An error occured during write
|
||||
};
|
||||
|
||||
// File seek flags
|
||||
enum lfs_whence_flags {
|
||||
LFS_SEEK_SET = 0, // Seek relative to an absolute position
|
||||
LFS_SEEK_CUR = 1, // Seek relative to the current file position
|
||||
LFS_SEEK_END = 2, // Seek relative to the end of the file
|
||||
};
|
||||
|
||||
// Configuration provided during initialization of the littlefs
|
||||
struct lfs_config {
|
||||
// Opaque user provided context that can be used to pass
|
||||
// information to the block device operations
|
||||
void *context;
|
||||
|
||||
// Read a region in a block. Negative error codes are propogated
|
||||
// to the user.
|
||||
int (*read)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size);
|
||||
|
||||
// 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.
|
||||
int (*prog)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size);
|
||||
|
||||
// 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.
|
||||
int (*erase)(const struct lfs_config *c, lfs_block_t block);
|
||||
|
||||
// Sync the state of the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
int (*sync)(const struct lfs_config *c);
|
||||
|
||||
// Minimum size of a block read. This determines the size of read buffers.
|
||||
// This may be larger than the physical read size to improve performance
|
||||
// by caching more of the block device.
|
||||
lfs_size_t read_size;
|
||||
|
||||
// Minimum size of a block program. This determines the size of program
|
||||
// buffers. This may be larger than the physical program size to improve
|
||||
// performance by caching more of the block device.
|
||||
// Must be a multiple of the read size.
|
||||
lfs_size_t prog_size;
|
||||
|
||||
// Size of an erasable block. This does not impact ram consumption and
|
||||
// may be larger than the physical erase size. However, this should be
|
||||
// kept small as each file currently takes up an entire block.
|
||||
// Must be a multiple of the program size.
|
||||
lfs_size_t block_size;
|
||||
|
||||
// Number of erasable blocks on the device.
|
||||
lfs_size_t block_count;
|
||||
|
||||
// Number of blocks to lookahead during block allocation. A larger
|
||||
// lookahead reduces the number of passes required to allocate a block.
|
||||
// The lookahead buffer requires only 1 bit per block so it can be quite
|
||||
// large with little ram impact. Should be a multiple of 32.
|
||||
lfs_size_t lookahead;
|
||||
|
||||
// Optional, statically allocated read buffer. Must be read sized.
|
||||
void *read_buffer;
|
||||
|
||||
// Optional, statically allocated program buffer. Must be program sized.
|
||||
void *prog_buffer;
|
||||
|
||||
// Optional, statically allocated lookahead buffer. Must be 1 bit per
|
||||
// lookahead block.
|
||||
void *lookahead_buffer;
|
||||
|
||||
// Optional, statically allocated buffer for files. Must be program sized.
|
||||
// If enabled, only one file may be opened at a time.
|
||||
void *file_buffer;
|
||||
};
|
||||
|
||||
// Optional configuration provided during lfs_file_opencfg
|
||||
struct lfs_file_config {
|
||||
// Optional, statically allocated buffer for files. Must be program sized.
|
||||
// If NULL, malloc will be used by default.
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
// File info structure
|
||||
struct lfs_info {
|
||||
// Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
|
||||
uint8_t type;
|
||||
|
||||
// Size of the file, only valid for REG files
|
||||
lfs_size_t size;
|
||||
|
||||
// Name of the file stored as a null-terminated string
|
||||
char name[LFS_NAME_MAX + 1];
|
||||
};
|
||||
|
||||
/// littlefs data structures ///
|
||||
typedef struct lfs_entry {
|
||||
lfs_off_t off;
|
||||
|
||||
struct lfs_disk_entry {
|
||||
uint8_t type;
|
||||
uint8_t elen;
|
||||
uint8_t alen;
|
||||
uint8_t nlen;
|
||||
union {
|
||||
struct {
|
||||
lfs_block_t head;
|
||||
lfs_size_t size;
|
||||
} file;
|
||||
lfs_block_t dir[2];
|
||||
} u;
|
||||
} d;
|
||||
} lfs_entry_t;
|
||||
|
||||
typedef struct lfs_cache {
|
||||
lfs_block_t block;
|
||||
lfs_off_t off;
|
||||
uint8_t *buffer;
|
||||
} lfs_cache_t;
|
||||
|
||||
typedef struct lfs_file {
|
||||
struct lfs_file *next;
|
||||
lfs_block_t pair[2];
|
||||
lfs_off_t poff;
|
||||
|
||||
lfs_block_t head;
|
||||
lfs_size_t size;
|
||||
|
||||
const struct lfs_file_config *cfg;
|
||||
uint32_t flags;
|
||||
lfs_off_t pos;
|
||||
lfs_block_t block;
|
||||
lfs_off_t off;
|
||||
lfs_cache_t cache;
|
||||
} lfs_file_t;
|
||||
|
||||
typedef struct lfs_dir {
|
||||
struct lfs_dir *next;
|
||||
lfs_block_t pair[2];
|
||||
lfs_off_t off;
|
||||
|
||||
lfs_block_t head[2];
|
||||
lfs_off_t pos;
|
||||
|
||||
struct lfs_disk_dir {
|
||||
uint32_t rev;
|
||||
lfs_size_t size;
|
||||
lfs_block_t tail[2];
|
||||
} d;
|
||||
} lfs_dir_t;
|
||||
|
||||
typedef struct lfs_superblock {
|
||||
lfs_off_t off;
|
||||
|
||||
struct lfs_disk_superblock {
|
||||
uint8_t type;
|
||||
uint8_t elen;
|
||||
uint8_t alen;
|
||||
uint8_t nlen;
|
||||
lfs_block_t root[2];
|
||||
uint32_t block_size;
|
||||
uint32_t block_count;
|
||||
uint32_t version;
|
||||
char magic[8];
|
||||
} d;
|
||||
} lfs_superblock_t;
|
||||
|
||||
typedef struct lfs_free {
|
||||
lfs_block_t off;
|
||||
lfs_block_t size;
|
||||
lfs_block_t i;
|
||||
lfs_block_t ack;
|
||||
uint32_t *buffer;
|
||||
} lfs_free_t;
|
||||
|
||||
// The littlefs type
|
||||
typedef struct lfs {
|
||||
const struct lfs_config *cfg;
|
||||
|
||||
lfs_block_t root[2];
|
||||
lfs_file_t *files;
|
||||
lfs_dir_t *dirs;
|
||||
|
||||
lfs_cache_t rcache;
|
||||
lfs_cache_t pcache;
|
||||
|
||||
lfs_free_t free;
|
||||
bool deorphaned;
|
||||
} lfs_t;
|
||||
|
||||
/// Filesystem functions ///
|
||||
|
||||
// Format a block device with the littlefs
|
||||
//
|
||||
// Requires a littlefs object and config struct. This clobbers the littlefs
|
||||
// object, and does not leave the filesystem mounted. The config struct must
|
||||
// be zeroed for defaults and backwards compatibility.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_format(lfs_t *lfs, const struct lfs_config *config);
|
||||
|
||||
// Mounts a littlefs
|
||||
//
|
||||
// Requires a littlefs object and config struct. Multiple filesystems
|
||||
// may be mounted simultaneously with multiple littlefs objects. Both
|
||||
// lfs and config must be allocated while mounted. The config struct must
|
||||
// be zeroed for defaults and backwards compatibility.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_mount(lfs_t *lfs, const struct lfs_config *config);
|
||||
|
||||
// Unmounts a littlefs
|
||||
//
|
||||
// Does nothing besides releasing any allocated resources.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_unmount(lfs_t *lfs);
|
||||
|
||||
/// General operations ///
|
||||
|
||||
// Removes a file or directory
|
||||
//
|
||||
// If removing a directory, the directory must be empty.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_remove(lfs_t *lfs, const char *path);
|
||||
|
||||
// Rename or move a file or directory
|
||||
//
|
||||
// If the destination exists, it must match the source in type.
|
||||
// If the destination is a directory, the directory must be empty.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath);
|
||||
|
||||
// Find info about a file or directory
|
||||
//
|
||||
// Fills out the info structure, based on the specified file or directory.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
|
||||
|
||||
/// File operations ///
|
||||
|
||||
// Open a file
|
||||
//
|
||||
// The mode that the file is opened in is determined by the flags, which
|
||||
// are values from the enum lfs_open_flags that are bitwise-ored together.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags);
|
||||
|
||||
// Open a file with extra configuration
|
||||
//
|
||||
// The mode that the file is opened in is determined by the flags, which
|
||||
// are values from the enum lfs_open_flags that are bitwise-ored together.
|
||||
//
|
||||
// The config struct provides additional config options per file as described
|
||||
// above. The config struct must be allocated while the file is open, and the
|
||||
// config struct must be zeroed for defaults and backwards compatibility.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, const char *path, int flags, const struct lfs_file_config *config);
|
||||
|
||||
// Close a file
|
||||
//
|
||||
// Any pending writes are written out to storage as though
|
||||
// sync had been called and releases any allocated resources.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_close(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
// Synchronize a file on storage
|
||||
//
|
||||
// Any pending writes are written out to storage.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
// Read data from file
|
||||
//
|
||||
// Takes a buffer and size indicating where to store the read data.
|
||||
// Returns the number of bytes read, or a negative error code on failure.
|
||||
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, void *buffer, lfs_size_t size);
|
||||
|
||||
// Write data to file
|
||||
//
|
||||
// Takes a buffer and size indicating the data to write. The file will not
|
||||
// actually be updated on the storage until either sync or close is called.
|
||||
//
|
||||
// Returns the number of bytes written, or a negative error code on failure.
|
||||
lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size);
|
||||
|
||||
// Change the position of the file
|
||||
//
|
||||
// The change in position is determined by the offset and whence flag.
|
||||
// Returns the old position of the file, or a negative error code on failure.
|
||||
lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, lfs_soff_t off, int whence);
|
||||
|
||||
// Truncates the size of the file to the specified size
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size);
|
||||
|
||||
// Return the position of the file
|
||||
//
|
||||
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
|
||||
// Returns the position of the file, or a negative error code on failure.
|
||||
lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
// Change the position of the file to the beginning of the file
|
||||
//
|
||||
// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR)
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
// Return the size of the file
|
||||
//
|
||||
// Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END)
|
||||
// Returns the size of the file, or a negative error code on failure.
|
||||
lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file);
|
||||
|
||||
/// Directory operations ///
|
||||
|
||||
// Create a directory
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_mkdir(lfs_t *lfs, const char *path);
|
||||
|
||||
// Open a directory
|
||||
//
|
||||
// Once open a directory can be used with read to iterate over files.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path);
|
||||
|
||||
// Close a directory
|
||||
//
|
||||
// Releases any allocated resources.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir);
|
||||
|
||||
// Read an entry in the directory
|
||||
//
|
||||
// Fills out the info structure, based on the specified file or directory.
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
|
||||
|
||||
// Change the position of the directory
|
||||
//
|
||||
// The new off must be a value previous returned from tell and specifies
|
||||
// an absolute offset in the directory seek.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off);
|
||||
|
||||
// Return the position of the directory
|
||||
//
|
||||
// The returned offset is only meant to be consumed by seek and may not make
|
||||
// sense, but does indicate the current position in the directory iteration.
|
||||
//
|
||||
// Returns the position of the directory, or a negative error code on failure.
|
||||
lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir);
|
||||
|
||||
// Change the position of the directory to the beginning of the directory
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir);
|
||||
|
||||
/// Miscellaneous littlefs specific operations ///
|
||||
|
||||
// Traverse through all blocks in use by the filesystem
|
||||
//
|
||||
// The provided callback will be called with each block address that is
|
||||
// currently in use by the filesystem. This can be used to determine which
|
||||
// blocks are in use or how much of the storage is available.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data);
|
||||
|
||||
// Prunes any recoverable errors that may have occured in the filesystem
|
||||
//
|
||||
// Not needed to be called by user unless an operation is interrupted
|
||||
// but the filesystem is still mounted. This is already called on first
|
||||
// allocation.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs_deorphan(lfs_t *lfs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* lfs util functions
|
||||
*
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#include "lfs_util.h"
|
||||
|
||||
// Only compile if user does not provide custom config
|
||||
#ifndef LFS_CONFIG
|
||||
|
||||
// Software CRC implementation with small lookup table
|
||||
void lfs_crc(uint32_t *restrict crc, const void *buffer, size_t size)
|
||||
{
|
||||
static const uint32_t rtable[16] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
|
||||
};
|
||||
|
||||
const uint8_t *data = buffer;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
*crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 0)) & 0xf];
|
||||
*crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 4)) & 0xf];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* lfs utility functions
|
||||
*
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef LFS_UTIL_H
|
||||
#define LFS_UTIL_H
|
||||
|
||||
// Users can override lfs_util.h with their own configuration by defining
|
||||
// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
|
||||
//
|
||||
// If LFS_CONFIG is used, none of the default utils will be emitted and must be
|
||||
// provided by the config file. To start I would suggest copying lfs_util.h and
|
||||
// modifying as needed.
|
||||
#ifdef LFS_CONFIG
|
||||
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
|
||||
#define LFS_STRINGIZE2(x) #x
|
||||
#include LFS_STRINGIZE(LFS_CONFIG)
|
||||
#else
|
||||
|
||||
// System includes
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef LFS_NO_MALLOC
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifndef LFS_NO_ASSERT
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#if !CFG_DEBUG
|
||||
#define LFS_NO_DEBUG
|
||||
#define LFS_NO_WARN
|
||||
#define LFS_NO_ERROR
|
||||
#endif
|
||||
|
||||
#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Macros, may be replaced by system specific wrappers. Arguments to these
|
||||
// macros must not have side-effects as the macros can be removed for a smaller
|
||||
// code footprint
|
||||
|
||||
// Logging functions
|
||||
#ifndef LFS_NO_DEBUG
|
||||
#define LFS_DEBUG(fmt, ...) printf("lfs debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LFS_DEBUG(fmt, ...)
|
||||
#endif
|
||||
|
||||
#ifndef LFS_NO_WARN
|
||||
#define LFS_WARN(fmt, ...) printf("lfs warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LFS_WARN(fmt, ...)
|
||||
#endif
|
||||
|
||||
#ifndef LFS_NO_ERROR
|
||||
#define LFS_ERROR(fmt, ...) printf("lfs error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LFS_ERROR(fmt, ...)
|
||||
#endif
|
||||
|
||||
// Runtime assertions
|
||||
#ifndef LFS_NO_ASSERT
|
||||
#define LFS_ASSERT(test) assert(test)
|
||||
#else
|
||||
#define LFS_ASSERT(test)
|
||||
#endif
|
||||
|
||||
// Builtin functions, these may be replaced by more efficient
|
||||
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
|
||||
// expensive basic C implementation for debugging purposes
|
||||
|
||||
// Min/max functions for unsigned 32-bit numbers
|
||||
static inline uint32_t lfs_max(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
static inline uint32_t lfs_min(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
// Find the next smallest power of 2 less than or equal to a
|
||||
static inline uint32_t lfs_npw2(uint32_t a)
|
||||
{
|
||||
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
||||
return 32 - __builtin_clz(a - 1);
|
||||
#else
|
||||
uint32_t r = 0;
|
||||
uint32_t s;
|
||||
a -= 1;
|
||||
s = (a > 0xffff) << 4;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
s = (a > 0xff) << 3;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
s = (a > 0xf) << 2;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
s = (a > 0x3) << 1;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
return (r | (a >> 1)) + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Count the number of trailing binary zeros in a
|
||||
// lfs_ctz(0) may be undefined
|
||||
static inline uint32_t lfs_ctz(uint32_t a)
|
||||
{
|
||||
#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
|
||||
return __builtin_ctz(a);
|
||||
#else
|
||||
return lfs_npw2((a & -a) + 1) - 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Count the number of binary ones in a
|
||||
static inline uint32_t lfs_popc(uint32_t a)
|
||||
{
|
||||
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
||||
return __builtin_popcount(a);
|
||||
#else
|
||||
a = a - ((a >> 1) & 0x55555555);
|
||||
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
|
||||
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Find the sequence comparison of a and b, this is the distance
|
||||
// between a and b ignoring overflow
|
||||
static inline int lfs_scmp(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (int)(unsigned)(a - b);
|
||||
}
|
||||
|
||||
// Convert from 32-bit little-endian to native order
|
||||
static inline uint32_t lfs_fromle32(uint32_t a)
|
||||
{
|
||||
#if !defined(LFS_NO_INTRINSICS) && ((defined(BYTE_ORDER) && BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \
|
||||
(defined(__BYTE_ORDER) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \
|
||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
return a;
|
||||
#elif !defined(LFS_NO_INTRINSICS) && \
|
||||
((defined(BYTE_ORDER) && BYTE_ORDER == ORDER_BIG_ENDIAN) || (defined(__BYTE_ORDER) && __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \
|
||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
return __builtin_bswap32(a);
|
||||
#else
|
||||
return (((uint8_t *)&a)[0] << 0) | (((uint8_t *)&a)[1] << 8) | (((uint8_t *)&a)[2] << 16) | (((uint8_t *)&a)[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Convert to 32-bit little-endian from native order
|
||||
static inline uint32_t lfs_tole32(uint32_t a)
|
||||
{
|
||||
return lfs_fromle32(a);
|
||||
}
|
||||
|
||||
// Calculate CRC-32 with polynomial = 0x04c11db7
|
||||
void lfs_crc(uint32_t *crc, const void *buffer, size_t size);
|
||||
|
||||
// Allocate memory, only used if buffers are not provided to littlefs
|
||||
static inline void *lfs_malloc(size_t size)
|
||||
{
|
||||
#ifndef LFS_NO_MALLOC
|
||||
return malloc(size);
|
||||
#else
|
||||
(void)size;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Deallocate memory, only used if buffers are not provided to littlefs
|
||||
static inline void lfs_free(void *p)
|
||||
{
|
||||
#ifndef LFS_NO_MALLOC
|
||||
free(p);
|
||||
#else
|
||||
(void)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -32,6 +32,8 @@ void powerCommandsCheck()
|
|||
delete screen;
|
||||
LOG_DEBUG("final reboot!");
|
||||
reboot();
|
||||
#elif defined(ARCH_STM32WL)
|
||||
HAL_NVIC_SystemReset();
|
||||
#else
|
||||
rebootAtMsec = -1;
|
||||
LOG_WARN("FIXME implement reboot for this platform. Note that some settings require a restart to be applied");
|
||||
|
|
|
@ -40,5 +40,9 @@
|
|||
// "USERPREFS_OEM_IMAGE_WIDTH": "50",
|
||||
// "USERPREFS_OEM_IMAGE_HEIGHT": "28",
|
||||
// "USERPREFS_OEM_IMAGE_DATA": "{ 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0x61, 0x00, 0x00, 0x00, 0x0C, 0xFF, 0xFF, 0xC7, 0x00, 0x00, 0x00, 0x0C, 0xFF, 0xFF, 0xC7, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0x67, 0x00, 0x00, 0x00, 0x18, 0x1F, 0xF0, 0x67, 0x00, 0x00, 0x00, 0x30, 0x1F, 0xF8, 0x33, 0x00, 0x00, 0x00, 0x30, 0x00, 0xFC, 0x31, 0x00, 0x00, 0x00, 0x60, 0x00, 0xFE, 0x18, 0x00, 0x00, 0x00, 0x60, 0x00, 0x7E, 0x18, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x3F, 0x0C, 0x00, 0x00, 0x00, 0xC0, 0x80, 0x1F, 0x0C, 0x00, 0x00, 0x00, 0x80, 0x81, 0x1F, 0x06, 0x00, 0x00, 0x00, 0x80, 0xC1, 0x0F, 0x06, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x8F, 0x01, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xC7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00}",
|
||||
// "USERPREFS_NETWORK_ENABLED_PROTOCOLS": "1", // Enable UDP mesh
|
||||
// "USERPREFS_NETWORK_WIFI_ENABLED": "true",
|
||||
// "USERPREFS_NETWORK_WIFI_SSID": "wifi_ssid",
|
||||
// "USERPREFS_NETWORK_WIFI_PSK": "wifi_psk",
|
||||
"USERPREFS_TZ_STRING": "tzplaceholder "
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ extends = stm32_base
|
|||
; `ebyte_e77_dev` was added in this commit. Remove when a new release is used in the base.
|
||||
platform = https://github.com/platformio/platform-ststm32.git#3208828db447f4373cd303b7f7393c8fc0dae623
|
||||
board = ebyte_e77_dev
|
||||
board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem
|
||||
board_level = extra
|
||||
build_flags =
|
||||
${stm32_base.build_flags}
|
||||
|
@ -11,31 +12,19 @@ build_flags =
|
|||
-DPIN_SERIAL_RX=PA3
|
||||
-DPIN_SERIAL_TX=PA2
|
||||
-DHAL_DAC_MODULE_ONLY
|
||||
-DHAL_ADC_MODULE_DISABLED
|
||||
-DHAL_COMP_MODULE_DISABLED
|
||||
-DHAL_CRC_MODULE_DISABLED
|
||||
-DHAL_CRYP_MODULE_DISABLED
|
||||
-DHAL_GTZC_MODULE_DISABLED
|
||||
-DHAL_HSEM_MODULE_DISABLED
|
||||
-DHAL_I2C_MODULE_DISABLED
|
||||
-DHAL_I2S_MODULE_DISABLED
|
||||
-DHAL_IPCC_MODULE_DISABLED
|
||||
-DHAL_IRDA_MODULE_DISABLED
|
||||
-DHAL_IWDG_MODULE_DISABLED
|
||||
-DHAL_LPTIM_MODULE_DISABLED
|
||||
-DHAL_PKA_MODULE_DISABLED
|
||||
-DHAL_RNG_MODULE_DISABLED
|
||||
-DHAL_RTC_MODULE_DISABLED
|
||||
-DHAL_SMARTCARD_MODULE_DISABLED
|
||||
-DHAL_SMBUS_MODULE_DISABLED
|
||||
-DHAL_TIM_MODULE_DISABLED
|
||||
-DHAL_WWDG_MODULE_DISABLED
|
||||
-DHAL_EXTI_MODULE_DISABLED
|
||||
-DHAL_SAI_MODULE_DISABLED
|
||||
-DHAL_ICACHE_MODULE_DISABLED
|
||||
-DHAL_RNG_MODULE_ENABLED
|
||||
-DRADIOLIB_EXCLUDE_SX128X=1
|
||||
-DRADIOLIB_EXCLUDE_SX127X=1
|
||||
-DRADIOLIB_EXCLUDE_LR11X0=1
|
||||
; -D PIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF
|
||||
-DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1
|
||||
-DMESHTASTIC_EXCLUDE_I2C=1
|
||||
-DMESHTASTIC_EXCLUDE_WIFI=1
|
||||
-DMESHTASTIC_EXCLUDE_BLUETOOTH=1
|
||||
-DMESHTASTIC_EXCLUDE_GPS=1
|
||||
-DMESHTASTIC_EXCLUDE_SCREEN=1
|
||||
-DMESHTASTIC_EXCLUDE_MQTT=1
|
||||
-DMESHTASTIC_EXCLUDE_POWERMON=1
|
||||
;-DPIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF
|
||||
;-DCFG_DEBUG
|
||||
|
||||
upload_port = stlink
|
|
@ -1,4 +1,4 @@
|
|||
[env:ThinkNode-M2]
|
||||
[env:thinknode_m2]
|
||||
extends = esp32s3_base
|
||||
board = ESP32-S3-WROOM-1-N4
|
||||
build_flags =
|
||||
|
|
|
@ -39,7 +39,7 @@ board = esp32-s3-devkitc-1
|
|||
board_level = extra
|
||||
upload_protocol = esptool
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D CROWPANEL_ESP32S3_5_EPAPER -I variants/crowpanel-esp32s3-5-epaper
|
||||
${esp32_base.build_flags} -D CROWPANEL_ESP32S3_4_EPAPER -I variants/crowpanel-esp32s3-5-epaper
|
||||
-D PRIVATE_HW
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DGPS_POWER_TOGGLE
|
||||
|
@ -67,7 +67,7 @@ board = esp32-s3-devkitc-1
|
|||
board_level = extra
|
||||
upload_protocol = esptool
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D CROWPANEL_ESP32S3_5_EPAPER -I variants/crowpanel-esp32s3-5-epaper
|
||||
${esp32_base.build_flags} -D CROWPANEL_ESP32S3_2_EPAPER -I variants/crowpanel-esp32s3-5-epaper
|
||||
-D PRIVATE_HW
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DGPS_POWER_TOGGLE
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
[env:hackerboxes-esp32-io]
|
||||
extends = esp32_base
|
||||
board = esp32dev
|
||||
board_level = extra
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-D PRIVATE_HW
|
||||
-I variants/hackerboxes_esp32_io
|
||||
monitor_speed = 115200
|
||||
upload_protocol = esptool
|
||||
;upload_port = /dev/ttyUSB0
|
||||
upload_speed = 921600
|
|
@ -0,0 +1,30 @@
|
|||
#define BUTTON_PIN 0
|
||||
|
||||
// HACKBOX LoRa IO Kit
|
||||
// Uses a ESP-32-WROOM and a RA-01SH (SX1262) LoRa Board
|
||||
|
||||
#define LED_PIN 2 // LED
|
||||
#define LED_STATE_ON 1 // State when LED is lit
|
||||
|
||||
#define HAS_SCREEN 0
|
||||
#define HAS_GPS 0
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
|
||||
#define USE_SX1262
|
||||
#define LORA_SCK 18
|
||||
#define LORA_MISO 19
|
||||
#define LORA_MOSI 23
|
||||
#define LORA_CS 5
|
||||
#define LORA_DIO0 RADIOLIB_NC
|
||||
#define LORA_RESET 27
|
||||
#define LORA_DIO1 33
|
||||
#define LORA_DIO2 RADIOLIB_NC
|
||||
#define LORA_BUSY 32
|
||||
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_BUSY
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_MAX_POWER 22 // Max power of the RA-01SH is 22db
|
|
@ -0,0 +1,14 @@
|
|||
[env:hackerboxes-esp32c3-oled]
|
||||
extends = esp32c3_base
|
||||
board = esp32-c3-devkitm-1
|
||||
board_level = extra
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-D PRIVATE_HW
|
||||
-D ARDUINO_USB_MODE=1
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||
-I variants/hackerboxes_esp32c3_oled
|
||||
monitor_speed = 115200
|
||||
upload_protocol = esptool
|
||||
;upload_port = /dev/ttyUSB0
|
||||
upload_speed = 921600
|
|
@ -0,0 +1,36 @@
|
|||
#define BUTTON_PIN 9
|
||||
|
||||
// Hackerboxes LoRa ESP32-C3 OLED Kit
|
||||
// Uses a ESP32-C3 OLED Board and a RA-01SH (SX1262) LoRa Board
|
||||
|
||||
#define LED_PIN 8 // LED
|
||||
#define LED_STATE_ON 1 // State when LED is lit
|
||||
|
||||
#define HAS_SCREEN 0
|
||||
#define HAS_GPS 0
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
|
||||
// #define USE_SSD1306_72_40
|
||||
// #define I2C_SDA 5 // I2C pins for this board
|
||||
// #define I2C_SCL 6 //
|
||||
// #define TFT_WIDTH 72
|
||||
// #define TFT_HEIGHT 40
|
||||
|
||||
#define USE_SX1262
|
||||
#define LORA_SCK 4
|
||||
#define LORA_MISO 7
|
||||
#define LORA_MOSI 3
|
||||
#define LORA_CS 1
|
||||
#define LORA_DIO0 RADIOLIB_NC
|
||||
#define LORA_RESET 0
|
||||
#define LORA_DIO1 20
|
||||
#define LORA_DIO2 RADIOLIB_NC
|
||||
#define LORA_BUSY 10
|
||||
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_BUSY
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_MAX_POWER 22 // Max power of the RA-01SH is 22db
|
|
@ -0,0 +1,11 @@
|
|||
[env:heltec_sensor_hub]
|
||||
extends = esp32s3_base
|
||||
board = heltec_wifi_lora_32_V3
|
||||
board_check = true
|
||||
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags} -I variants/heltec_sensor_hub
|
||||
-D HELTEC_SENSOR_HUB
|
||||
|
||||
lib_deps = ${esp32s3_base.lib_deps}
|
||||
adafruit/Adafruit NeoPixel @ ^1.12.0
|
|
@ -0,0 +1,46 @@
|
|||
#define EXT_PWR_DETECT 20
|
||||
|
||||
#define BUTTON_PIN 17
|
||||
|
||||
#define BATTERY_PIN 7 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
#define ADC_CHANNEL ADC1_GPIO7_CHANNEL
|
||||
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
|
||||
#define ADC_MULTIPLIER (4.9 * 1.045)
|
||||
#define ADC_CTRL 34 // active HIGH, powers the voltage divider. Only on 1.1
|
||||
#define ADC_CTRL_ENABLED HIGH
|
||||
|
||||
#define HAS_NEOPIXEL // Enable the use of neopixels
|
||||
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
|
||||
#define NEOPIXEL_DATA 18 // gpio pin used to send data to the neopixels
|
||||
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
|
||||
|
||||
#define USE_SX1262
|
||||
#define LORA_DIO0 RADIOLIB_NC
|
||||
#define LORA_RESET 12
|
||||
#define LORA_DIO1 14 // SX1262 IRQ
|
||||
#define LORA_DIO2 13 // SX1262 BUSY
|
||||
|
||||
#define LORA_SCK 9
|
||||
#define LORA_MISO 11
|
||||
#define LORA_MOSI 10
|
||||
#define LORA_CS 8
|
||||
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
#define I2C_SDA 1
|
||||
#define I2C_SCL 2
|
||||
#define HAS_SCREEN 0
|
||||
#define SENSOR_POWER_CTRL_PIN 33
|
||||
#define SENSOR_POWER_ON 1
|
||||
|
||||
#define PERIPHERAL_WARMUP_MS 100
|
||||
|
||||
#define ESP32S3_WAKE_TYPE ESP_EXT1_WAKEUP_ANY_HIGH
|
||||
|
||||
#define ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE 1
|
|
@ -27,6 +27,7 @@ build_flags = ${native_base.build_flags} -Os -lX11 -linput -lxkbcommon -ffunctio
|
|||
-D USE_X11=1
|
||||
-D HAS_TFT=1
|
||||
-D HAS_SCREEN=0
|
||||
-D LV_CACHE_DEF_SIZE=6291456
|
||||
-D LV_BUILD_TEST=0
|
||||
-D LV_USE_LIBINPUT=1
|
||||
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||
|
@ -56,7 +57,7 @@ build_flags = ${native_base.build_flags} -O0 -fsanitize=address -lX11 -linput -l
|
|||
-D USE_X11=1
|
||||
-D HAS_TFT=1
|
||||
-D HAS_SCREEN=0
|
||||
; -D CALIBRATE_TOUCH=0
|
||||
-D LV_CACHE_DEF_SIZE=6291456
|
||||
-D LV_BUILD_TEST=0
|
||||
-D LV_USE_LOG=1
|
||||
-D LV_USE_SYSMON=1
|
||||
|
|
|
@ -1,36 +1,23 @@
|
|||
[env:rak3172]
|
||||
extends = stm32_base
|
||||
board = wiscore_rak3172
|
||||
board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem
|
||||
build_flags =
|
||||
${stm32_base.build_flags}
|
||||
-Ivariants/rak3172
|
||||
-DSERIAL_UART_INSTANCE=1
|
||||
-DPIN_SERIAL_RX=PB7
|
||||
-DPIN_SERIAL_TX=PB6
|
||||
-DHAL_DAC_MODULE_ONLY
|
||||
-DHAL_ADC_MODULE_DISABLED
|
||||
-DHAL_COMP_MODULE_DISABLED
|
||||
-DHAL_CRC_MODULE_DISABLED
|
||||
-DHAL_CRYP_MODULE_DISABLED
|
||||
-DHAL_GTZC_MODULE_DISABLED
|
||||
-DHAL_HSEM_MODULE_DISABLED
|
||||
-DHAL_I2C_MODULE_DISABLED
|
||||
-DHAL_I2S_MODULE_DISABLED
|
||||
-DHAL_IPCC_MODULE_DISABLED
|
||||
-DHAL_IRDA_MODULE_DISABLED
|
||||
-DHAL_IWDG_MODULE_DISABLED
|
||||
-DHAL_LPTIM_MODULE_DISABLED
|
||||
-DHAL_PKA_MODULE_DISABLED
|
||||
-DHAL_RNG_MODULE_DISABLED
|
||||
-DHAL_RTC_MODULE_DISABLED
|
||||
-DHAL_SMARTCARD_MODULE_DISABLED
|
||||
-DHAL_SMBUS_MODULE_DISABLED
|
||||
-DHAL_TIM_MODULE_DISABLED
|
||||
-DHAL_WWDG_MODULE_DISABLED
|
||||
-DHAL_EXTI_MODULE_DISABLED
|
||||
-DHAL_SAI_MODULE_DISABLED
|
||||
-DHAL_ICACHE_MODULE_DISABLED
|
||||
-DHAL_RNG_MODULE_ENABLED
|
||||
-DRADIOLIB_EXCLUDE_SX128X=1
|
||||
-DRADIOLIB_EXCLUDE_SX127X=1
|
||||
-DRADIOLIB_EXCLUDE_LR11X0=1
|
||||
upload_port = stlink
|
||||
-DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1
|
||||
-DMESHTASTIC_EXCLUDE_I2C=1
|
||||
-DMESHTASTIC_EXCLUDE_WIFI=1
|
||||
-DMESHTASTIC_EXCLUDE_BLUETOOTH=1
|
||||
-DMESHTASTIC_EXCLUDE_GPS=1
|
||||
-DMESHTASTIC_EXCLUDE_SCREEN=1
|
||||
-DMESHTASTIC_EXCLUDE_MQTT=1
|
||||
-DMESHTASTIC_EXCLUDE_POWERMON=1
|
||||
;-DPIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF
|
||||
;-DCFG_DEBUG
|
||||
upload_port = stlink
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
/*
|
||||
STM32WLE5 Core Module for LoRaWAN® RAK3372
|
||||
https://store.rakwireless.com/products/wisblock-core-module-rak3372
|
||||
*/
|
||||
|
||||
/*
|
||||
This variant is a work in progress.
|
||||
Do not expect a working Meshtastic device with this target.
|
||||
|
@ -8,4 +13,7 @@ Do not expect a working Meshtastic device with this target.
|
|||
|
||||
#define USE_STM32WLx
|
||||
|
||||
#endif
|
||||
#define LED_PIN PA0 // Green LED
|
||||
#define LED_STATE_ON 1
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,8 +23,9 @@ build_flags = ${rp2350_base.build_flags}
|
|||
-DHAS_WIFI=1
|
||||
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m33"
|
||||
-fexceptions # for exception handling in MQTT
|
||||
-DHAS_UDP_MULTICAST=1
|
||||
build_src_filter = ${rp2350_base.build_src_filter} +<mesh/wifi/>
|
||||
lib_deps =
|
||||
${rp2350_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
debug_build_flags = ${rp2350_base.build_flags}, -g
|
||||
debug_build_flags = ${rp2350_base.build_flags}, -g
|
||||
|
|
|
@ -10,9 +10,10 @@ build_flags = ${rp2040_base.build_flags}
|
|||
-DHW_SPI1_DEVICE
|
||||
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
|
||||
-fexceptions # for exception handling in MQTT
|
||||
-DHAS_UDP_MULTICAST=1
|
||||
build_src_filter = ${rp2040_base.build_src_filter} +<mesh/wifi/>
|
||||
lib_deps =
|
||||
${rp2040_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
debug_build_flags = ${rp2040_base.build_flags}, -g
|
||||
debug_tool = cmsis-dap ; for e.g. Picotool
|
||||
debug_tool = cmsis-dap ; for e.g. Picotool
|
||||
|
|
|
@ -24,7 +24,7 @@ build_flags = ${esp32_base.build_flags}
|
|||
-DUSE_ARDUINO_HAL_GPIO
|
||||
|
||||
lib_deps = ${esp32s3_base.lib_deps}
|
||||
https://github.com/mverch67/LovyanGFX#develop
|
||||
https://github.com/mverch67/LovyanGFX#4c76238c1344162a234ae917b27651af146d6fb2
|
||||
earlephilhower/ESP8266Audio@^1.9.9
|
||||
earlephilhower/ESP8266SAM@^1.0.1
|
||||
|
||||
|
@ -49,7 +49,7 @@ build_flags =
|
|||
-D HAS_SCREEN=0
|
||||
-D HAS_TFT=1
|
||||
-D DISPLAY_SET_RESOLUTION
|
||||
-D USE_I2S_BUZZER
|
||||
-D USE_PIN_BUZZER
|
||||
-D RAM_SIZE=4096
|
||||
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||
-D LV_CONF_INCLUDE_SIMPLE
|
||||
|
@ -65,10 +65,9 @@ build_flags =
|
|||
-D LGFX_DRIVER=LGFX_INDICATOR
|
||||
-D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_INDICATOR.h\"
|
||||
-D VIEW_320x240
|
||||
; -D USE_DOUBLE_BUFFER
|
||||
-D USE_PACKET_API
|
||||
|
||||
lib_deps =
|
||||
${env:seeed-sensecap-indicator.lib_deps}
|
||||
${device-ui_base.lib_deps}
|
||||
https://github.com/bitbank2/bb_captouch.git#8f2f06462ff597847921739376a299db93612417 ; alternative touch library supporting FT6x36
|
||||
https://github.com/mverch67/bb_captouch.git#8626412fe650d808a267791c0eae6e5860c85a5d ; alternative touch library supporting FT6x36
|
||||
|
|
|
@ -42,7 +42,7 @@ build_flags =
|
|||
-D HAS_SCREEN=0
|
||||
-D HAS_TFT=1
|
||||
-D USE_I2S_BUZZER
|
||||
-D RAM_SIZE=4096
|
||||
-D RAM_SIZE=5120
|
||||
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||
-D LV_CONF_INCLUDE_SIMPLE
|
||||
-D LV_COMP_CONF_INCLUDE_SIMPLE
|
||||
|
@ -66,6 +66,7 @@ build_flags =
|
|||
-D VIEW_320x240
|
||||
; -D USE_DOUBLE_BUFFER
|
||||
-D USE_PACKET_API
|
||||
-D MAP_FULL_REDRAW
|
||||
|
||||
lib_deps =
|
||||
${env:t-deck.lib_deps}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
extends = esp32s3_base
|
||||
board = t-watch-s3
|
||||
board_check = true
|
||||
board_build.partitions = default_16MB.csv
|
||||
board_build.partitions = default_8MB.csv
|
||||
upload_protocol = esptool
|
||||
|
||||
build_flags = ${esp32_base.build_flags}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[env:wio-e5]
|
||||
extends = stm32_base
|
||||
board = lora_e5_dev_board
|
||||
board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem
|
||||
build_flags =
|
||||
${stm32_base.build_flags}
|
||||
-Ivariants/wio-e5
|
||||
|
@ -8,31 +9,19 @@ build_flags =
|
|||
-DPIN_SERIAL_RX=PB7
|
||||
-DPIN_SERIAL_TX=PB6
|
||||
-DHAL_DAC_MODULE_ONLY
|
||||
-DHAL_ADC_MODULE_DISABLED
|
||||
-DHAL_COMP_MODULE_DISABLED
|
||||
-DHAL_CRC_MODULE_DISABLED
|
||||
-DHAL_CRYP_MODULE_DISABLED
|
||||
-DHAL_GTZC_MODULE_DISABLED
|
||||
-DHAL_HSEM_MODULE_DISABLED
|
||||
-DHAL_I2C_MODULE_DISABLED
|
||||
-DHAL_I2S_MODULE_DISABLED
|
||||
-DHAL_IPCC_MODULE_DISABLED
|
||||
-DHAL_IRDA_MODULE_DISABLED
|
||||
-DHAL_IWDG_MODULE_DISABLED
|
||||
-DHAL_LPTIM_MODULE_DISABLED
|
||||
-DHAL_PKA_MODULE_DISABLED
|
||||
-DHAL_RNG_MODULE_DISABLED
|
||||
-DHAL_RTC_MODULE_DISABLED
|
||||
-DHAL_SMARTCARD_MODULE_DISABLED
|
||||
-DHAL_SMBUS_MODULE_DISABLED
|
||||
-DHAL_TIM_MODULE_DISABLED
|
||||
-DHAL_WWDG_MODULE_DISABLED
|
||||
-DHAL_EXTI_MODULE_DISABLED
|
||||
-DHAL_SAI_MODULE_DISABLED
|
||||
-DHAL_ICACHE_MODULE_DISABLED
|
||||
-DHAL_RNG_MODULE_ENABLED
|
||||
-DRADIOLIB_EXCLUDE_SX128X=1
|
||||
-DRADIOLIB_EXCLUDE_SX127X=1
|
||||
-DRADIOLIB_EXCLUDE_LR11X0=1
|
||||
; -D PIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF
|
||||
-DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1
|
||||
-DMESHTASTIC_EXCLUDE_I2C=1
|
||||
-DMESHTASTIC_EXCLUDE_WIFI=1
|
||||
-DMESHTASTIC_EXCLUDE_BLUETOOTH=1
|
||||
-DMESHTASTIC_EXCLUDE_GPS=1
|
||||
-DMESHTASTIC_EXCLUDE_SCREEN=1
|
||||
-DMESHTASTIC_EXCLUDE_MQTT=1
|
||||
-DMESHTASTIC_EXCLUDE_POWERMON=1
|
||||
;-DPIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF
|
||||
;-DCFG_DEBUG
|
||||
|
||||
upload_port = stlink
|
|
@ -17,4 +17,9 @@ Do not expect a working Meshtastic device with this target.
|
|||
#define LED_PIN PB5
|
||||
#define LED_STATE_ON 1
|
||||
|
||||
#if (defined(LED_BUILTIN) && LED_BUILTIN == PNUM_NOT_DEFINED)
|
||||
#undef LED_BUILTIN
|
||||
#define LED_BUILTIN (LED_PIN)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[VERSION]
|
||||
major = 2
|
||||
minor = 6
|
||||
build = 2
|
||||
build = 3
|
||||
|
|
Ładowanie…
Reference in New Issue