mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-16 08:31:35 +10:00
Compare commits
37
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
640e731ad2 | ||
|
|
ba81a8ad87 | ||
|
|
83d8e3cb09 | ||
|
|
6429eca5e4 | ||
|
|
13101c1bab | ||
|
|
d28af68b5a | ||
|
|
53a7afff41 | ||
|
|
eb375d8e62 | ||
|
|
33f2b7144f | ||
|
|
e5f8218d34 | ||
|
|
0ddb507055 | ||
|
|
3afe84c4f4 | ||
|
|
e9d8a3d7f9 | ||
|
|
e722a97987 | ||
|
|
daa4186d65 | ||
|
|
1ee800e901 | ||
|
|
cf7f0f9d08 | ||
|
|
1e4a0134e6 | ||
|
|
0951fdd49b | ||
|
|
848a3ed6a1 | ||
|
|
fd7a1f2ccb | ||
|
|
5acaf8f897 | ||
|
|
cff93adb5e | ||
|
|
e4d3ec1f59 | ||
|
|
ae27aaaf43 | ||
|
|
31c0e8fa2c | ||
|
|
0d95b1afcc | ||
|
|
46235f6f8b | ||
|
|
d1068fd1e4 | ||
|
|
f41afb14b1 | ||
|
|
f8ad02aab3 | ||
|
|
077759e15d | ||
|
|
22aa2d7582 | ||
|
|
6673cb9292 | ||
|
|
8efc9702d3 | ||
|
|
2876eec7ed | ||
|
|
9cc13e628a |
@@ -29,6 +29,7 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|||||||
gpg \
|
gpg \
|
||||||
gnupg2 \
|
gnupg2 \
|
||||||
libusb-1.0-0-dev \
|
libusb-1.0-0-dev \
|
||||||
|
libuv1-dev \
|
||||||
libi2c-dev \
|
libi2c-dev \
|
||||||
libxcb-xkb-dev \
|
libxcb-xkb-dev \
|
||||||
libxkbcommon-dev \
|
libxkbcommon-dev \
|
||||||
|
|||||||
@@ -72,6 +72,15 @@ body:
|
|||||||
validations:
|
validations:
|
||||||
required: true
|
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
|
- type: input
|
||||||
id: version
|
id: version
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
@@ -11,4 +11,4 @@ runs:
|
|||||||
- name: Install libs needed for native build
|
- name: Install libs needed for native build
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
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
|
||||||
|
|||||||
+5
-5
@@ -9,14 +9,14 @@ plugins:
|
|||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- prettier@3.5.3
|
- prettier@3.5.3
|
||||||
- trufflehog@3.88.17
|
- trufflehog@3.88.18
|
||||||
- yamllint@1.36.0
|
- yamllint@1.37.0
|
||||||
- bandit@1.8.3
|
- bandit@1.8.3
|
||||||
- checkov@3.2.386
|
- checkov@3.2.392
|
||||||
- terrascan@1.19.9
|
- terrascan@1.19.9
|
||||||
- trivy@0.60.0
|
- trivy@0.60.0
|
||||||
- taplo@0.9.3
|
- taplo@0.9.3
|
||||||
- ruff@0.10.0
|
- ruff@0.11.2
|
||||||
- isort@6.0.1
|
- isort@6.0.1
|
||||||
- markdownlint@0.44.0
|
- markdownlint@0.44.0
|
||||||
- oxipng@9.1.4
|
- oxipng@9.1.4
|
||||||
@@ -28,7 +28,7 @@ lint:
|
|||||||
- shellcheck@0.10.0
|
- shellcheck@0.10.0
|
||||||
- black@25.1.0
|
- black@25.1.0
|
||||||
- git-diff-check
|
- git-diff-check
|
||||||
- gitleaks@8.24.0
|
- gitleaks@8.24.2
|
||||||
- clang-format@16.0.3
|
- clang-format@16.0.3
|
||||||
ignore:
|
ignore:
|
||||||
- linters: [ALL]
|
- linters: [ALL]
|
||||||
|
|||||||
+2
-2
@@ -13,7 +13,7 @@ ENV TZ=Etc/UTC
|
|||||||
ENV PIP_ROOT_USER_ACTION=ignore
|
ENV PIP_ROOT_USER_ACTION=ignore
|
||||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||||
wget g++ zip git ca-certificates \
|
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 \
|
libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev pkg-config \
|
||||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
|
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
|
||||||
&& pip install --no-cache-dir -U platformio \
|
&& pip install --no-cache-dir -U platformio \
|
||||||
@@ -38,7 +38,7 @@ ENV TZ=Etc/UTC
|
|||||||
USER root
|
USER root
|
||||||
|
|
||||||
RUN apt-get update && apt-get --no-install-recommends -y install \
|
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/* \
|
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
|
||||||
&& mkdir -p /var/lib/meshtasticd \
|
&& mkdir -p /var/lib/meshtasticd \
|
||||||
&& mkdir -p /etc/meshtasticd/config.d \
|
&& mkdir -p /etc/meshtasticd/config.d \
|
||||||
|
|||||||
+2
-2
@@ -9,7 +9,7 @@ FROM python:3.13-alpine3.21 AS builder
|
|||||||
ENV PIP_ROOT_USER_ACTION=ignore
|
ENV PIP_ROOT_USER_ACTION=ignore
|
||||||
RUN apk --no-cache add \
|
RUN apk --no-cache add \
|
||||||
bash g++ libstdc++-dev linux-headers zip git ca-certificates libgpiod-dev yaml-cpp-dev bluez-dev \
|
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/* \
|
&& rm -rf /var/cache/apk/* \
|
||||||
&& pip install --no-cache-dir -U platformio \
|
&& pip install --no-cache-dir -U platformio \
|
||||||
&& mkdir /tmp/firmware
|
&& mkdir /tmp/firmware
|
||||||
@@ -32,7 +32,7 @@ FROM alpine:3.21
|
|||||||
USER root
|
USER root
|
||||||
|
|
||||||
RUN apk --no-cache add \
|
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/* \
|
&& rm -rf /var/cache/apk/* \
|
||||||
&& mkdir -p /var/lib/meshtasticd \
|
&& mkdir -p /var/lib/meshtasticd \
|
||||||
&& mkdir -p /etc/meshtasticd/config.d \
|
&& mkdir -p /etc/meshtasticd/config.d \
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ build_flags =
|
|||||||
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
|
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
|
||||||
-DMESHTASTIC_EXCLUDE_AUDIO=1
|
-DMESHTASTIC_EXCLUDE_AUDIO=1
|
||||||
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
|
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
|
||||||
-DMAX_NUM_NODES=80
|
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp>
|
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
; The Portduino based 'native' environment. Currently supported on Linux targets with real LoRa hardware (or simulated).
|
; The Portduino based 'native' environment. Currently supported on Linux targets with real LoRa hardware (or simulated).
|
||||||
[portduino_base]
|
[portduino_base]
|
||||||
platform = https://github.com/meshtastic/platform-native.git#562d189828f09fbf4c4093b3c0104bae9d8e9ff9
|
platform = https://github.com/meshtastic/platform-native.git#e82ba1a19b6cd1dc55cbde29b33ea8dd0640014f
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
@@ -34,10 +34,12 @@ build_flags =
|
|||||||
-Isrc/platform/portduino
|
-Isrc/platform/portduino
|
||||||
-DRADIOLIB_EEPROM_UNSUPPORTED
|
-DRADIOLIB_EEPROM_UNSUPPORTED
|
||||||
-DPORTDUINO_LINUX_HARDWARE
|
-DPORTDUINO_LINUX_HARDWARE
|
||||||
|
-DHAS_UDP_MULTICAST
|
||||||
-lpthread
|
-lpthread
|
||||||
-lstdc++fs
|
-lstdc++fs
|
||||||
-lbluetooth
|
-lbluetooth
|
||||||
-lgpiod
|
-lgpiod
|
||||||
-lyaml-cpp
|
-lyaml-cpp
|
||||||
-li2c
|
-li2c
|
||||||
|
-luv
|
||||||
-std=c++17
|
-std=c++17
|
||||||
|
|||||||
+13
-15
@@ -1,13 +1,14 @@
|
|||||||
[stm32_base]
|
[stm32_base]
|
||||||
extends = arduino_base
|
extends = arduino_base
|
||||||
platform = platformio/ststm32
|
platform = ststm32
|
||||||
platform_packages = platformio/framework-arduinoststm32@^4.20900.0
|
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
|
build_type = release
|
||||||
|
|
||||||
;board_build.flash_offset = 0x08000000
|
build_flags =
|
||||||
|
|
||||||
build_flags =
|
|
||||||
${arduino_base.build_flags}
|
${arduino_base.build_flags}
|
||||||
-flto
|
-flto
|
||||||
-Isrc/platform/stm32wl -g
|
-Isrc/platform/stm32wl -g
|
||||||
@@ -18,27 +19,24 @@ build_flags =
|
|||||||
-DMESHTASTIC_EXCLUDE_SCREEN
|
-DMESHTASTIC_EXCLUDE_SCREEN
|
||||||
-DMESHTASTIC_EXCLUDE_MQTT
|
-DMESHTASTIC_EXCLUDE_MQTT
|
||||||
-DMESHTASTIC_EXCLUDE_BLUETOOTH
|
-DMESHTASTIC_EXCLUDE_BLUETOOTH
|
||||||
-DMESHTASTIC_EXCLUDE_PKI
|
|
||||||
-DMESHTASTIC_EXCLUDE_GPS
|
-DMESHTASTIC_EXCLUDE_GPS
|
||||||
; -DVECT_TAB_OFFSET=0x08000000
|
;-DDEBUG_MUTE
|
||||||
-DconfigUSE_CMSIS_RTOS_V2=1
|
|
||||||
; -DSPI_MODE_0=SPI_MODE0
|
|
||||||
-fmerge-all-constants
|
-fmerge-all-constants
|
||||||
-ffunction-sections
|
-ffunction-sections
|
||||||
-fdata-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>
|
${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
|
board_upload.offset_address = 0x08000000
|
||||||
upload_protocol = stlink
|
upload_protocol = stlink
|
||||||
|
debug_tool = stlink
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
charlesbaynham/OSFS@^1.2.3
|
${radiolib_base.lib_deps}
|
||||||
jgromes/RadioLib@7.0.2
|
https://github.com/caveman99/Crypto.git#eae9c768054118a9399690f8af202853d1ae8516
|
||||||
https://github.com/caveman99/Crypto.git#f61ae26a53f7a2d0ba5511625b8bf8eff3a35d5e
|
|
||||||
|
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
mathertel/OneButton@2.6.1
|
mathertel/OneButton@2.6.1
|
||||||
Wire
|
Wire
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
CS: 0
|
||||||
|
IRQ: 6
|
||||||
|
Reset: 2
|
||||||
|
Busy: 4
|
||||||
|
RXen: 1
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
spidev: ch341
|
||||||
|
USB_PID: 0x5512
|
||||||
|
USB_VID: 0x1A86
|
||||||
|
# Optional: Reduce power to 10 dBm to
|
||||||
|
# avoid over-drawing the USB port
|
||||||
|
# SX126X_MAX_POWER: 10
|
||||||
|
# Optional: Set the serial number for multi-radio support
|
||||||
|
# USB_Serialnum: 13374201
|
||||||
+28
-29
@@ -7,12 +7,19 @@ SET "DEBUG=0"
|
|||||||
SET "PYTHON="
|
SET "PYTHON="
|
||||||
SET "WEB_APP=0"
|
SET "WEB_APP=0"
|
||||||
SET "TFT_BUILD=0"
|
SET "TFT_BUILD=0"
|
||||||
SET "TFT8=0"
|
SET "BIGDB8=0"
|
||||||
SET "TFT16=0"
|
SET "BIGDB16=0"
|
||||||
SET "ESPTOOL_BAUD=115200"
|
SET "ESPTOOL_BAUD=115200"
|
||||||
SET "ESPTOOL_CMD="
|
SET "ESPTOOL_CMD="
|
||||||
SET "LOGCOUNTER=0"
|
SET "LOGCOUNTER=0"
|
||||||
|
|
||||||
|
@REM FIXME: Determine mcu from PlatformIO variant, this is unmaintainable.
|
||||||
|
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"
|
||||||
|
|
||||||
GOTO getopts
|
GOTO getopts
|
||||||
:help
|
:help
|
||||||
ECHO Flash image file to device, but first erasing and writing system information.
|
ECHO Flash image file to device, but first erasing and writing system information.
|
||||||
@@ -34,7 +41,7 @@ ECHO Example: %SCRIPT_NAME% -f firmware-unphone-2.6.0.0b106d4.bin -p COM11 --web
|
|||||||
GOTO eof
|
GOTO eof
|
||||||
|
|
||||||
:version
|
:version
|
||||||
ECHO %SCRIPT_NAME% [Version 2.6.0]
|
ECHO %SCRIPT_NAME% [Version 2.6.1]
|
||||||
ECHO Meshtastic
|
ECHO Meshtastic
|
||||||
GOTO eof
|
GOTO eof
|
||||||
|
|
||||||
@@ -106,7 +113,7 @@ IF NOT "__%PYTHON%__"=="____" (
|
|||||||
|
|
||||||
CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..."
|
CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..."
|
||||||
!ESPTOOL_CMD! >nul 2>&1
|
!ESPTOOL_CMD! >nul 2>&1
|
||||||
IF %ERRORLEVEL% GTR 2 (
|
IF %ERRORLEVEL% GEQ 2 (
|
||||||
@REM esptool exits with code 1 if help is displayed.
|
@REM esptool exits with code 1 if help is displayed.
|
||||||
CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!"
|
CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!"
|
||||||
EXIT /B 1
|
EXIT /B 1
|
||||||
@@ -121,6 +128,7 @@ CALL :LOG_MESSAGE DEBUG "Using esptool command: !ESPTOOL_CMD!"
|
|||||||
IF "__!ESPTOOL_PORT!__" == "____" (
|
IF "__!ESPTOOL_PORT!__" == "____" (
|
||||||
CALL :LOG_MESSAGE WARN "Using esptool port: UNSET."
|
CALL :LOG_MESSAGE WARN "Using esptool port: UNSET."
|
||||||
) ELSE (
|
) ELSE (
|
||||||
|
SET "ESPTOOL_CMD=!ESPTOOL_CMD! --port !ESPTOOL_PORT!"
|
||||||
CALL :LOG_MESSAGE INFO "Using esptool port: !ESPTOOL_PORT!."
|
CALL :LOG_MESSAGE INFO "Using esptool port: !ESPTOOL_PORT!."
|
||||||
)
|
)
|
||||||
CALL :LOG_MESSAGE INFO "Using esptool baud: !ESPTOOL_BAUD!."
|
CALL :LOG_MESSAGE INFO "Using esptool baud: !ESPTOOL_BAUD!."
|
||||||
@@ -133,44 +141,36 @@ IF NOT "!FILENAME:-tft-=!"=="!FILENAME!" (
|
|||||||
CALL :LOG_MESSAGE ERROR "Cannot enable WebUI (--web) and MUI." & GOTO eof
|
CALL :LOG_MESSAGE ERROR "Cannot enable WebUI (--web) and MUI." & GOTO eof
|
||||||
)
|
)
|
||||||
SET "TFT_BUILD=1"
|
SET "TFT_BUILD=1"
|
||||||
GOTO tft
|
|
||||||
) ELSE (
|
) ELSE (
|
||||||
CALL :LOG_MESSAGE DEBUG "We are NOT working with a *-tft-* file. !FILENAME!"
|
CALL :LOG_MESSAGE DEBUG "We are NOT working with a *-tft-* file. !FILENAME!"
|
||||||
GOTO no_tft
|
|
||||||
)
|
)
|
||||||
|
|
||||||
:tft
|
FOR %%a IN (%BIGDB_8MB%) DO (
|
||||||
SET "TFT8MB=picomputer-s3 unphone seeed-sensecap-indicator"
|
|
||||||
FOR %%a IN (%TFT8MB%) DO (
|
|
||||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
||||||
@REM We are working with any of %TFT8MB%.
|
@REM We are working with any of %BIGDB_8MB%.
|
||||||
SET "TFT8=1"
|
SET "BIGDB8=1"
|
||||||
GOTO end_loop_tft8mb
|
GOTO end_loop_bigdb_8mb
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
:end_loop_tft8mb
|
:end_loop_bigdb_8mb
|
||||||
|
|
||||||
SET "TFT16MB=t-deck"
|
FOR %%a IN (%BIGDB_16MB%) DO (
|
||||||
FOR %%a IN (%TFT16MB%) DO (
|
|
||||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
||||||
@REM We are working with any of %TFT16MB%.
|
@REM We are working with any of %BIGDB_16MB%.
|
||||||
SET "TFT16=1"
|
SET "BIGDB16=1"
|
||||||
GOTO end_loop_tft16mb
|
GOTO end_loop_bigdb_16mb
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
:end_loop_tft16mb
|
:end_loop_bigdb_16mb
|
||||||
|
|
||||||
IF %TFT8% EQU 1 CALL :LOG_MESSAGE INFO "tft and MUI 8mb selected."
|
IF %BIGDB8% EQU 1 CALL :LOG_MESSAGE INFO "BigDB 8mb partition selected."
|
||||||
IF %TFT16% EQU 1 CALL :LOG_MESSAGE INFO "tft and MUI 16mb selected."
|
IF %BIGDB16% EQU 1 CALL :LOG_MESSAGE INFO "BigDB 16mb partition selected."
|
||||||
|
|
||||||
:no_tft
|
|
||||||
|
|
||||||
@REM Extract BASENAME from %FILENAME% for later use.
|
@REM Extract BASENAME from %FILENAME% for later use.
|
||||||
SET "BASENAME=!FILENAME:firmware-=!"
|
SET "BASENAME=!FILENAME:firmware-=!"
|
||||||
CALL :LOG_MESSAGE DEBUG "Computed firmware basename: !BASENAME!"
|
CALL :LOG_MESSAGE DEBUG "Computed firmware basename: !BASENAME!"
|
||||||
|
|
||||||
@REM Account for S3 and C3 board's different OTA partition.
|
@REM Account for S3 and C3 board's different OTA partition.
|
||||||
SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone"
|
|
||||||
FOR %%a IN (%S3%) DO (
|
FOR %%a IN (%S3%) DO (
|
||||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
||||||
@REM We are working with any of %S3%.
|
@REM We are working with any of %S3%.
|
||||||
@@ -179,7 +179,6 @@ FOR %%a IN (%S3%) DO (
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
SET "C3=esp32c3"
|
|
||||||
FOR %%a IN (%C3%) DO (
|
FOR %%a IN (%C3%) DO (
|
||||||
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
IF NOT "!FILENAME:%%a=!"=="!FILENAME!" (
|
||||||
@REM We are working with any of %C3%.
|
@REM We are working with any of %C3%.
|
||||||
@@ -208,14 +207,14 @@ CALL :LOG_MESSAGE DEBUG "Set SPIFFS_FILENAME to: !SPIFFS_FILENAME!"
|
|||||||
SET "OTA_OFFSET=0x260000"
|
SET "OTA_OFFSET=0x260000"
|
||||||
SET "SPIFFS_OFFSET=0x300000"
|
SET "SPIFFS_OFFSET=0x300000"
|
||||||
|
|
||||||
@REM Offsets for MUI 8mb.
|
@REM Offsets for BigDB 8mb.
|
||||||
IF %TFT8% EQU 1 IF %TFT_BUILD% EQU 1 (
|
IF %BIGDB8% EQU 1 (
|
||||||
SET "OTA_OFFSET=0x340000"
|
SET "OTA_OFFSET=0x340000"
|
||||||
SET "SPIFFS_OFFSET=0x670000"
|
SET "SPIFFS_OFFSET=0x670000"
|
||||||
)
|
)
|
||||||
|
|
||||||
@REM Offsets for MUI 16mb.
|
@REM Offsets for BigDB 16mb.
|
||||||
IF %TFT16% EQU 1 IF %TFT_BUILD% EQU 1 (
|
IF %BIGDB16% EQU 1 (
|
||||||
SET "OTA_OFFSET=0x650000"
|
SET "OTA_OFFSET=0x650000"
|
||||||
SET "SPIFFS_OFFSET=0xc90000"
|
SET "SPIFFS_OFFSET=0xc90000"
|
||||||
)
|
)
|
||||||
|
|||||||
+66
-24
@@ -2,9 +2,48 @@
|
|||||||
|
|
||||||
PYTHON=${PYTHON:-$(which python3 python | head -n 1)}
|
PYTHON=${PYTHON:-$(which python3 python | head -n 1)}
|
||||||
WEB_APP=false
|
WEB_APP=false
|
||||||
TFT8=false
|
|
||||||
TFT16=false
|
|
||||||
TFT_BUILD=false
|
TFT_BUILD=false
|
||||||
|
MCU=""
|
||||||
|
|
||||||
|
# Variant groups
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
BIGDB_16MB=(
|
||||||
|
"t-deck"
|
||||||
|
"mesh-tab"
|
||||||
|
"t-energy-s3"
|
||||||
|
"dreamcatcher"
|
||||||
|
"ESP32-S3-Pico"
|
||||||
|
"m5stack-cores3"
|
||||||
|
"station-g2"
|
||||||
|
"t-eth-elite"
|
||||||
|
"t-watch-s3"
|
||||||
|
)
|
||||||
|
S3_VARIANTS=(
|
||||||
|
"s3"
|
||||||
|
"-v3"
|
||||||
|
"t-deck"
|
||||||
|
"wireless-paper"
|
||||||
|
"wireless-tracker"
|
||||||
|
"station-g2"
|
||||||
|
"unphone"
|
||||||
|
)
|
||||||
|
|
||||||
# Determine the correct esptool command to use
|
# Determine the correct esptool command to use
|
||||||
if "$PYTHON" -m esptool version >/dev/null 2>&1; then
|
if "$PYTHON" -m esptool version >/dev/null 2>&1; then
|
||||||
@@ -42,8 +81,8 @@ while [ $# -gt 0 ]; do
|
|||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
-p)
|
-p)
|
||||||
ESPTOOL_PORT="$2"
|
ESPTOOL_CMD="$ESPTOOL_CMD --port $2"
|
||||||
shift # Shift past the option argument
|
shift
|
||||||
;;
|
;;
|
||||||
-P)
|
-P)
|
||||||
PYTHON="$2"
|
PYTHON="$2"
|
||||||
@@ -78,21 +117,13 @@ if [[ $FILENAME != firmware-* ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if FILENAME contains "-tft-" and set target partitionScheme accordingly.
|
# Check if FILENAME contains "-tft-" and prevent web/mui comingling.
|
||||||
if [[ ${FILENAME//-tft-/} != "$FILENAME" ]]; then
|
if [[ ${FILENAME//-tft-/} != "$FILENAME" ]]; then
|
||||||
TFT_BUILD=true
|
TFT_BUILD=true
|
||||||
if [[ $WEB_APP == true ]] && [[ $TFT_BUILD == true ]]; then
|
if [[ $WEB_APP == true ]] && [[ $TFT_BUILD == true ]]; then
|
||||||
echo "Cannot enable WebUI (--web) and MUI."
|
echo "Cannot enable WebUI (--web) and MUI."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $FILENAME == *"picomputer-s3"* || $FILENAME == *"unphone"* || $FILENAME == *"seeed-sensecap-indicator"* ]]; then
|
|
||||||
TFT8=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $FILENAME == *"t-deck"* ]]; then
|
|
||||||
TFT16=true
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Extract BASENAME from %FILENAME% for later use.
|
# Extract BASENAME from %FILENAME% for later use.
|
||||||
@@ -105,20 +136,31 @@ if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
|
|||||||
# Default OTA Offset
|
# Default OTA Offset
|
||||||
OTA_OFFSET=0x260000
|
OTA_OFFSET=0x260000
|
||||||
|
|
||||||
# littlefs* offset for MUI 8mb and OTA OFFSET.
|
# littlefs* offset for BigDB 8mb and OTA OFFSET.
|
||||||
if [ "$TFT8" = true ] && [ "$TFT_BUILD" = true ]; then
|
for variant in "${BIGDB_8MB[@]}"; do
|
||||||
OFFSET=0x670000
|
if [ -n "${FILENAME##*"$variant"*}" ]; then
|
||||||
OTA_OFFSET=0x340000
|
OFFSET=0x670000
|
||||||
fi
|
OTA_OFFSET=0x340000
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# littlefs* offset for MUI 16mb and OTA OFFSET.
|
# littlefs* offset for BigDB 16mb and OTA OFFSET.
|
||||||
if [ "$TFT16" = true ] && [ "$TFT_BUILD" = true ]; then
|
for variant in "${BIGDB_16MB[@]}"; do
|
||||||
OFFSET=0xc90000
|
if [ -n "${FILENAME##*"$variant"*}" ]; then
|
||||||
OTA_OFFSET=0x650000
|
OFFSET=0xc90000
|
||||||
fi
|
OTA_OFFSET=0x650000
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# Account for S3 board's different OTA partition
|
# Account for S3 board's different OTA partition
|
||||||
if [ -n "${FILENAME##*"s3"*}" ] && [ -n "${FILENAME##*"-v3"*}" ] && [ -n "${FILENAME##*"t-deck"*}" ] && [ -n "${FILENAME##*"wireless-paper"*}" ] && [ -n "${FILENAME##*"wireless-tracker"*}" ] && [ -n "${FILENAME##*"station-g2"*}" ] && [ -n "${FILENAME##*"unphone"*}" ]; then
|
# FIXME: Use PlatformIO info to determine MCU type, this is unmaintainable
|
||||||
|
for variant in "${S3_VARIANTS[@]}"; do
|
||||||
|
if [ -n "${FILENAME##*"$variant"*}" ]; then
|
||||||
|
MCU="esp32s3"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$MCU" != "esp32s3" ]; then
|
||||||
if [ -n "${FILENAME##*"esp32c3"*}" ]; then
|
if [ -n "${FILENAME##*"esp32c3"*}" ]; then
|
||||||
OTAFILE=bleota.bin
|
OTAFILE=bleota.bin
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ ECHO.
|
|||||||
ECHO Usage: %SCRIPT_NAME% -f filename [-p PORT] [-P python]
|
ECHO Usage: %SCRIPT_NAME% -f filename [-p PORT] [-P python]
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Options:
|
ECHO Options:
|
||||||
ECHO -f filename The .bin file to flash. Custom to your device type and region. (required)
|
ECHO -f filename The update .bin file to flash. Custom to your device type and region. (required)
|
||||||
ECHO The file must be located in this current directory.
|
ECHO The file must be located in this current directory.
|
||||||
ECHO -p PORT Set the environment variable for ESPTOOL_PORT.
|
ECHO -p PORT Set the environment variable for ESPTOOL_PORT.
|
||||||
ECHO If not set, ESPTOOL iterates all ports (Dangerous).
|
ECHO If not set, ESPTOOL iterates all ports (Dangerous).
|
||||||
@@ -28,7 +28,7 @@ ECHO Example: %SCRIPT_NAME% -f firmware-t-deck-tft-2.6.0.0b106d4-update.bin -p C
|
|||||||
GOTO eof
|
GOTO eof
|
||||||
|
|
||||||
:version
|
:version
|
||||||
ECHO %SCRIPT_NAME% [Version 2.6.0]
|
ECHO %SCRIPT_NAME% [Version 2.6.1]
|
||||||
ECHO Meshtastic
|
ECHO Meshtastic
|
||||||
GOTO eof
|
GOTO eof
|
||||||
|
|
||||||
@@ -53,6 +53,7 @@ IF "__!FILENAME!__"=="____" (
|
|||||||
CALL :LOG_MESSAGE DEBUG "Missing -f filename input."
|
CALL :LOG_MESSAGE DEBUG "Missing -f filename input."
|
||||||
GOTO help
|
GOTO help
|
||||||
) ELSE (
|
) ELSE (
|
||||||
|
CALL :LOG_MESSAGE DEBUG "Filename: !FILENAME!"
|
||||||
IF NOT "__!FILENAME: =!__"=="__!FILENAME!__" (
|
IF NOT "__!FILENAME: =!__"=="__!FILENAME!__" (
|
||||||
CALL :LOG_MESSAGE ERROR "Filename containing spaces are not supported."
|
CALL :LOG_MESSAGE ERROR "Filename containing spaces are not supported."
|
||||||
GOTO help
|
GOTO help
|
||||||
@@ -62,7 +63,6 @@ IF "__!FILENAME!__"=="____" (
|
|||||||
SET "FILENAME=!FILENAME:./=!"
|
SET "FILENAME=!FILENAME:./=!"
|
||||||
)
|
)
|
||||||
|
|
||||||
CALL :LOG_MESSAGE DEBUG "Filename: !FILENAME!"
|
|
||||||
CALL :LOG_MESSAGE DEBUG "Checking if !FILENAME! exists..."
|
CALL :LOG_MESSAGE DEBUG "Checking if !FILENAME! exists..."
|
||||||
IF NOT EXIST !FILENAME! (
|
IF NOT EXIST !FILENAME! (
|
||||||
CALL :LOG_MESSAGE ERROR "File does not exist: !FILENAME!. Terminating."
|
CALL :LOG_MESSAGE ERROR "File does not exist: !FILENAME!. Terminating."
|
||||||
@@ -71,7 +71,7 @@ IF NOT EXIST !FILENAME! (
|
|||||||
|
|
||||||
IF "!FILENAME:update=!"=="!FILENAME!" (
|
IF "!FILENAME:update=!"=="!FILENAME!" (
|
||||||
CALL :LOG_MESSAGE DEBUG "We are NOT working with a *update* file. !FILENAME!"
|
CALL :LOG_MESSAGE DEBUG "We are NOT working with a *update* file. !FILENAME!"
|
||||||
CALL :LOG_MESSAGE INFO "Use script device-install.bat to flash update !FILENAME!."
|
CALL :LOG_MESSAGE INFO "Use script device-install.bat to flash !FILENAME!."
|
||||||
GOTO eof
|
GOTO eof
|
||||||
) ELSE (
|
) ELSE (
|
||||||
CALL :LOG_MESSAGE DEBUG "We are working with a *update* file. !FILENAME!"
|
CALL :LOG_MESSAGE DEBUG "We are working with a *update* file. !FILENAME!"
|
||||||
@@ -95,7 +95,7 @@ IF NOT "__%PYTHON%__"=="____" (
|
|||||||
|
|
||||||
CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..."
|
CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..."
|
||||||
!ESPTOOL_CMD! >nul 2>&1
|
!ESPTOOL_CMD! >nul 2>&1
|
||||||
IF %ERRORLEVEL% GTR 2 (
|
IF %ERRORLEVEL% GEQ 2 (
|
||||||
@REM esptool exits with code 1 if help is displayed.
|
@REM esptool exits with code 1 if help is displayed.
|
||||||
CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!"
|
CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!"
|
||||||
EXIT /B 1
|
EXIT /B 1
|
||||||
@@ -110,6 +110,7 @@ CALL :LOG_MESSAGE DEBUG "Using esptool command: !ESPTOOL_CMD!"
|
|||||||
IF "__!ESPTOOL_PORT!__" == "____" (
|
IF "__!ESPTOOL_PORT!__" == "____" (
|
||||||
CALL :LOG_MESSAGE WARN "Using esptool port: UNSET."
|
CALL :LOG_MESSAGE WARN "Using esptool port: UNSET."
|
||||||
) ELSE (
|
) ELSE (
|
||||||
|
SET "ESPTOOL_CMD=!ESPTOOL_CMD! --port !ESPTOOL_PORT!"
|
||||||
CALL :LOG_MESSAGE INFO "Using esptool port: !ESPTOOL_PORT!."
|
CALL :LOG_MESSAGE INFO "Using esptool port: !ESPTOOL_PORT!."
|
||||||
)
|
)
|
||||||
CALL :LOG_MESSAGE INFO "Using esptool baud: !ESPTOOL_BAUD!."
|
CALL :LOG_MESSAGE INFO "Using esptool baud: !ESPTOOL_BAUD!."
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ while getopts ":hp:P:f:" opt; do
|
|||||||
show_help
|
show_help
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
p) export ESPTOOL_PORT=${OPTARG}
|
p) ESPTOOL_CMD="$ESPTOOL_CMD --port ${OPTARG}"
|
||||||
;;
|
;;
|
||||||
P) PYTHON=${OPTARG}
|
P) PYTHON=${OPTARG}
|
||||||
;;
|
;;
|
||||||
f) FILENAME=${OPTARG}
|
f) FILENAME=${OPTARG}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ if platform.name == "espressif32":
|
|||||||
|
|
||||||
if platform.name == "nordicnrf52":
|
if platform.name == "nordicnrf52":
|
||||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex",
|
env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex",
|
||||||
env.VerboseAction(f"{sys.executable} ./bin/uf2conv.py $BUILD_DIR/firmware.hex -c -f 0xADA52840 -o $BUILD_DIR/firmware.uf2",
|
env.VerboseAction(f"\"{sys.executable}\" ./bin/uf2conv.py $BUILD_DIR/firmware.hex -c -f 0xADA52840 -o $BUILD_DIR/firmware.uf2",
|
||||||
"Generating UF2 file"))
|
"Generating UF2 file"))
|
||||||
|
|
||||||
Import("projenv")
|
Import("projenv")
|
||||||
|
|||||||
Vendored
+1
@@ -17,6 +17,7 @@ Build-Depends: debhelper-compat (= 13),
|
|||||||
libbluetooth-dev,
|
libbluetooth-dev,
|
||||||
libusb-1.0-0-dev,
|
libusb-1.0-0-dev,
|
||||||
libi2c-dev,
|
libi2c-dev,
|
||||||
|
libuv1-dev,
|
||||||
openssl,
|
openssl,
|
||||||
libssl-dev,
|
libssl-dev,
|
||||||
libulfius-dev,
|
libulfius-dev,
|
||||||
|
|||||||
Executable
+22
@@ -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(bluez)
|
||||||
BuildRequires: pkgconfig(libusb-1.0)
|
BuildRequires: pkgconfig(libusb-1.0)
|
||||||
BuildRequires: libi2c-devel
|
BuildRequires: libi2c-devel
|
||||||
|
BuildRequires: pkgconfig(libuv)
|
||||||
# Web components:
|
# Web components:
|
||||||
BuildRequires: pkgconfig(openssl)
|
BuildRequires: pkgconfig(openssl)
|
||||||
BuildRequires: pkgconfig(liborcania)
|
BuildRequires: pkgconfig(liborcania)
|
||||||
|
|||||||
+1
-1
@@ -94,7 +94,7 @@ lib_deps =
|
|||||||
|
|
||||||
[device-ui_base]
|
[device-ui_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
https://github.com/meshtastic/device-ui.git#74e739ed4532ca10393df9fc89ae5a22f0bab2b1
|
https://github.com/meshtastic/device-ui.git#7a6ffba3c86901b0e3234b6c056aa803b4cd8854
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
; (not included in native / portduino)
|
; (not included in native / portduino)
|
||||||
|
|||||||
+1
-1
Submodule protobufs updated: 14ec205865...b4044f8f9f
+2
-4
@@ -41,10 +41,8 @@ class AudioThread : public concurrency::OSThread
|
|||||||
delete i2sRtttl;
|
delete i2sRtttl;
|
||||||
i2sRtttl = nullptr;
|
i2sRtttl = nullptr;
|
||||||
}
|
}
|
||||||
if (rtttlFile != nullptr) {
|
delete rtttlFile;
|
||||||
delete rtttlFile;
|
rtttlFile = nullptr;
|
||||||
rtttlFile = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
setCPUFast(false);
|
setCPUFast(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
|
|||||||
#ifdef USERPREFS_BUTTON_PIN
|
#ifdef USERPREFS_BUTTON_PIN
|
||||||
int pin = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN; // Resolved button pin
|
int pin = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN; // Resolved button pin
|
||||||
#endif
|
#endif
|
||||||
#if defined(HELTEC_CAPSULE_SENSOR_V3)
|
#if defined(HELTEC_CAPSULE_SENSOR_V3) || defined(HELTEC_SENSOR_HUB)
|
||||||
this->userButton = OneButton(pin, false, false);
|
this->userButton = OneButton(pin, false, false);
|
||||||
#elif defined(BUTTON_ACTIVE_LOW)
|
#elif defined(BUTTON_ACTIVE_LOW)
|
||||||
this->userButton = OneButton(pin, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP);
|
this->userButton = OneButton(pin, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP);
|
||||||
|
|||||||
+2
-58
@@ -29,30 +29,6 @@ SPIClass SPI1(HSPI);
|
|||||||
|
|
||||||
#endif // HAS_SDCARD
|
#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.
|
* @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)
|
bool copyFile(const char *from, const char *to)
|
||||||
{
|
{
|
||||||
#ifdef ARCH_STM32WL
|
#ifdef FSCom
|
||||||
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)
|
|
||||||
// take SPI Lock
|
// take SPI Lock
|
||||||
concurrency::LockGuard g(spiLock);
|
concurrency::LockGuard g(spiLock);
|
||||||
unsigned char cbuffer[16];
|
unsigned char cbuffer[16];
|
||||||
@@ -127,13 +77,7 @@ bool copyFile(const char *from, const char *to)
|
|||||||
*/
|
*/
|
||||||
bool renameFile(const char *pathFrom, const char *pathTo)
|
bool renameFile(const char *pathFrom, const char *pathTo)
|
||||||
{
|
{
|
||||||
#ifdef ARCH_STM32WL
|
#ifdef FSCom
|
||||||
if (copyFile(pathFrom, pathTo) && (OSFS::deleteFile(pathFrom) == OSFS::result::NO_ERROR)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#elif defined(FSCom)
|
|
||||||
|
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
// take SPI Lock
|
// take SPI Lock
|
||||||
|
|||||||
+5
-7
@@ -15,13 +15,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ARCH_STM32WL)
|
#if defined(ARCH_STM32WL)
|
||||||
// STM32WL series 2 Kbytes (8 rows of 256 bytes)
|
// STM32WL
|
||||||
#include <EEPROM.h>
|
#include "LittleFS.h"
|
||||||
#include <OSFS.h>
|
#define FSCom InternalFS
|
||||||
|
#define FSBegin() FSCom.begin()
|
||||||
// Useful consts
|
using namespace STM32_LittleFS_Namespace;
|
||||||
const OSFS::result noerr = OSFS::result::NO_ERROR;
|
|
||||||
const OSFS::result notfound = OSFS::result::FILE_NOT_FOUND;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ARCH_RP2040)
|
#if defined(ARCH_RP2040)
|
||||||
|
|||||||
+2
-2
@@ -391,7 +391,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
virtual bool isVbusIn() override
|
virtual bool isVbusIn() override
|
||||||
{
|
{
|
||||||
#ifdef EXT_PWR_DETECT
|
#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 external powered that pin will be pulled down
|
||||||
if (digitalRead(EXT_PWR_DETECT) == LOW) {
|
if (digitalRead(EXT_PWR_DETECT) == LOW) {
|
||||||
return true;
|
return true;
|
||||||
@@ -541,7 +541,7 @@ Power::Power() : OSThread("Power")
|
|||||||
bool Power::analogInit()
|
bool Power::analogInit()
|
||||||
{
|
{
|
||||||
#ifdef EXT_PWR_DETECT
|
#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);
|
pinMode(EXT_PWR_DETECT, INPUT_PULLUP);
|
||||||
#else
|
#else
|
||||||
pinMode(EXT_PWR_DETECT, INPUT);
|
pinMode(EXT_PWR_DETECT, INPUT);
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define MLX90614_ADDR_DEF 0x5A
|
#define MLX90614_ADDR_DEF 0x5A
|
||||||
#define CGRADSENS_ADDR 0x66
|
#define CGRADSENS_ADDR 0x66
|
||||||
#define LTR390UV_ADDR 0x53
|
#define LTR390UV_ADDR 0x53
|
||||||
|
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 // same adress as TCA8418
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// ACCELEROMETER
|
// ACCELEROMETER
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
|
|||||||
|
|
||||||
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
||||||
{
|
{
|
||||||
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004, MPR121KB};
|
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004, MPR121KB, TCA8418KB};
|
||||||
return firstOfOrNONE(5, types);
|
return firstOfOrNONE(6, types);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
|
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
|
||||||
@@ -74,4 +74,4 @@ bool ScanI2C::DeviceAddress::operator<(const ScanI2C::DeviceAddress &other) cons
|
|||||||
|| (port != NO_I2C && other.port != NO_I2C && (address < other.address));
|
|| (port != NO_I2C && other.port != NO_I2C && (address < other.address));
|
||||||
}
|
}
|
||||||
|
|
||||||
ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {}
|
ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class ScanI2C
|
|||||||
TDECKKB,
|
TDECKKB,
|
||||||
BBQ10KB,
|
BBQ10KB,
|
||||||
RAK14004,
|
RAK14004,
|
||||||
PMU_AXP192_AXP2101,
|
PMU_AXP192_AXP2101, // has the same address as the TCA8418KB
|
||||||
BME_680,
|
BME_680,
|
||||||
BME_280,
|
BME_280,
|
||||||
BMP_280,
|
BMP_280,
|
||||||
@@ -69,6 +69,7 @@ class ScanI2C
|
|||||||
DFROBOT_RAIN,
|
DFROBOT_RAIN,
|
||||||
DPS310,
|
DPS310,
|
||||||
LTR390UV,
|
LTR390UV,
|
||||||
|
TCA8418KB,
|
||||||
} DeviceType;
|
} DeviceType;
|
||||||
|
|
||||||
// typedef uint8_t DeviceAddress;
|
// typedef uint8_t DeviceAddress;
|
||||||
@@ -132,4 +133,4 @@ class ScanI2C
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool shouldSuppressScreen = false;
|
bool shouldSuppressScreen = false;
|
||||||
};
|
};
|
||||||
@@ -10,11 +10,6 @@
|
|||||||
#include "meshUtils.h" // vformat
|
#include "meshUtils.h" // vformat
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp
|
|
||||||
#ifndef XPOWERS_AXP192_AXP2101_ADDRESS
|
|
||||||
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool in_array(uint8_t *array, int size, uint8_t lookfor)
|
bool in_array(uint8_t *array, int size, uint8_t lookfor)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -211,6 +206,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case XPOWERS_AXP192_AXP2101_ADDRESS:
|
||||||
|
// Do we have the TCA8418 instead?
|
||||||
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x02), 1);
|
||||||
|
if ((registerValue & 0b11100000) == 0) {
|
||||||
|
logFoundDevice("TCA8418", (uint8_t)addr.address);
|
||||||
|
type = TCA8418KB;
|
||||||
|
} else {
|
||||||
|
logFoundDevice("AXP192/AXP2101", (uint8_t)addr.address);
|
||||||
|
type = PMU_AXP192_AXP2101;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard", (uint8_t)addr.address);
|
||||||
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10", (uint8_t)addr.address);
|
||||||
|
|
||||||
@@ -218,9 +225,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
#ifdef HAS_NCP5623
|
#ifdef HAS_NCP5623
|
||||||
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623", (uint8_t)addr.address);
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_PMU
|
|
||||||
SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "AXP192/AXP2101", (uint8_t)addr.address)
|
|
||||||
#endif
|
|
||||||
case BME_ADDR:
|
case BME_ADDR:
|
||||||
case BME_ADDR_ALTERNATE:
|
case BME_ADDR_ALTERNATE:
|
||||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID
|
||||||
@@ -536,4 +541,4 @@ void ScanI2CTwoWire::logFoundDevice(const char *device, uint8_t address)
|
|||||||
{
|
{
|
||||||
LOG_INFO("%s found at address 0x%x", device, address);
|
LOG_INFO("%s found at address 0x%x", device, address);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+2
-2
@@ -1200,12 +1200,12 @@ GnssModel_t GPS::probe(int serialSpeed)
|
|||||||
PROBE_SIMPLE("LC86", "$PQTMVERNO*58", "$PQTMVERNO,LC86", GNSS_MODEL_AG3352, 500);
|
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);
|
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");
|
_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);
|
delay(20);
|
||||||
std::vector<ChipInfo> mtk = {{"L76B", "Quectel-L76B", GNSS_MODEL_MTK_L76B},
|
std::vector<ChipInfo> mtk = {{"L76B", "Quectel-L76B", GNSS_MODEL_MTK_L76B},
|
||||||
{"PA1616S", "1616S", GNSS_MODEL_MTK_PA1616S},
|
{"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);
|
PROBE_FAMILY("MTK Family", "$PMTK605*31", mtk, 500);
|
||||||
|
|
||||||
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
|
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ void tftSetup(void)
|
|||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
tftSleepObserver.observe(¬ifyLightSleep);
|
tftSleepObserver.observe(¬ifyLightSleep);
|
||||||
endSleepObserver.observe(¬ifyLightSleepEnd);
|
endSleepObserver.observe(¬ifyLightSleepEnd);
|
||||||
xTaskCreatePinnedToCore(tft_task_handler, "tft", 8192, NULL, 1, NULL, 0);
|
xTaskCreatePinnedToCore(tft_task_handler, "tft", 10240, NULL, 1, NULL, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,561 @@
|
|||||||
|
// Based on the MPR121 Keyboard and Adafruit TCA8418 library
|
||||||
|
|
||||||
|
#include "TCA8418Keyboard.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// REGISTERS
|
||||||
|
// #define _TCA8418_REG_RESERVED 0x00
|
||||||
|
#define _TCA8418_REG_CFG 0x01 // Configuration register
|
||||||
|
#define _TCA8418_REG_INT_STAT 0x02 // Interrupt status
|
||||||
|
#define _TCA8418_REG_KEY_LCK_EC 0x03 // Key lock and event counter
|
||||||
|
#define _TCA8418_REG_KEY_EVENT_A 0x04 // Key event register A
|
||||||
|
#define _TCA8418_REG_KEY_EVENT_B 0x05 // Key event register B
|
||||||
|
#define _TCA8418_REG_KEY_EVENT_C 0x06 // Key event register C
|
||||||
|
#define _TCA8418_REG_KEY_EVENT_D 0x07 // Key event register D
|
||||||
|
#define _TCA8418_REG_KEY_EVENT_E 0x08 // Key event register E
|
||||||
|
#define _TCA8418_REG_KEY_EVENT_F 0x09 // Key event register F
|
||||||
|
#define _TCA8418_REG_KEY_EVENT_G 0x0A // Key event register G
|
||||||
|
#define _TCA8418_REG_KEY_EVENT_H 0x0B // Key event register H
|
||||||
|
#define _TCA8418_REG_KEY_EVENT_I 0x0C // Key event register I
|
||||||
|
#define _TCA8418_REG_KEY_EVENT_J 0x0D // Key event register J
|
||||||
|
#define _TCA8418_REG_KP_LCK_TIMER 0x0E // Keypad lock1 to lock2 timer
|
||||||
|
#define _TCA8418_REG_UNLOCK_1 0x0F // Unlock register 1
|
||||||
|
#define _TCA8418_REG_UNLOCK_2 0x10 // Unlock register 2
|
||||||
|
#define _TCA8418_REG_GPIO_INT_STAT_1 0x11 // GPIO interrupt status 1
|
||||||
|
#define _TCA8418_REG_GPIO_INT_STAT_2 0x12 // GPIO interrupt status 2
|
||||||
|
#define _TCA8418_REG_GPIO_INT_STAT_3 0x13 // GPIO interrupt status 3
|
||||||
|
#define _TCA8418_REG_GPIO_DAT_STAT_1 0x14 // GPIO data status 1
|
||||||
|
#define _TCA8418_REG_GPIO_DAT_STAT_2 0x15 // GPIO data status 2
|
||||||
|
#define _TCA8418_REG_GPIO_DAT_STAT_3 0x16 // GPIO data status 3
|
||||||
|
#define _TCA8418_REG_GPIO_DAT_OUT_1 0x17 // GPIO data out 1
|
||||||
|
#define _TCA8418_REG_GPIO_DAT_OUT_2 0x18 // GPIO data out 2
|
||||||
|
#define _TCA8418_REG_GPIO_DAT_OUT_3 0x19 // GPIO data out 3
|
||||||
|
#define _TCA8418_REG_GPIO_INT_EN_1 0x1A // GPIO interrupt enable 1
|
||||||
|
#define _TCA8418_REG_GPIO_INT_EN_2 0x1B // GPIO interrupt enable 2
|
||||||
|
#define _TCA8418_REG_GPIO_INT_EN_3 0x1C // GPIO interrupt enable 3
|
||||||
|
#define _TCA8418_REG_KP_GPIO_1 0x1D // Keypad/GPIO select 1
|
||||||
|
#define _TCA8418_REG_KP_GPIO_2 0x1E // Keypad/GPIO select 2
|
||||||
|
#define _TCA8418_REG_KP_GPIO_3 0x1F // Keypad/GPIO select 3
|
||||||
|
#define _TCA8418_REG_GPI_EM_1 0x20 // GPI event mode 1
|
||||||
|
#define _TCA8418_REG_GPI_EM_2 0x21 // GPI event mode 2
|
||||||
|
#define _TCA8418_REG_GPI_EM_3 0x22 // GPI event mode 3
|
||||||
|
#define _TCA8418_REG_GPIO_DIR_1 0x23 // GPIO data direction 1
|
||||||
|
#define _TCA8418_REG_GPIO_DIR_2 0x24 // GPIO data direction 2
|
||||||
|
#define _TCA8418_REG_GPIO_DIR_3 0x25 // GPIO data direction 3
|
||||||
|
#define _TCA8418_REG_GPIO_INT_LVL_1 0x26 // GPIO edge/level detect 1
|
||||||
|
#define _TCA8418_REG_GPIO_INT_LVL_2 0x27 // GPIO edge/level detect 2
|
||||||
|
#define _TCA8418_REG_GPIO_INT_LVL_3 0x28 // GPIO edge/level detect 3
|
||||||
|
#define _TCA8418_REG_DEBOUNCE_DIS_1 0x29 // Debounce disable 1
|
||||||
|
#define _TCA8418_REG_DEBOUNCE_DIS_2 0x2A // Debounce disable 2
|
||||||
|
#define _TCA8418_REG_DEBOUNCE_DIS_3 0x2B // Debounce disable 3
|
||||||
|
#define _TCA8418_REG_GPIO_PULL_1 0x2C // GPIO pull-up disable 1
|
||||||
|
#define _TCA8418_REG_GPIO_PULL_2 0x2D // GPIO pull-up disable 2
|
||||||
|
#define _TCA8418_REG_GPIO_PULL_3 0x2E // GPIO pull-up disable 3
|
||||||
|
// #define _TCA8418_REG_RESERVED 0x2F
|
||||||
|
|
||||||
|
// FIELDS CONFIG REGISTER 1
|
||||||
|
#define _TCA8418_REG_CFG_AI 0x80 // Auto-increment for read/write
|
||||||
|
#define _TCA8418_REG_CFG_GPI_E_CGF 0x40 // Event mode config
|
||||||
|
#define _TCA8418_REG_CFG_OVR_FLOW_M 0x20 // Overflow mode enable
|
||||||
|
#define _TCA8418_REG_CFG_INT_CFG 0x10 // Interrupt config
|
||||||
|
#define _TCA8418_REG_CFG_OVR_FLOW_IEN 0x08 // Overflow interrupt enable
|
||||||
|
#define _TCA8418_REG_CFG_K_LCK_IEN 0x04 // Keypad lock interrupt enable
|
||||||
|
#define _TCA8418_REG_CFG_GPI_IEN 0x02 // GPI interrupt enable
|
||||||
|
#define _TCA8418_REG_CFG_KE_IEN 0x01 // Key events interrupt enable
|
||||||
|
|
||||||
|
// FIELDS INT_STAT REGISTER 2
|
||||||
|
#define _TCA8418_REG_STAT_CAD_INT 0x10 // Ctrl-alt-del seq status
|
||||||
|
#define _TCA8418_REG_STAT_OVR_FLOW_INT 0x08 // Overflow interrupt status
|
||||||
|
#define _TCA8418_REG_STAT_K_LCK_INT 0x04 // Key lock interrupt status
|
||||||
|
#define _TCA8418_REG_STAT_GPI_INT 0x02 // GPI interrupt status
|
||||||
|
#define _TCA8418_REG_STAT_K_INT 0x01 // Key events interrupt status
|
||||||
|
|
||||||
|
// FIELDS KEY_LCK_EC REGISTER 3
|
||||||
|
#define _TCA8418_REG_LCK_EC_K_LCK_EN 0x40 // Key lock enable
|
||||||
|
#define _TCA8418_REG_LCK_EC_LCK_2 0x20 // Keypad lock status 2
|
||||||
|
#define _TCA8418_REG_LCK_EC_LCK_1 0x10 // Keypad lock status 1
|
||||||
|
#define _TCA8418_REG_LCK_EC_KLEC_3 0x08 // Key event count bit 3
|
||||||
|
#define _TCA8418_REG_LCK_EC_KLEC_2 0x04 // Key event count bit 2
|
||||||
|
#define _TCA8418_REG_LCK_EC_KLEC_1 0x02 // Key event count bit 1
|
||||||
|
#define _TCA8418_REG_LCK_EC_KLEC_0 0x01 // Key event count bit 0
|
||||||
|
|
||||||
|
// Pin IDs for matrix rows/columns
|
||||||
|
enum {
|
||||||
|
_TCA8418_ROW0, // Pin ID for row 0
|
||||||
|
_TCA8418_ROW1, // Pin ID for row 1
|
||||||
|
_TCA8418_ROW2, // Pin ID for row 2
|
||||||
|
_TCA8418_ROW3, // Pin ID for row 3
|
||||||
|
_TCA8418_ROW4, // Pin ID for row 4
|
||||||
|
_TCA8418_ROW5, // Pin ID for row 5
|
||||||
|
_TCA8418_ROW6, // Pin ID for row 6
|
||||||
|
_TCA8418_ROW7, // Pin ID for row 7
|
||||||
|
_TCA8418_COL0, // Pin ID for column 0
|
||||||
|
_TCA8418_COL1, // Pin ID for column 1
|
||||||
|
_TCA8418_COL2, // Pin ID for column 2
|
||||||
|
_TCA8418_COL3, // Pin ID for column 3
|
||||||
|
_TCA8418_COL4, // Pin ID for column 4
|
||||||
|
_TCA8418_COL5, // Pin ID for column 5
|
||||||
|
_TCA8418_COL6, // Pin ID for column 6
|
||||||
|
_TCA8418_COL7, // Pin ID for column 7
|
||||||
|
_TCA8418_COL8, // Pin ID for column 8
|
||||||
|
_TCA8418_COL9 // Pin ID for column 9
|
||||||
|
};
|
||||||
|
|
||||||
|
#define _TCA8418_COLS 3
|
||||||
|
#define _TCA8418_ROWS 4
|
||||||
|
#define _TCA8418_NUM_KEYS 12
|
||||||
|
|
||||||
|
uint8_t TCA8418TapMod[_TCA8418_NUM_KEYS] = {13, 7, 7, 7, 7, 7,
|
||||||
|
9, 7, 9, 2, 2, 2}; // Num chars per key, Modulus for rotating through characters
|
||||||
|
|
||||||
|
unsigned char TCA8418TapMap[_TCA8418_NUM_KEYS][13] = {
|
||||||
|
{'1', '.', ',', '?', '!', ':', ';', '-', '_', '\\', '/', '(', ')'}, // 1
|
||||||
|
{'2', 'a', 'b', 'c', 'A', 'B', 'C'}, // 2
|
||||||
|
{'3', 'd', 'e', 'f', 'D', 'E', 'F'}, // 3
|
||||||
|
{'4', 'g', 'h', 'i', 'G', 'H', 'I'}, // 4
|
||||||
|
{'5', 'j', 'k', 'l', 'J', 'K', 'L'}, // 5
|
||||||
|
{'6', 'm', 'n', 'o', 'M', 'N', 'O'}, // 6
|
||||||
|
{'7', 'p', 'q', 'r', 's', 'P', 'Q', 'R', 'S'}, // 7
|
||||||
|
{'8', 't', 'u', 'v', 'T', 'U', 'V'}, // 8
|
||||||
|
{'9', 'w', 'x', 'y', 'z', 'W', 'X', 'Y', 'Z'}, // 9
|
||||||
|
{'*', '+'}, // *
|
||||||
|
{'0', ' '}, // 0
|
||||||
|
{'#', '@'}, // #
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = {
|
||||||
|
_TCA8418_ESC, // 1
|
||||||
|
_TCA8418_UP, // 2
|
||||||
|
_TCA8418_NONE, // 3
|
||||||
|
_TCA8418_LEFT, // 4
|
||||||
|
_TCA8418_NONE, // 5
|
||||||
|
_TCA8418_RIGHT, // 6
|
||||||
|
_TCA8418_NONE, // 7
|
||||||
|
_TCA8418_DOWN, // 8
|
||||||
|
_TCA8418_NONE, // 9
|
||||||
|
_TCA8418_BSP, // *
|
||||||
|
_TCA8418_NONE, // 0
|
||||||
|
_TCA8418_NONE, // #
|
||||||
|
};
|
||||||
|
|
||||||
|
#define _TCA8418_LONG_PRESS_THRESHOLD 2000
|
||||||
|
#define _TCA8418_MULTI_TAP_THRESHOLD 750
|
||||||
|
|
||||||
|
TCA8418Keyboard::TCA8418Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr)
|
||||||
|
{
|
||||||
|
state = Init;
|
||||||
|
last_key = -1;
|
||||||
|
next_key = -1;
|
||||||
|
should_backspace = false;
|
||||||
|
last_tap = 0L;
|
||||||
|
char_idx = 0;
|
||||||
|
tap_interval = 0;
|
||||||
|
backlight_on = true;
|
||||||
|
queue = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::begin(uint8_t addr, TwoWire *wire)
|
||||||
|
{
|
||||||
|
m_addr = addr;
|
||||||
|
m_wire = wire;
|
||||||
|
|
||||||
|
m_wire->begin();
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
|
||||||
|
{
|
||||||
|
m_addr = addr;
|
||||||
|
m_wire = nullptr;
|
||||||
|
writeCallback = w;
|
||||||
|
readCallback = r;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::reset()
|
||||||
|
{
|
||||||
|
LOG_DEBUG("TCA8418 Reset");
|
||||||
|
// GPIO
|
||||||
|
// set default all GIO pins to INPUT
|
||||||
|
writeRegister(_TCA8418_REG_GPIO_DIR_1, 0x00);
|
||||||
|
writeRegister(_TCA8418_REG_GPIO_DIR_2, 0x00);
|
||||||
|
// Set COL9 as GPIO output
|
||||||
|
writeRegister(_TCA8418_REG_GPIO_DIR_3, 0x02);
|
||||||
|
// Switch off keyboard backlight (COL9 = LOW)
|
||||||
|
writeRegister(_TCA8418_REG_GPIO_DAT_OUT_3, 0x00);
|
||||||
|
|
||||||
|
// add all pins to key events
|
||||||
|
writeRegister(_TCA8418_REG_GPI_EM_1, 0xFF);
|
||||||
|
writeRegister(_TCA8418_REG_GPI_EM_2, 0xFF);
|
||||||
|
writeRegister(_TCA8418_REG_GPI_EM_3, 0xFF);
|
||||||
|
|
||||||
|
// set all pins to FALLING interrupts
|
||||||
|
writeRegister(_TCA8418_REG_GPIO_INT_LVL_1, 0x00);
|
||||||
|
writeRegister(_TCA8418_REG_GPIO_INT_LVL_2, 0x00);
|
||||||
|
writeRegister(_TCA8418_REG_GPIO_INT_LVL_3, 0x00);
|
||||||
|
|
||||||
|
// add all pins to interrupts
|
||||||
|
writeRegister(_TCA8418_REG_GPIO_INT_EN_1, 0xFF);
|
||||||
|
writeRegister(_TCA8418_REG_GPIO_INT_EN_2, 0xFF);
|
||||||
|
writeRegister(_TCA8418_REG_GPIO_INT_EN_3, 0xFF);
|
||||||
|
|
||||||
|
// Set keyboard matrix size
|
||||||
|
matrix(_TCA8418_ROWS, _TCA8418_COLS);
|
||||||
|
enableDebounce();
|
||||||
|
flush();
|
||||||
|
state = Idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCA8418Keyboard::matrix(uint8_t rows, uint8_t columns)
|
||||||
|
{
|
||||||
|
if ((rows > 8) || (columns > 10))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Skip zero size matrix
|
||||||
|
if ((rows != 0) && (columns != 0)) {
|
||||||
|
// Setup the keypad matrix.
|
||||||
|
uint8_t mask = 0x00;
|
||||||
|
for (int r = 0; r < rows; r++) {
|
||||||
|
mask <<= 1;
|
||||||
|
mask |= 1;
|
||||||
|
}
|
||||||
|
writeRegister(_TCA8418_REG_KP_GPIO_1, mask);
|
||||||
|
|
||||||
|
mask = 0x00;
|
||||||
|
for (int c = 0; c < columns && c < 8; c++) {
|
||||||
|
mask <<= 1;
|
||||||
|
mask |= 1;
|
||||||
|
}
|
||||||
|
writeRegister(_TCA8418_REG_KP_GPIO_2, mask);
|
||||||
|
|
||||||
|
if (columns > 8) {
|
||||||
|
if (columns == 9)
|
||||||
|
mask = 0x01;
|
||||||
|
else
|
||||||
|
mask = 0x03;
|
||||||
|
writeRegister(_TCA8418_REG_KP_GPIO_3, mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TCA8418Keyboard::keyCount() const
|
||||||
|
{
|
||||||
|
uint8_t eventCount = readRegister(_TCA8418_REG_KEY_LCK_EC);
|
||||||
|
eventCount &= 0x0F; // lower 4 bits only
|
||||||
|
return eventCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCA8418Keyboard::hasEvent()
|
||||||
|
{
|
||||||
|
return queue.length() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::queueEvent(char next)
|
||||||
|
{
|
||||||
|
if (next == _TCA8418_NONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queue.concat(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
char TCA8418Keyboard::dequeueEvent()
|
||||||
|
{
|
||||||
|
if (queue.length() < 1) {
|
||||||
|
return _TCA8418_NONE;
|
||||||
|
}
|
||||||
|
char next = queue.charAt(0);
|
||||||
|
queue.remove(0, 1);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::trigger()
|
||||||
|
{
|
||||||
|
if (keyCount() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state != Init) {
|
||||||
|
// Read the key register
|
||||||
|
uint8_t k = readRegister(_TCA8418_REG_KEY_EVENT_A);
|
||||||
|
uint8_t key = k & 0x7F;
|
||||||
|
if (k & 0x80) {
|
||||||
|
if (state == Idle)
|
||||||
|
pressed(key);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (state == Held) {
|
||||||
|
released();
|
||||||
|
}
|
||||||
|
state = Idle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::pressed(uint8_t key)
|
||||||
|
{
|
||||||
|
if (state == Init || state == Busy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t next_key = 0;
|
||||||
|
int row = (key - 1) / 10;
|
||||||
|
int col = (key - 1) % 10;
|
||||||
|
|
||||||
|
if (row >= _TCA8418_ROWS || col >= _TCA8418_COLS) {
|
||||||
|
return; // Invalid key
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute key index based on dynamic row/column
|
||||||
|
next_key = row * _TCA8418_COLS + col;
|
||||||
|
|
||||||
|
// LOG_DEBUG("TCA8418: Key %u -> Next Key %u", key, next_key);
|
||||||
|
|
||||||
|
state = Held;
|
||||||
|
uint32_t now = millis();
|
||||||
|
tap_interval = now - last_tap;
|
||||||
|
if (tap_interval < 0) {
|
||||||
|
// Long running, millis has overflowed.
|
||||||
|
last_tap = 0;
|
||||||
|
state = Busy;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the key is the same as the last one or if the time interval has passed
|
||||||
|
if (next_key != last_key || tap_interval > _TCA8418_MULTI_TAP_THRESHOLD) {
|
||||||
|
char_idx = 0; // Reset char index if new key or long press
|
||||||
|
should_backspace = false; // dont backspace on new key
|
||||||
|
} else {
|
||||||
|
char_idx += 1; // Cycle through characters if same key pressed
|
||||||
|
should_backspace = true; // allow backspace on same key
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the current key as the last key
|
||||||
|
last_key = next_key;
|
||||||
|
last_tap = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::released()
|
||||||
|
{
|
||||||
|
if (state != Held) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_key < 0 || last_key > _TCA8418_NUM_KEYS) { // reset to idle if last_key out of bounds
|
||||||
|
last_key = -1;
|
||||||
|
state = Idle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t now = millis();
|
||||||
|
int32_t held_interval = now - last_tap;
|
||||||
|
last_tap = now;
|
||||||
|
if (tap_interval < _TCA8418_MULTI_TAP_THRESHOLD && should_backspace) {
|
||||||
|
queueEvent(_TCA8418_BSP);
|
||||||
|
}
|
||||||
|
if (held_interval > _TCA8418_LONG_PRESS_THRESHOLD) {
|
||||||
|
queueEvent(TCA8418LongPressMap[last_key]);
|
||||||
|
// LOG_DEBUG("Long Press Key: %i Map: %i", last_key, TCA8418LongPressMap[last_key]);
|
||||||
|
} else {
|
||||||
|
queueEvent(TCA8418TapMap[last_key][(char_idx % TCA8418TapMod[last_key])]);
|
||||||
|
// LOG_DEBUG("Key Press: %i Index:%i if %i Map: %c", last_key, char_idx, TCA8418TapMod[last_key],
|
||||||
|
// TCA8418TapMap[last_key][(char_idx % TCA8418TapMod[last_key])]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TCA8418Keyboard::flush()
|
||||||
|
{
|
||||||
|
// Flush key events
|
||||||
|
uint8_t count = 0;
|
||||||
|
while (readRegister(_TCA8418_REG_KEY_EVENT_A) != 0)
|
||||||
|
count++;
|
||||||
|
// Flush gpio events
|
||||||
|
readRegister(_TCA8418_REG_GPIO_INT_STAT_1);
|
||||||
|
readRegister(_TCA8418_REG_GPIO_INT_STAT_2);
|
||||||
|
readRegister(_TCA8418_REG_GPIO_INT_STAT_3);
|
||||||
|
// Clear INT_STAT register
|
||||||
|
writeRegister(_TCA8418_REG_INT_STAT, 3);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TCA8418Keyboard::digitalRead(uint8_t pinnum) const
|
||||||
|
{
|
||||||
|
if (pinnum > _TCA8418_COL9)
|
||||||
|
return 0xFF;
|
||||||
|
|
||||||
|
uint8_t reg = _TCA8418_REG_GPIO_DAT_STAT_1 + pinnum / 8;
|
||||||
|
uint8_t mask = (1 << (pinnum % 8));
|
||||||
|
|
||||||
|
// Level 0 = low other = high
|
||||||
|
uint8_t value = readRegister(reg);
|
||||||
|
if (value & mask)
|
||||||
|
return HIGH;
|
||||||
|
return LOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCA8418Keyboard::digitalWrite(uint8_t pinnum, uint8_t level)
|
||||||
|
{
|
||||||
|
if (pinnum > _TCA8418_COL9)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8_t reg = _TCA8418_REG_GPIO_DAT_OUT_1 + pinnum / 8;
|
||||||
|
uint8_t mask = (1 << (pinnum % 8));
|
||||||
|
|
||||||
|
// Level 0 = low other = high
|
||||||
|
uint8_t value = readRegister(reg);
|
||||||
|
if (level == LOW)
|
||||||
|
value &= ~mask;
|
||||||
|
else
|
||||||
|
value |= mask;
|
||||||
|
writeRegister(reg, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCA8418Keyboard::pinMode(uint8_t pinnum, uint8_t mode)
|
||||||
|
{
|
||||||
|
if (pinnum > _TCA8418_COL9)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8_t idx = pinnum / 8;
|
||||||
|
uint8_t reg = _TCA8418_REG_GPIO_DIR_1 + idx;
|
||||||
|
uint8_t mask = (1 << (pinnum % 8));
|
||||||
|
|
||||||
|
// Mode 0 = input 1 = output
|
||||||
|
uint8_t value = readRegister(reg);
|
||||||
|
if (mode == OUTPUT)
|
||||||
|
value |= mask;
|
||||||
|
else
|
||||||
|
value &= ~mask;
|
||||||
|
writeRegister(reg, value);
|
||||||
|
|
||||||
|
// Pullup 0 = enabled 1 = disabled
|
||||||
|
reg = _TCA8418_REG_GPIO_PULL_1 + idx;
|
||||||
|
value = readRegister(reg);
|
||||||
|
if (mode == INPUT_PULLUP)
|
||||||
|
value &= ~mask;
|
||||||
|
else
|
||||||
|
value |= mask;
|
||||||
|
writeRegister(reg, value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCA8418Keyboard::pinIRQMode(uint8_t pinnum, uint8_t mode)
|
||||||
|
{
|
||||||
|
if (pinnum > _TCA8418_COL9)
|
||||||
|
return false;
|
||||||
|
if ((mode != RISING) && (mode != FALLING))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Mode 0 = falling 1 = rising
|
||||||
|
uint8_t idx = pinnum / 8;
|
||||||
|
uint8_t reg = _TCA8418_REG_GPIO_INT_LVL_1 + idx;
|
||||||
|
uint8_t mask = (1 << (pinnum % 8));
|
||||||
|
|
||||||
|
uint8_t value = readRegister(reg);
|
||||||
|
if (mode == RISING)
|
||||||
|
value |= mask;
|
||||||
|
else
|
||||||
|
value &= ~mask;
|
||||||
|
writeRegister(reg, value);
|
||||||
|
|
||||||
|
// Enable interrupt
|
||||||
|
reg = _TCA8418_REG_GPIO_INT_EN_1 + idx;
|
||||||
|
value = readRegister(reg);
|
||||||
|
value |= mask;
|
||||||
|
writeRegister(reg, value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::enableInterrupts()
|
||||||
|
{
|
||||||
|
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
||||||
|
value |= (_TCA8418_REG_CFG_GPI_IEN | _TCA8418_REG_CFG_KE_IEN);
|
||||||
|
writeRegister(_TCA8418_REG_CFG, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
void TCA8418Keyboard::disableInterrupts()
|
||||||
|
{
|
||||||
|
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
||||||
|
value &= ~(_TCA8418_REG_CFG_GPI_IEN | _TCA8418_REG_CFG_KE_IEN);
|
||||||
|
writeRegister(_TCA8418_REG_CFG, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
void TCA8418Keyboard::enableMatrixOverflow()
|
||||||
|
{
|
||||||
|
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
||||||
|
value |= _TCA8418_REG_CFG_OVR_FLOW_M;
|
||||||
|
writeRegister(_TCA8418_REG_CFG, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
void TCA8418Keyboard::disableMatrixOverflow()
|
||||||
|
{
|
||||||
|
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
||||||
|
value &= ~_TCA8418_REG_CFG_OVR_FLOW_M;
|
||||||
|
writeRegister(_TCA8418_REG_CFG, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
void TCA8418Keyboard::enableDebounce()
|
||||||
|
{
|
||||||
|
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_1, 0x00);
|
||||||
|
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_2, 0x00);
|
||||||
|
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_3, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::disableDebounce()
|
||||||
|
{
|
||||||
|
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_1, 0xFF);
|
||||||
|
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_2, 0xFF);
|
||||||
|
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_3, 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::setBacklight(bool on)
|
||||||
|
{
|
||||||
|
if (on) {
|
||||||
|
digitalWrite(_TCA8418_COL9, HIGH);
|
||||||
|
} else {
|
||||||
|
digitalWrite(_TCA8418_COL9, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TCA8418Keyboard::readRegister(uint8_t reg) const
|
||||||
|
{
|
||||||
|
if (m_wire) {
|
||||||
|
m_wire->beginTransmission(m_addr);
|
||||||
|
m_wire->write(reg);
|
||||||
|
m_wire->endTransmission();
|
||||||
|
|
||||||
|
m_wire->requestFrom(m_addr, (uint8_t)1);
|
||||||
|
if (m_wire->available() < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return m_wire->read();
|
||||||
|
}
|
||||||
|
if (readCallback) {
|
||||||
|
uint8_t data;
|
||||||
|
readCallback(m_addr, reg, &data, 1);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418Keyboard::writeRegister(uint8_t reg, uint8_t value)
|
||||||
|
{
|
||||||
|
uint8_t data[2];
|
||||||
|
data[0] = reg;
|
||||||
|
data[1] = value;
|
||||||
|
|
||||||
|
if (m_wire) {
|
||||||
|
m_wire->beginTransmission(m_addr);
|
||||||
|
m_wire->write(data, sizeof(uint8_t) * 2);
|
||||||
|
m_wire->endTransmission();
|
||||||
|
}
|
||||||
|
if (writeCallback) {
|
||||||
|
writeCallback(m_addr, data[0], &(data[1]), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
// Based on the MPR121 Keyboard and Adafruit TCA8418 library
|
||||||
|
#include "configuration.h"
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
#define _TCA8418_NONE 0x00
|
||||||
|
#define _TCA8418_REBOOT 0x90
|
||||||
|
#define _TCA8418_LEFT 0xb4
|
||||||
|
#define _TCA8418_UP 0xb5
|
||||||
|
#define _TCA8418_DOWN 0xb6
|
||||||
|
#define _TCA8418_RIGHT 0xb7
|
||||||
|
#define _TCA8418_ESC 0x1b
|
||||||
|
#define _TCA8418_BSP 0x08
|
||||||
|
#define _TCA8418_SELECT 0x0d
|
||||||
|
|
||||||
|
class TCA8418Keyboard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
|
||||||
|
|
||||||
|
enum KeyState { Init = 0, Idle, Held, Busy };
|
||||||
|
|
||||||
|
KeyState state;
|
||||||
|
int8_t last_key;
|
||||||
|
int8_t next_key;
|
||||||
|
bool should_backspace;
|
||||||
|
uint32_t last_tap;
|
||||||
|
uint8_t char_idx;
|
||||||
|
int32_t tap_interval;
|
||||||
|
bool backlight_on;
|
||||||
|
|
||||||
|
String queue;
|
||||||
|
|
||||||
|
TCA8418Keyboard();
|
||||||
|
|
||||||
|
void begin(uint8_t addr = XPOWERS_AXP192_AXP2101_ADDRESS, TwoWire *wire = &Wire);
|
||||||
|
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = XPOWERS_AXP192_AXP2101_ADDRESS);
|
||||||
|
|
||||||
|
void reset(void);
|
||||||
|
// Configure the size of the keypad.
|
||||||
|
// All other rows and columns are set as inputs.
|
||||||
|
bool matrix(uint8_t rows, uint8_t columns);
|
||||||
|
|
||||||
|
// Flush all events in the FIFO buffer + GPIO events.
|
||||||
|
uint8_t flush(void);
|
||||||
|
|
||||||
|
// Key events available in the internal FIFO buffer.
|
||||||
|
uint8_t keyCount(void) const;
|
||||||
|
|
||||||
|
void trigger(void);
|
||||||
|
void pressed(uint8_t key);
|
||||||
|
void released(void);
|
||||||
|
bool hasEvent(void);
|
||||||
|
char dequeueEvent(void);
|
||||||
|
void queueEvent(char);
|
||||||
|
|
||||||
|
uint8_t digitalRead(uint8_t pinnum) const;
|
||||||
|
bool digitalWrite(uint8_t pinnum, uint8_t level);
|
||||||
|
bool pinMode(uint8_t pinnum, uint8_t mode);
|
||||||
|
bool pinIRQMode(uint8_t pinnum, uint8_t mode); // MODE FALLING or RISING
|
||||||
|
|
||||||
|
// enable / disable interrupts for matrix and GPI pins
|
||||||
|
void enableInterrupts();
|
||||||
|
void disableInterrupts();
|
||||||
|
|
||||||
|
// ignore key events when FIFO buffer is full or not.
|
||||||
|
void enableMatrixOverflow();
|
||||||
|
void disableMatrixOverflow();
|
||||||
|
|
||||||
|
// debounce keys.
|
||||||
|
void enableDebounce();
|
||||||
|
void disableDebounce();
|
||||||
|
|
||||||
|
void setBacklight(bool on);
|
||||||
|
|
||||||
|
uint8_t readRegister(uint8_t reg) const;
|
||||||
|
void writeRegister(uint8_t reg, uint8_t value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TwoWire *m_wire;
|
||||||
|
uint8_t m_addr;
|
||||||
|
i2c_com_fptr_t readCallback;
|
||||||
|
i2c_com_fptr_t writeCallback;
|
||||||
|
};
|
||||||
@@ -12,8 +12,8 @@ void CardKbI2cImpl::init()
|
|||||||
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(I2C_NO_RESCAN)
|
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(I2C_NO_RESCAN)
|
||||||
if (cardkb_found.address == 0x00) {
|
if (cardkb_found.address == 0x00) {
|
||||||
LOG_DEBUG("Rescan for I2C keyboard");
|
LOG_DEBUG("Rescan for I2C keyboard");
|
||||||
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR};
|
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR, XPOWERS_AXP192_AXP2101_ADDRESS};
|
||||||
uint8_t i2caddr_asize = 4;
|
uint8_t i2caddr_asize = 5;
|
||||||
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
||||||
|
|
||||||
#if WIRE_INTERFACES_COUNT == 2
|
#if WIRE_INTERFACES_COUNT == 2
|
||||||
@@ -43,6 +43,10 @@ void CardKbI2cImpl::init()
|
|||||||
// assign an arbitrary value to distinguish from other models
|
// assign an arbitrary value to distinguish from other models
|
||||||
kb_model = 0x37;
|
kb_model = 0x37;
|
||||||
break;
|
break;
|
||||||
|
case ScanI2C::DeviceType::TCA8418KB:
|
||||||
|
// assign an arbitrary value to distinguish from other models
|
||||||
|
kb_model = 0x84;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// use this as default since it's also just zero
|
// use this as default since it's also just zero
|
||||||
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00", kb_info.type);
|
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00", kb_info.type);
|
||||||
@@ -63,4 +67,4 @@ void CardKbI2cImpl::init()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
inputBroker->registerSource(this);
|
inputBroker->registerSource(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ int32_t KbI2cBase::runOnce()
|
|||||||
if (cardkb_found.address == MPR121_KB_ADDR) {
|
if (cardkb_found.address == MPR121_KB_ADDR) {
|
||||||
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire1);
|
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire1);
|
||||||
}
|
}
|
||||||
|
if (cardkb_found.address == XPOWERS_AXP192_AXP2101_ADDRESS) {
|
||||||
|
TCAKeyboard.begin(XPOWERS_AXP192_AXP2101_ADDRESS, &Wire1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case ScanI2C::WIRE:
|
case ScanI2C::WIRE:
|
||||||
@@ -55,6 +58,9 @@ int32_t KbI2cBase::runOnce()
|
|||||||
if (cardkb_found.address == MPR121_KB_ADDR) {
|
if (cardkb_found.address == MPR121_KB_ADDR) {
|
||||||
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire);
|
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire);
|
||||||
}
|
}
|
||||||
|
if (cardkb_found.address == XPOWERS_AXP192_AXP2101_ADDRESS) {
|
||||||
|
TCAKeyboard.begin(XPOWERS_AXP192_AXP2101_ADDRESS, &Wire);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ScanI2C::NO_I2C:
|
case ScanI2C::NO_I2C:
|
||||||
default:
|
default:
|
||||||
@@ -163,6 +169,70 @@ int32_t KbI2cBase::runOnce()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 0x84: { // Adafruit TCA8418
|
||||||
|
TCAKeyboard.trigger();
|
||||||
|
InputEvent e;
|
||||||
|
while (TCAKeyboard.hasEvent()) {
|
||||||
|
char nextEvent = TCAKeyboard.dequeueEvent();
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = 0x00;
|
||||||
|
e.source = this->_originName;
|
||||||
|
switch (nextEvent) {
|
||||||
|
case _TCA8418_NONE:
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||||
|
e.kbchar = 0x00;
|
||||||
|
break;
|
||||||
|
case _TCA8418_REBOOT:
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = INPUT_BROKER_MSG_REBOOT;
|
||||||
|
break;
|
||||||
|
case _TCA8418_LEFT:
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||||
|
e.kbchar = 0x00;
|
||||||
|
break;
|
||||||
|
case _TCA8418_UP:
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||||
|
e.kbchar = 0x00;
|
||||||
|
break;
|
||||||
|
case _TCA8418_DOWN:
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||||
|
e.kbchar = 0x00;
|
||||||
|
break;
|
||||||
|
case _TCA8418_RIGHT:
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||||
|
e.kbchar = 0x00;
|
||||||
|
break;
|
||||||
|
case _TCA8418_BSP:
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||||
|
e.kbchar = 0x08;
|
||||||
|
break;
|
||||||
|
case _TCA8418_SELECT:
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||||
|
e.kbchar = 0x0d;
|
||||||
|
break;
|
||||||
|
case _TCA8418_ESC:
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||||
|
e.kbchar = 0x1b;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (nextEvent > 127) {
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||||
|
e.kbchar = 0x00;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = nextEvent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||||
|
LOG_DEBUG("TCA8418 Notifying: %i Char: %c", e.inputEvent, e.kbchar);
|
||||||
|
this->notifyObservers(&e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x37: { // MPR121
|
case 0x37: { // MPR121
|
||||||
MPRkeyboard.trigger();
|
MPRkeyboard.trigger();
|
||||||
InputEvent e;
|
InputEvent e;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "BBQ10Keyboard.h"
|
#include "BBQ10Keyboard.h"
|
||||||
#include "InputBroker.h"
|
#include "InputBroker.h"
|
||||||
#include "MPR121Keyboard.h"
|
#include "MPR121Keyboard.h"
|
||||||
|
#include "TCA8418Keyboard.h"
|
||||||
#include "Wire.h"
|
#include "Wire.h"
|
||||||
#include "concurrency/OSThread.h"
|
#include "concurrency/OSThread.h"
|
||||||
|
|
||||||
@@ -21,5 +22,6 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
|
|||||||
|
|
||||||
BBQ10Keyboard Q10keyboard;
|
BBQ10Keyboard Q10keyboard;
|
||||||
MPR121Keyboard MPRkeyboard;
|
MPR121Keyboard MPRkeyboard;
|
||||||
|
TCA8418Keyboard TCAKeyboard;
|
||||||
bool is_sym = false;
|
bool is_sym = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -568,6 +568,10 @@ void setup()
|
|||||||
// assign an arbitrary value to distinguish from other models
|
// assign an arbitrary value to distinguish from other models
|
||||||
kb_model = 0x37;
|
kb_model = 0x37;
|
||||||
break;
|
break;
|
||||||
|
case ScanI2C::DeviceType::TCA8418KB:
|
||||||
|
// assign an arbitrary value to distinguish from other models
|
||||||
|
kb_model = 0x84;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// use this as default since it's also just zero
|
// use this as default since it's also just zero
|
||||||
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00", kb_info.type);
|
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00", kb_info.type);
|
||||||
@@ -822,6 +826,13 @@ void setup()
|
|||||||
#ifdef HAS_UDP_MULTICAST
|
#ifdef HAS_UDP_MULTICAST
|
||||||
LOG_DEBUG("Start multicast thread");
|
LOG_DEBUG("Start multicast thread");
|
||||||
udpThread = new UdpMulticastThread();
|
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
|
#endif
|
||||||
service = new MeshService();
|
service = new MeshService();
|
||||||
service->init();
|
service->init();
|
||||||
|
|||||||
@@ -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)
|
void CryptoEngine::aesSetKey(const uint8_t *key_bytes, size_t key_len)
|
||||||
{
|
{
|
||||||
if (aes) {
|
delete aes;
|
||||||
delete aes;
|
aes = nullptr;
|
||||||
aes = nullptr;
|
|
||||||
}
|
|
||||||
if (key_len != 0) {
|
if (key_len != 0) {
|
||||||
aes = new AESSmall256();
|
aes = new AESSmall256();
|
||||||
aes->setKey(key_bytes, key_len);
|
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.
|
// Generic implementation of AES-CTR encryption.
|
||||||
void CryptoEngine::encryptAESCtr(CryptoKey _key, uint8_t *_nonce, size_t numBytes, uint8_t *bytes)
|
void CryptoEngine::encryptAESCtr(CryptoKey _key, uint8_t *_nonce, size_t numBytes, uint8_t *bytes)
|
||||||
{
|
{
|
||||||
if (ctr) {
|
delete ctr;
|
||||||
delete ctr;
|
ctr = nullptr;
|
||||||
ctr = nullptr;
|
|
||||||
}
|
|
||||||
if (_key.length == 16)
|
if (_key.length == 16)
|
||||||
ctr = new CTR<AES128>();
|
ctr = new CTR<AES128>();
|
||||||
else
|
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++;
|
fromNum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +326,10 @@ void MeshService::sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage
|
|||||||
releaseMqttClientProxyMessageToPool(d);
|
releaseMqttClientProxyMessageToPool(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(toPhoneMqttProxyQueue.enqueue(m, 0));
|
if (toPhoneMqttProxyQueue.enqueue(m, 0) == false) {
|
||||||
|
LOG_CRIT("Failed to queue a packet into toPhoneMqttProxyQueue!");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
fromNum++;
|
fromNum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +343,10 @@ void MeshService::sendClientNotification(meshtastic_ClientNotification *n)
|
|||||||
releaseClientNotificationToPool(d);
|
releaseClientNotificationToPool(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(toPhoneClientNotificationQueue.enqueue(n, 0));
|
if (toPhoneClientNotificationQueue.enqueue(n, 0) == false) {
|
||||||
|
LOG_CRIT("Failed to queue a notification into toPhoneClientNotificationQueue!");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
fromNum++;
|
fromNum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+127
-7
@@ -51,6 +51,10 @@
|
|||||||
#include <utility/bonding.h>
|
#include <utility/bonding.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI
|
||||||
|
#include <WiFiOTA.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
NodeDB *nodeDB = nullptr;
|
NodeDB *nodeDB = nullptr;
|
||||||
|
|
||||||
// we have plenty of ram so statically alloc this tempbuf (for now)
|
// 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_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING |
|
||||||
meshtastic_Config_PositionConfig_PositionFlags_DOP | meshtastic_Config_PositionConfig_PositionFlags_SATINVIEW);
|
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
|
#ifdef DISPLAY_FLIP_SCREEN
|
||||||
config.display.flip_screen = true;
|
config.display.flip_screen = true;
|
||||||
#endif
|
#endif
|
||||||
@@ -635,6 +660,12 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
|||||||
config.display.wake_on_tap_or_motion = true;
|
config.display.wake_on_tap_or_motion = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI
|
||||||
|
if (WiFiOTA::isUpdated()) {
|
||||||
|
WiFiOTA::recoverConfig(&config.network);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
initConfigIntervals();
|
initConfigIntervals();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1427,13 +1458,14 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
|
|||||||
#if !(MESHTASTIC_EXCLUDE_PKI)
|
#if !(MESHTASTIC_EXCLUDE_PKI)
|
||||||
if (p.public_key.size > 0) {
|
if (p.public_key.size > 0) {
|
||||||
printBytes("Incoming Pubkey: ", p.public_key.bytes, 32);
|
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!");
|
if (info->user.public_key.size > 0) { // if we have a key for this user already, don't overwrite with a new one
|
||||||
// we copy the key into the incoming packet, to prevent overwrite
|
LOG_INFO("Public Key set for node, not updating!");
|
||||||
memcpy(p.public_key.bytes, info->user.public_key.bytes, 32);
|
// we copy the key into the incoming packet, to prevent overwrite
|
||||||
} else {
|
p.public_key.size = 32;
|
||||||
LOG_INFO("Update Node Pubkey!");
|
memcpy(p.public_key.bytes, info->user.public_key.bytes, 32);
|
||||||
}
|
} else if (p.public_key.size > 0) {
|
||||||
|
LOG_INFO("Update Node Pubkey!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1598,6 +1630,94 @@ UserLicenseStatus NodeDB::getLicenseStatus(uint32_t nodeNum)
|
|||||||
return info->user.is_licensed ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed;
|
return info->user.is_licensed ? UserLicenseStatus::Licensed : UserLicenseStatus::NotLicensed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NodeDB::backupPreferences(meshtastic_AdminMessage_BackupLocation location)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
lastBackupAttempt = millis();
|
||||||
|
#ifdef FSCom
|
||||||
|
if (location == meshtastic_AdminMessage_BackupLocation_FLASH) {
|
||||||
|
meshtastic_BackupPreferences backup = meshtastic_BackupPreferences_init_zero;
|
||||||
|
backup.version = DEVICESTATE_CUR_VER;
|
||||||
|
backup.timestamp = getValidTime(RTCQuality::RTCQualityDevice, false);
|
||||||
|
backup.has_config = true;
|
||||||
|
backup.config = config;
|
||||||
|
backup.has_module_config = true;
|
||||||
|
backup.module_config = moduleConfig;
|
||||||
|
backup.has_channels = true;
|
||||||
|
backup.channels = channelFile;
|
||||||
|
backup.has_owner = true;
|
||||||
|
backup.owner = owner;
|
||||||
|
|
||||||
|
size_t backupSize;
|
||||||
|
pb_get_encoded_size(&backupSize, meshtastic_BackupPreferences_fields, &backup);
|
||||||
|
|
||||||
|
spiLock->lock();
|
||||||
|
FSCom.mkdir("/backups");
|
||||||
|
spiLock->unlock();
|
||||||
|
success = saveProto(backupFileName, backupSize, &meshtastic_BackupPreferences_msg, &backup);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
LOG_INFO("Saved backup preferences");
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Failed to save backup preferences to file");
|
||||||
|
}
|
||||||
|
} else if (location == meshtastic_AdminMessage_BackupLocation_SD) {
|
||||||
|
// TODO: After more mainline SD card support
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location, int restoreWhat)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
#ifdef FSCom
|
||||||
|
if (location == meshtastic_AdminMessage_BackupLocation_FLASH) {
|
||||||
|
spiLock->lock();
|
||||||
|
if (!FSCom.exists(backupFileName)) {
|
||||||
|
spiLock->unlock();
|
||||||
|
LOG_WARN("Could not restore. No backup file found");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
spiLock->unlock();
|
||||||
|
}
|
||||||
|
meshtastic_BackupPreferences backup = meshtastic_BackupPreferences_init_zero;
|
||||||
|
success = loadProto(backupFileName, meshtastic_BackupPreferences_size, sizeof(meshtastic_BackupPreferences),
|
||||||
|
&meshtastic_BackupPreferences_msg, &backup);
|
||||||
|
if (success) {
|
||||||
|
if (restoreWhat & SEGMENT_CONFIG) {
|
||||||
|
config = backup.config;
|
||||||
|
LOG_DEBUG("Restored config");
|
||||||
|
}
|
||||||
|
if (restoreWhat & SEGMENT_MODULECONFIG) {
|
||||||
|
moduleConfig = backup.module_config;
|
||||||
|
LOG_DEBUG("Restored module config");
|
||||||
|
}
|
||||||
|
if (restoreWhat & SEGMENT_DEVICESTATE) {
|
||||||
|
devicestate.owner = backup.owner;
|
||||||
|
LOG_DEBUG("Restored device state");
|
||||||
|
}
|
||||||
|
if (restoreWhat & SEGMENT_CHANNELS) {
|
||||||
|
channelFile = backup.channels;
|
||||||
|
LOG_DEBUG("Restored channels");
|
||||||
|
}
|
||||||
|
|
||||||
|
success = saveToDisk(restoreWhat);
|
||||||
|
if (success) {
|
||||||
|
LOG_INFO("Restored preferences from backup");
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Failed to save restored preferences to flash");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Failed to restore preferences from backup file");
|
||||||
|
}
|
||||||
|
} else if (location == meshtastic_AdminMessage_BackupLocation_SD) {
|
||||||
|
// TODO: After more mainline SD card support
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/// Record an error that should be reported via analytics
|
/// Record an error that should be reported via analytics
|
||||||
void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, const char *filename)
|
void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, const char *filename)
|
||||||
{
|
{
|
||||||
|
|||||||
+7
-1
@@ -48,6 +48,7 @@ static constexpr const char *configFileName = "/prefs/config.proto";
|
|||||||
static constexpr const char *uiconfigFileName = "/prefs/uiconfig.proto";
|
static constexpr const char *uiconfigFileName = "/prefs/uiconfig.proto";
|
||||||
static constexpr const char *moduleConfigFileName = "/prefs/module.proto";
|
static constexpr const char *moduleConfigFileName = "/prefs/module.proto";
|
||||||
static constexpr const char *channelFileName = "/prefs/channels.proto";
|
static constexpr const char *channelFileName = "/prefs/channels.proto";
|
||||||
|
static constexpr const char *backupFileName = "/backups/backup.proto";
|
||||||
|
|
||||||
/// Given a node, return how many seconds in the past (vs now) that we last heard from it
|
/// Given a node, return how many seconds in the past (vs now) that we last heard from it
|
||||||
uint32_t sinceLastSeen(const meshtastic_NodeInfoLite *n);
|
uint32_t sinceLastSeen(const meshtastic_NodeInfoLite *n);
|
||||||
@@ -202,8 +203,13 @@ class NodeDB
|
|||||||
|
|
||||||
bool hasValidPosition(const meshtastic_NodeInfoLite *n);
|
bool hasValidPosition(const meshtastic_NodeInfoLite *n);
|
||||||
|
|
||||||
|
bool backupPreferences(meshtastic_AdminMessage_BackupLocation location);
|
||||||
|
bool restorePreferences(meshtastic_AdminMessage_BackupLocation location,
|
||||||
|
int restoreWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t lastNodeDbSave = 0; // when we last saved our db to flash
|
uint32_t lastNodeDbSave = 0; // when we last saved our db to flash
|
||||||
|
uint32_t lastBackupAttempt = 0; // when we last tried a backup automatically or manually
|
||||||
/// Find a node in our DB, create an empty NodeInfoLite if missing
|
/// Find a node in our DB, create an empty NodeInfoLite if missing
|
||||||
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
|
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -372,7 +372,7 @@ DecodeState perhapsDecode(meshtastic_MeshPacket *p)
|
|||||||
p->pki_encrypted = true;
|
p->pki_encrypted = true;
|
||||||
memcpy(&p->public_key.bytes, nodeDB->getMeshNode(p->from)->user.public_key.bytes, 32);
|
memcpy(&p->public_key.bytes, nodeDB->getMeshNode(p->from)->user.public_key.bytes, 32);
|
||||||
p->public_key.size = 32;
|
p->public_key.size = 32;
|
||||||
memcpy(&p->decoded, &decodedtmp, sizeof(meshtastic_Data_msg));
|
p->decoded = decodedtmp;
|
||||||
p->which_payload_variant = meshtastic_MeshPacket_decoded_tag; // change type to decoded
|
p->which_payload_variant = meshtastic_MeshPacket_decoded_tag; // change type to decoded
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("PKC Decrypted, but pb_decode failed!");
|
LOG_ERROR("PKC Decrypted, but pb_decode failed!");
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ bool STM32WLE5JCInterface::init()
|
|||||||
{
|
{
|
||||||
RadioLibInterface::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);
|
setTCXOVoltage(1.7);
|
||||||
|
#endif
|
||||||
|
|
||||||
lora.setRfSwitchTable(rfswitch_pins, rfswitch_table);
|
lora.setRfSwitchTable(rfswitch_pins, rfswitch_table);
|
||||||
|
|
||||||
@@ -42,4 +44,4 @@ bool STM32WLE5JCInterface::init()
|
|||||||
return res == RADIOLIB_ERR_NONE;
|
return res == RADIOLIB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ARCH_STM32WL
|
#endif // ARCH_STM32WL
|
||||||
|
|||||||
@@ -235,6 +235,8 @@ typedef enum _meshtastic_HardwareModel {
|
|||||||
meshtastic_HardwareModel_THINKNODE_M2 = 90,
|
meshtastic_HardwareModel_THINKNODE_M2 = 90,
|
||||||
/* Lilygo T-ETH-Elite */
|
/* Lilygo T-ETH-Elite */
|
||||||
meshtastic_HardwareModel_T_ETH_ELITE = 91,
|
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.
|
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.
|
||||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|||||||
@@ -18,10 +18,30 @@
|
|||||||
#define MAX_RX_TOPHONE 32
|
#define MAX_RX_TOPHONE 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// max number of nodes allowed in the mesh
|
/// max number of nodes allowed in the nodeDB
|
||||||
#ifndef MAX_NUM_NODES
|
#ifndef MAX_NUM_NODES
|
||||||
|
#if defined(ARCH_STM32WL)
|
||||||
|
#define MAX_NUM_NODES 10
|
||||||
|
#elif defined(ARCH_NRF52)
|
||||||
|
#define MAX_NUM_NODES 80
|
||||||
|
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
#include "Esp.h"
|
||||||
|
static inline int get_max_num_nodes()
|
||||||
|
{
|
||||||
|
uint32_t flash_size = ESP.getFlashChipSize() / (1024 * 1024); // Convert Bytes to MB
|
||||||
|
if (flash_size >= 15) {
|
||||||
|
return 250;
|
||||||
|
} else if (flash_size >= 7) {
|
||||||
|
return 200;
|
||||||
|
} else {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define MAX_NUM_NODES get_max_num_nodes()
|
||||||
|
#else
|
||||||
#define MAX_NUM_NODES 100
|
#define MAX_NUM_NODES 100
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Max number of channels allowed
|
/// Max number of channels allowed
|
||||||
#define MAX_NUM_CHANNELS (member_size(meshtastic_ChannelFile, channels) / member_size(meshtastic_ChannelFile, channels[0]))
|
#define MAX_NUM_CHANNELS (member_size(meshtastic_ChannelFile, channels) / member_size(meshtastic_ChannelFile, channels[0]))
|
||||||
|
|||||||
@@ -22,8 +22,13 @@ class UdpMulticastThread : public concurrency::OSThread
|
|||||||
|
|
||||||
void start()
|
void start()
|
||||||
{
|
{
|
||||||
if (udp.listenMulticast(udpIpAddress, UDP_MULTICAST_DEFAUL_PORT)) {
|
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());
|
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); });
|
udp.onPacket([this](AsyncUDPPacket packet) { onReceive(packet); });
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG("Failed to listen on UDP");
|
LOG_DEBUG("Failed to listen on UDP");
|
||||||
@@ -33,7 +38,10 @@ class UdpMulticastThread : public concurrency::OSThread
|
|||||||
void onReceive(AsyncUDPPacket packet)
|
void onReceive(AsyncUDPPacket packet)
|
||||||
{
|
{
|
||||||
size_t packetLength = packet.length();
|
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);
|
LOG_DEBUG("UDP broadcast from: %s, len=%u", packet.remoteIP().toString().c_str(), packetLength);
|
||||||
|
#endif
|
||||||
meshtastic_MeshPacket mp;
|
meshtastic_MeshPacket mp;
|
||||||
LOG_DEBUG("Decoding MeshPacket from UDP len=%u", packetLength);
|
LOG_DEBUG("Decoding MeshPacket from UDP len=%u", packetLength);
|
||||||
bool isPacketDecoded = pb_decode_from_bytes(packet.data(), packetLength, &meshtastic_MeshPacket_msg, &mp);
|
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)
|
bool onSend(const meshtastic_MeshPacket *mp)
|
||||||
{
|
{
|
||||||
if (!mp || WiFi.status() != WL_CONNECTED) {
|
if (!mp || !udp) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifndef ARCH_PORTDUINO
|
||||||
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
LOG_DEBUG("Broadcasting packet over UDP (id=%u)", mp->id);
|
LOG_DEBUG("Broadcasting packet over UDP (id=%u)", mp->id);
|
||||||
uint8_t buffer[meshtastic_MeshPacket_size];
|
uint8_t buffer[meshtastic_MeshPacket_size];
|
||||||
size_t encodedLength = pb_encode_to_bytes(buffer, sizeof(buffer), &meshtastic_MeshPacket_msg, mp);
|
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;
|
IPAddress udpIpAddress;
|
||||||
AsyncUDP udp;
|
AsyncUDP udp;
|
||||||
};
|
};
|
||||||
#endif // ARCH_ESP32
|
#endif // HAS_UDP_MULTICAST
|
||||||
@@ -133,7 +133,7 @@ static void onNetworkConnected()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if HAS_UDP_MULTICAST
|
#if HAS_UDP_MULTICAST
|
||||||
if (udpThread) {
|
if (udpThread && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
|
||||||
udpThread->start();
|
udpThread->start();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH
|
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||||
#include "BleOta.h"
|
#include "BleOta.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI
|
||||||
|
#include "WiFiOTA.h"
|
||||||
|
#endif
|
||||||
#include "Router.h"
|
#include "Router.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
@@ -194,19 +197,23 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
|||||||
}
|
}
|
||||||
case meshtastic_AdminMessage_reboot_ota_seconds_tag: {
|
case meshtastic_AdminMessage_reboot_ota_seconds_tag: {
|
||||||
int32_t s = r->reboot_ota_seconds;
|
int32_t s = r->reboot_ota_seconds;
|
||||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH
|
#if defined(ARCH_ESP32)
|
||||||
if (BleOta::getOtaAppVersion().isEmpty()) {
|
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||||
LOG_INFO("No OTA firmware available, scheduling regular reboot in %d seconds", s);
|
if (!BleOta::getOtaAppVersion().isEmpty()) {
|
||||||
screen->startAlert("Rebooting...");
|
|
||||||
} else {
|
|
||||||
screen->startFirmwareUpdateScreen();
|
screen->startFirmwareUpdateScreen();
|
||||||
BleOta::switchToOtaApp();
|
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
|
#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);
|
rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -370,6 +377,42 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
|||||||
LOG_DEBUG("Failed to delete file");
|
LOG_DEBUG("Failed to delete file");
|
||||||
}
|
}
|
||||||
spiLock->unlock();
|
spiLock->unlock();
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case meshtastic_AdminMessage_backup_preferences_tag: {
|
||||||
|
LOG_INFO("Client requesting to backup preferences");
|
||||||
|
if (nodeDB->backupPreferences(r->backup_preferences)) {
|
||||||
|
myReply = allocErrorResponse(meshtastic_Routing_Error_NONE, &mp);
|
||||||
|
} else {
|
||||||
|
myReply = allocErrorResponse(meshtastic_Routing_Error_BAD_REQUEST, &mp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case meshtastic_AdminMessage_restore_preferences_tag: {
|
||||||
|
LOG_INFO("Client requesting to restore preferences");
|
||||||
|
if (nodeDB->restorePreferences(r->backup_preferences,
|
||||||
|
SEGMENT_DEVICESTATE | SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_CHANNELS)) {
|
||||||
|
myReply = allocErrorResponse(meshtastic_Routing_Error_NONE, &mp);
|
||||||
|
LOG_DEBUG("Rebooting after successful restore of preferences");
|
||||||
|
reboot(1000);
|
||||||
|
disableBluetooth();
|
||||||
|
} else {
|
||||||
|
myReply = allocErrorResponse(meshtastic_Routing_Error_BAD_REQUEST, &mp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case meshtastic_AdminMessage_remove_backup_preferences_tag: {
|
||||||
|
LOG_INFO("Client requesting to remove backup preferences");
|
||||||
|
#ifdef FSCom
|
||||||
|
if (r->remove_backup_preferences == meshtastic_AdminMessage_BackupLocation_FLASH) {
|
||||||
|
spiLock->lock();
|
||||||
|
FSCom.remove(backupFileName);
|
||||||
|
spiLock->unlock();
|
||||||
|
} else if (r->remove_backup_preferences == meshtastic_AdminMessage_BackupLocation_SD) {
|
||||||
|
// TODO: After more mainline SD card support
|
||||||
|
LOG_ERROR("SD backup removal not implemented yet");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,9 @@
|
|||||||
#include "input/SerialKeyboardImpl.h"
|
#include "input/SerialKeyboardImpl.h"
|
||||||
#include "input/TrackballInterruptImpl1.h"
|
#include "input/TrackballInterruptImpl1.h"
|
||||||
#include "input/UpDownInterruptImpl1.h"
|
#include "input/UpDownInterruptImpl1.h"
|
||||||
|
#if !MESHTASTIC_EXCLUDE_I2C
|
||||||
#include "input/cardKbI2cImpl.h"
|
#include "input/cardKbI2cImpl.h"
|
||||||
|
#endif
|
||||||
#include "input/kbMatrixImpl.h"
|
#include "input/kbMatrixImpl.h"
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_ADMIN
|
#if !MESHTASTIC_EXCLUDE_ADMIN
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ uint32_t packetSequence = 0;
|
|||||||
|
|
||||||
int32_t RangeTestModule::runOnce()
|
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
|
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)
|
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) {
|
if (moduleConfig.range_test.enabled) {
|
||||||
|
|
||||||
|
|||||||
@@ -468,81 +468,83 @@ void SerialModule::processWXSerial()
|
|||||||
// Extract the current line
|
// Extract the current line
|
||||||
char line[meshtastic_Constants_DATA_PAYLOAD_LEN];
|
char line[meshtastic_Constants_DATA_PAYLOAD_LEN];
|
||||||
memset(line, '\0', sizeof(line));
|
memset(line, '\0', sizeof(line));
|
||||||
memcpy(line, &serialBytes[lineStart], lineEnd - lineStart);
|
if (lineEnd - lineStart < sizeof(line) - 1) {
|
||||||
if (strstr(line, "Wind") != NULL) // we have a wind 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
|
gotwind = true;
|
||||||
char *windDirPos = strstr(line, "WindDir = ");
|
// Find the positions of "=" signs in the line
|
||||||
char *windSpeedPos = strstr(line, "WindSpeed = ");
|
char *windDirPos = strstr(line, "WindDir = ");
|
||||||
char *windGustPos = strstr(line, "WindGust = ");
|
char *windSpeedPos = strstr(line, "WindSpeed = ");
|
||||||
|
char *windGustPos = strstr(line, "WindGust = ");
|
||||||
|
|
||||||
if (windDirPos != NULL) {
|
if (windDirPos != NULL) {
|
||||||
// Extract data after "=" for WindDir
|
// Extract data after "=" for WindDir
|
||||||
strcpy(windDir, windDirPos + 15); // Add 15 to skip "WindDir = "
|
strlcpy(windDir, windDirPos + 15, sizeof(windDir)); // Add 15 to skip "WindDir = "
|
||||||
double radians = GeoCoord::toRadians(strtof(windDir, nullptr));
|
double radians = GeoCoord::toRadians(strtof(windDir, nullptr));
|
||||||
dir_sum_sin += sin(radians);
|
dir_sum_sin += sin(radians);
|
||||||
dir_sum_cos += cos(radians);
|
dir_sum_cos += cos(radians);
|
||||||
dirCount++;
|
dirCount++;
|
||||||
} else if (windSpeedPos != NULL) {
|
} else if (windSpeedPos != NULL) {
|
||||||
// Extract data after "=" for WindSpeed
|
// Extract data after "=" for WindSpeed
|
||||||
strcpy(windVel, windSpeedPos + 15); // Add 15 to skip "WindSpeed = "
|
strlcpy(windVel, windSpeedPos + 15, sizeof(windVel)); // Add 15 to skip "WindSpeed = "
|
||||||
float newv = strtof(windVel, nullptr);
|
float newv = strtof(windVel, nullptr);
|
||||||
velSum += newv;
|
velSum += newv;
|
||||||
velCount++;
|
velCount++;
|
||||||
if (newv < lull || lull == -1)
|
if (newv < lull || lull == -1)
|
||||||
lull = newv;
|
lull = newv;
|
||||||
|
|
||||||
} else if (windGustPos != NULL) {
|
} else if (windGustPos != NULL) {
|
||||||
strcpy(windGust, windGustPos + 15); // Add 15 to skip "WindSpeed = "
|
strlcpy(windGust, windGustPos + 15, sizeof(windGust)); // Add 15 to skip "WindSpeed = "
|
||||||
float newg = strtof(windGust, nullptr);
|
float newg = strtof(windGust, nullptr);
|
||||||
if (newg > gust)
|
if (newg > gust)
|
||||||
gust = newg;
|
gust = newg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// these are also voltage data we care about possibly
|
// these are also voltage data we care about possibly
|
||||||
} else if (strstr(line, "BatVoltage") != NULL) { // we have a battVoltage line
|
} else if (strstr(line, "BatVoltage") != NULL) { // we have a battVoltage line
|
||||||
char *batVoltagePos = strstr(line, "BatVoltage = ");
|
char *batVoltagePos = strstr(line, "BatVoltage = ");
|
||||||
if (batVoltagePos != NULL) {
|
if (batVoltagePos != NULL) {
|
||||||
strcpy(batVoltage, batVoltagePos + 17); // 18 for ws 80, 17 for ws85
|
strlcpy(batVoltage, batVoltagePos + 17, sizeof(batVoltage)); // 18 for ws 80, 17 for ws85
|
||||||
batVoltageF = strtof(batVoltage, nullptr);
|
batVoltageF = strtof(batVoltage, nullptr);
|
||||||
break; // last possible data we want so break
|
break; // last possible data we want so break
|
||||||
}
|
}
|
||||||
} else if (strstr(line, "CapVoltage") != NULL) { // we have a cappVoltage line
|
} else if (strstr(line, "CapVoltage") != NULL) { // we have a cappVoltage line
|
||||||
char *capVoltagePos = strstr(line, "CapVoltage = ");
|
char *capVoltagePos = strstr(line, "CapVoltage = ");
|
||||||
if (capVoltagePos != NULL) {
|
if (capVoltagePos != NULL) {
|
||||||
strcpy(capVoltage, capVoltagePos + 17); // 18 for ws 80, 17 for ws85
|
strlcpy(capVoltage, capVoltagePos + 17, sizeof(capVoltage)); // 18 for ws 80, 17 for ws85
|
||||||
capVoltageF = strtof(capVoltage, nullptr);
|
capVoltageF = strtof(capVoltage, nullptr);
|
||||||
}
|
}
|
||||||
// GXTS04Temp = 24.4
|
// GXTS04Temp = 24.4
|
||||||
} else if (strstr(line, "GXTS04Temp") != NULL) { // we have a temperature line
|
} else if (strstr(line, "GXTS04Temp") != NULL) { // we have a temperature line
|
||||||
char *tempPos = strstr(line, "GXTS04Temp = ");
|
char *tempPos = strstr(line, "GXTS04Temp = ");
|
||||||
if (tempPos != NULL) {
|
if (tempPos != NULL) {
|
||||||
strcpy(temperature, tempPos + 15); // 15 spaces for ws85
|
strlcpy(temperature, tempPos + 15, sizeof(temperature)); // 15 spaces for ws85
|
||||||
temperatureF = strtof(temperature, nullptr);
|
temperatureF = strtof(temperature, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (strstr(line, "RainIntSum") != NULL) { // we have a rainsum line
|
} 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.
|
|
||||||
// LOG_INFO(line);
|
// LOG_INFO(line);
|
||||||
char *pos = strstr(line, "Rain = ");
|
char *pos = strstr(line, "RainIntSum = ");
|
||||||
if (pos != NULL) {
|
if (pos != NULL) {
|
||||||
strcpy(rainStr, pos + 17); // 17 spaces for ws85
|
strlcpy(rainStr, pos + 17, sizeof(rainStr)); // 17 spaces for ws85
|
||||||
rain = strtof(rainStr, nullptr);
|
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
|
// Update lineStart for the next line
|
||||||
lineStart = lineEnd + 1;
|
lineStart = lineEnd + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -98,7 +98,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
|||||||
// moduleConfig.telemetry.environment_screen_enabled = 1;
|
// moduleConfig.telemetry.environment_screen_enabled = 1;
|
||||||
// moduleConfig.telemetry.environment_update_interval = 15;
|
// 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
|
// 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();
|
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
|
// This is the first time the OSThread library has called this function, so do some setup
|
||||||
firstTime = 0;
|
firstTime = 0;
|
||||||
|
|
||||||
if (moduleConfig.telemetry.environment_measurement_enabled) {
|
if (moduleConfig.telemetry.environment_measurement_enabled || ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE) {
|
||||||
LOG_INFO("Environment Telemetry: init");
|
LOG_INFO("Environment Telemetry: init");
|
||||||
#ifdef SENSECAP_INDICATOR
|
#ifdef SENSECAP_INDICATOR
|
||||||
result = indicatorSensor.runOnce();
|
result = indicatorSensor.runOnce();
|
||||||
@@ -178,7 +179,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
|||||||
return result == UINT32_MAX ? disable() : setStartDelay();
|
return result == UINT32_MAX ? disable() : setStartDelay();
|
||||||
} else {
|
} else {
|
||||||
// if we somehow got to a second run of this module with measurement disabled, then just wait forever
|
// 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();
|
return disable();
|
||||||
} else {
|
} else {
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||||
|
|||||||
@@ -3,6 +3,11 @@
|
|||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE
|
||||||
|
#define ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "ProtobufModule.h"
|
#include "ProtobufModule.h"
|
||||||
|
|||||||
@@ -160,13 +160,11 @@ class AccelerometerThread : public concurrency::OSThread
|
|||||||
void clean()
|
void clean()
|
||||||
{
|
{
|
||||||
isInitialised = false;
|
isInitialised = false;
|
||||||
if (sensor != nullptr) {
|
delete sensor;
|
||||||
delete sensor;
|
sensor = nullptr;
|
||||||
sensor = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#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
|
||||||
@@ -178,6 +178,8 @@
|
|||||||
#define HW_VENDOR meshtastic_HardwareModel_MESH_TAB
|
#define HW_VENDOR meshtastic_HardwareModel_MESH_TAB
|
||||||
#elif defined(T_ETH_ELITE)
|
#elif defined(T_ETH_ELITE)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_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
|
#endif
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include "nimble/NimbleBluetooth.h"
|
#include "nimble/NimbleBluetooth.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <WiFiOTA.h>
|
||||||
|
|
||||||
#if HAS_WIFI
|
#if HAS_WIFI
|
||||||
#include "mesh/wifi/WiFiAPClient.h"
|
#include "mesh/wifi/WiFiAPClient.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -139,12 +141,19 @@ void esp32Setup()
|
|||||||
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||||
String BLEOTA = BleOta::getOtaAppVersion();
|
String BLEOTA = BleOta::getOtaAppVersion();
|
||||||
if (BLEOTA.isEmpty()) {
|
if (BLEOTA.isEmpty()) {
|
||||||
LOG_INFO("No OTA firmware available");
|
LOG_INFO("No BLE OTA firmware available");
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("OTA firmware version %s", BLEOTA.c_str());
|
LOG_INFO("BLE OTA firmware version %s", BLEOTA.c_str());
|
||||||
}
|
}
|
||||||
#else
|
#endif
|
||||||
LOG_INFO("No OTA firmware available");
|
#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
|
#endif
|
||||||
|
|
||||||
// enableModemSleep();
|
// enableModemSleep();
|
||||||
|
|||||||
@@ -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_ */
|
||||||
File diff suppressed because it is too large
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;
|
delete screen;
|
||||||
LOG_DEBUG("final reboot!");
|
LOG_DEBUG("final reboot!");
|
||||||
reboot();
|
reboot();
|
||||||
|
#elif defined(ARCH_STM32WL)
|
||||||
|
HAL_NVIC_SystemReset();
|
||||||
#else
|
#else
|
||||||
rebootAtMsec = -1;
|
rebootAtMsec = -1;
|
||||||
LOG_WARN("FIXME implement reboot for this platform. Note that some settings require a restart to be applied");
|
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_WIDTH": "50",
|
||||||
// "USERPREFS_OEM_IMAGE_HEIGHT": "28",
|
// "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_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 "
|
"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.
|
; `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
|
platform = https://github.com/platformio/platform-ststm32.git#3208828db447f4373cd303b7f7393c8fc0dae623
|
||||||
board = ebyte_e77_dev
|
board = ebyte_e77_dev
|
||||||
|
board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem
|
||||||
board_level = extra
|
board_level = extra
|
||||||
build_flags =
|
build_flags =
|
||||||
${stm32_base.build_flags}
|
${stm32_base.build_flags}
|
||||||
@@ -11,31 +12,19 @@ build_flags =
|
|||||||
-DPIN_SERIAL_RX=PA3
|
-DPIN_SERIAL_RX=PA3
|
||||||
-DPIN_SERIAL_TX=PA2
|
-DPIN_SERIAL_TX=PA2
|
||||||
-DHAL_DAC_MODULE_ONLY
|
-DHAL_DAC_MODULE_ONLY
|
||||||
-DHAL_ADC_MODULE_DISABLED
|
-DHAL_RNG_MODULE_ENABLED
|
||||||
-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
|
|
||||||
-DRADIOLIB_EXCLUDE_SX128X=1
|
-DRADIOLIB_EXCLUDE_SX128X=1
|
||||||
-DRADIOLIB_EXCLUDE_SX127X=1
|
-DRADIOLIB_EXCLUDE_SX127X=1
|
||||||
-DRADIOLIB_EXCLUDE_LR11X0=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
|
upload_port = stlink
|
||||||
@@ -14,7 +14,6 @@ Do not expect a working Meshtastic device with this target.
|
|||||||
#define _VARIANT_EBYTE_E77_
|
#define _VARIANT_EBYTE_E77_
|
||||||
|
|
||||||
#define USE_STM32WLx
|
#define USE_STM32WLx
|
||||||
#define MAX_NUM_NODES 10
|
|
||||||
|
|
||||||
#define LED_PIN PB4 // LED1
|
#define LED_PIN PB4 // LED1
|
||||||
// #define LED_PIN PB3 // LED2
|
// #define LED_PIN PB3 // LED2
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ board_build.flash_mode = qio
|
|||||||
board_build.psram_type = opi
|
board_build.psram_type = opi
|
||||||
board_upload.flash_size = 8MB
|
board_upload.flash_size = 8MB
|
||||||
board_upload.maximum_size = 8388608
|
board_upload.maximum_size = 8388608
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
board = esp32-s3-devkitc-1
|
board = esp32-s3-devkitc-1
|
||||||
;upload_port = /dev/ttyUSB0
|
;upload_port = /dev/ttyUSB0
|
||||||
board_level = extra
|
board_level = extra
|
||||||
@@ -32,6 +33,7 @@ board_build.flash_mode = qio
|
|||||||
board_build.psram_type = opi
|
board_build.psram_type = opi
|
||||||
board_upload.flash_size = 8MB
|
board_upload.flash_size = 8MB
|
||||||
board_upload.maximum_size = 8388608
|
board_upload.maximum_size = 8388608
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
board = esp32-s3-devkitc-1
|
board = esp32-s3-devkitc-1
|
||||||
;upload_port = /dev/ttyUSB0
|
;upload_port = /dev/ttyUSB0
|
||||||
board_level = extra
|
board_level = extra
|
||||||
@@ -59,6 +61,7 @@ board_build.flash_mode = qio
|
|||||||
board_build.psram_type = opi
|
board_build.psram_type = opi
|
||||||
board_upload.flash_size = 8MB
|
board_upload.flash_size = 8MB
|
||||||
board_upload.maximum_size = 8388608
|
board_upload.maximum_size = 8388608
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
board = esp32-s3-devkitc-1
|
board = esp32-s3-devkitc-1
|
||||||
;upload_port = /dev/ttyUSB0
|
;upload_port = /dev/ttyUSB0
|
||||||
board_level = extra
|
board_level = extra
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ debug_tool = jlink
|
|||||||
[env:t-energy-s3_e22]
|
[env:t-energy-s3_e22]
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = esp32-s3-devkitc-1
|
board = esp32-s3-devkitc-1
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
board_level = extra
|
board_level = extra
|
||||||
board_upload.flash_size = 16MB ;Specify the FLASH capacity as 16MB
|
board_upload.flash_size = 16MB ;Specify the FLASH capacity as 16MB
|
||||||
board_build.arduino.memory_type = qio_opi ;Enable internal PSRAM
|
board_build.arduino.memory_type = qio_opi ;Enable internal PSRAM
|
||||||
@@ -100,4 +101,4 @@ build_flags =
|
|||||||
-D BOARD_HAS_PSRAM
|
-D BOARD_HAS_PSRAM
|
||||||
-D ARDUINO_USB_MODE=0
|
-D ARDUINO_USB_MODE=0
|
||||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-I variants/diy/t-energy-s3_e22
|
-I variants/diy/t-energy-s3_e22
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[env:dreamcatcher] ; 2301, latest revision
|
[env:dreamcatcher] ; 2301, latest revision
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = esp32s3box
|
board = esp32s3box
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
board_level = extra
|
board_level = extra
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
@@ -8,7 +9,7 @@ build_flags =
|
|||||||
-D PRIVATE_HW
|
-D PRIVATE_HW
|
||||||
-D OTHERNET_DC_REV=2301
|
-D OTHERNET_DC_REV=2301
|
||||||
-I variants/dreamcatcher
|
-I variants/dreamcatcher
|
||||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
|
|
||||||
lib_deps = ${esp32s3_base.lib_deps}
|
lib_deps = ${esp32s3_base.lib_deps}
|
||||||
earlephilhower/ESP8266Audio@^1.9.9
|
earlephilhower/ESP8266Audio@^1.9.9
|
||||||
@@ -17,6 +18,7 @@ lib_deps = ${esp32s3_base.lib_deps}
|
|||||||
[env:dreamcatcher-2206]
|
[env:dreamcatcher-2206]
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = esp32s3box
|
board = esp32s3box
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
board_level = extra
|
board_level = extra
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
@@ -24,4 +26,4 @@ build_flags =
|
|||||||
-D PRIVATE_HW
|
-D PRIVATE_HW
|
||||||
-D OTHERNET_DC_REV=2206
|
-D OTHERNET_DC_REV=2206
|
||||||
-I variants/dreamcatcher
|
-I variants/dreamcatcher
|
||||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ board_level = extra
|
|||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
board = esp32-s3-pico
|
board = esp32-s3-pico
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
|
|
||||||
board_upload.use_1200bps_touch = yes
|
board_upload.use_1200bps_touch = yes
|
||||||
board_upload.wait_for_upload_port = yes
|
board_upload.wait_for_upload_port = yes
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = heltec_wifi_lora_32_V3
|
board = heltec_wifi_lora_32_V3
|
||||||
board_check = true
|
board_check = true
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags} -I variants/heltec_capsule_sensor_v3
|
${esp32s3_base.build_flags} -I variants/heltec_capsule_sensor_v3
|
||||||
-D HELTEC_CAPSULE_SENSOR_V3
|
-D HELTEC_CAPSULE_SENSOR_V3
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = heltec_wifi_lora_32_V3
|
board = heltec_wifi_lora_32_V3
|
||||||
board_check = true
|
board_check = true
|
||||||
# Temporary until espressif creates a release with this new target
|
board_build.partitions = default_8MB.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/heltec_v3
|
${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/heltec_v3
|
||||||
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
-D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
[env:heltec-vision-master-e213]
|
[env:heltec-vision-master-e213]
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = heltec_vision_master_e213
|
board = heltec_vision_master_e213
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags}
|
${esp32s3_base.build_flags}
|
||||||
-Ivariants/heltec_vision_master_e213
|
-Ivariants/heltec_vision_master_e213
|
||||||
-DHELTEC_VISION_MASTER_E213
|
-DHELTEC_VISION_MASTER_E213
|
||||||
-DUSE_EINK
|
-DUSE_EINK
|
||||||
@@ -22,6 +23,7 @@ upload_speed = 115200
|
|||||||
[env:heltec-vision-master-e213-inkhud]
|
[env:heltec-vision-master-e213-inkhud]
|
||||||
extends = esp32s3_base, inkhud
|
extends = esp32s3_base, inkhud
|
||||||
board = heltec_vision_master_e213
|
board = heltec_vision_master_e213
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${esp32_base.build_src_filter}
|
${esp32_base.build_src_filter}
|
||||||
${inkhud.build_src_filter}
|
${inkhud.build_src_filter}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
[env:heltec-vision-master-e290]
|
[env:heltec-vision-master-e290]
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = heltec_vision_master_e290
|
board = heltec_vision_master_e290
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags}
|
${esp32s3_base.build_flags}
|
||||||
-I variants/heltec_vision_master_e290
|
-I variants/heltec_vision_master_e290
|
||||||
@@ -26,6 +27,7 @@ upload_speed = 115200
|
|||||||
[env:heltec-vision-master-e290-inkhud]
|
[env:heltec-vision-master-e290-inkhud]
|
||||||
extends = esp32s3_base, inkhud
|
extends = esp32s3_base, inkhud
|
||||||
board = heltec_vision_master_e290
|
board = heltec_vision_master_e290
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${esp32_base.build_src_filter}
|
${esp32_base.build_src_filter}
|
||||||
${inkhud.build_src_filter}
|
${inkhud.build_src_filter}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
[env:heltec-vision-master-t190]
|
[env:heltec-vision-master-t190]
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = heltec_vision_master_t190
|
board = heltec_vision_master_t190
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags}
|
${esp32s3_base.build_flags}
|
||||||
-Ivariants/heltec_vision_master_t190
|
-Ivariants/heltec_vision_master_t190
|
||||||
-DHELTEC_VISION_MASTER_T190
|
-DHELTEC_VISION_MASTER_T190
|
||||||
; -D PRIVATE_HW
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${esp32s3_base.lib_deps}
|
${esp32s3_base.lib_deps}
|
||||||
lewisxhe/PCF8563_Library@^1.0.1
|
lewisxhe/PCF8563_Library@^1.0.1
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
[env:heltec-wireless-paper]
|
[env:heltec-wireless-paper]
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = heltec_wifi_lora_32_V3
|
board = heltec_wifi_lora_32_V3
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags}
|
${esp32s3_base.build_flags}
|
||||||
-I variants/heltec_wireless_paper
|
-I variants/heltec_wireless_paper
|
||||||
@@ -23,6 +24,7 @@ upload_speed = 115200
|
|||||||
[env:heltec-wireless-paper-inkhud]
|
[env:heltec-wireless-paper-inkhud]
|
||||||
extends = esp32s3_base, inkhud
|
extends = esp32s3_base, inkhud
|
||||||
board = heltec_wifi_lora_32_V3
|
board = heltec_wifi_lora_32_V3
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${esp32_base.build_src_filter}
|
${esp32_base.build_src_filter}
|
||||||
${inkhud.build_src_filter}
|
${inkhud.build_src_filter}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board_level = extra
|
board_level = extra
|
||||||
board = heltec_wifi_lora_32_V3
|
board = heltec_wifi_lora_32_V3
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags}
|
${esp32s3_base.build_flags}
|
||||||
-I variants/heltec_wireless_paper_v1
|
-I variants/heltec_wireless_paper_v1
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[env:heltec-wireless-tracker]
|
[env:heltec-wireless-tracker]
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = heltec_wireless_tracker
|
board = heltec_wireless_tracker
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board_level = extra
|
board_level = extra
|
||||||
board = heltec_wireless_tracker
|
board = heltec_wireless_tracker
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags} -I variants/heltec_wireless_tracker_V1_0
|
${esp32s3_base.build_flags} -I variants/heltec_wireless_tracker_V1_0
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
[env:heltec-wsl-v3]
|
[env:heltec-wsl-v3]
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = heltec_wifi_lora_32_V3
|
board = heltec_wifi_lora_32_V3
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
# Temporary until espressif creates a release with this new target
|
# Temporary until espressif creates a release with this new target
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags} -D HELTEC_WSL_V3 -I variants/heltec_wsl_v3
|
${esp32s3_base.build_flags} -D HELTEC_WSL_V3 -I variants/heltec_wsl_v3
|
||||||
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
-D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ board = icarus
|
|||||||
board_level = extra
|
board_level = extra
|
||||||
board_check = true
|
board_check = true
|
||||||
board_build.mcu = esp32s3
|
board_build.mcu = esp32s3
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
platform_packages = platformio/framework-arduinoespressif32@https://github.com/PowerFeather/powerfeather-meshtastic-arduino-lib/releases/download/2.0.16a/esp32-2.0.16.zip
|
platform_packages = platformio/framework-arduinoespressif32@https://github.com/PowerFeather/powerfeather-meshtastic-arduino-lib/releases/download/2.0.16a/esp32-2.0.16.zip
|
||||||
@@ -15,5 +16,4 @@ build_unflags =
|
|||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags} -D PRIVATE_HW -I variants/icarus
|
${esp32s3_base.build_flags} -D PRIVATE_HW -I variants/icarus
|
||||||
-DBOARD_HAS_PSRAM
|
-DBOARD_HAS_PSRAM
|
||||||
|
-DARDUINO_USB_MODE=0
|
||||||
-DARDUINO_USB_MODE=0
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = m5stack-cores3
|
board = m5stack-cores3
|
||||||
board_check = true
|
board_check = true
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
|
|
||||||
build_flags = ${esp32_base.build_flags}
|
build_flags = ${esp32_base.build_flags}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ build_flags = ${esp32s3_base.build_flags}
|
|||||||
-D USE_LOG_DEBUG
|
-D USE_LOG_DEBUG
|
||||||
-D LOG_DEBUG_INC=\"DebugConfiguration.h\"
|
-D LOG_DEBUG_INC=\"DebugConfiguration.h\"
|
||||||
-D RADIOLIB_SPI_PARANOID=0
|
-D RADIOLIB_SPI_PARANOID=0
|
||||||
-D MAX_NUM_NODES=250
|
|
||||||
-D MAX_THREADS=40
|
-D MAX_THREADS=40
|
||||||
-D HAS_SCREEN=0
|
-D HAS_SCREEN=0
|
||||||
-D HAS_TFT=1
|
-D HAS_TFT=1
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = bpi_picow_esp32_s3
|
board = bpi_picow_esp32_s3
|
||||||
board_check = true
|
board_check = true
|
||||||
|
board_build.partitions = default_8MB.csv
|
||||||
;OpenOCD flash method
|
;OpenOCD flash method
|
||||||
;upload_protocol = esp-builtin
|
;upload_protocol = esp-builtin
|
||||||
;Normal method
|
;Normal method
|
||||||
@@ -22,7 +23,6 @@ build_src_filter =
|
|||||||
|
|
||||||
[env:picomputer-s3-tft]
|
[env:picomputer-s3-tft]
|
||||||
extends = env:picomputer-s3
|
extends = env:picomputer-s3
|
||||||
board_build.partitions = default_8MB.csv ; just for test
|
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
${env:picomputer-s3.build_flags}
|
${env:picomputer-s3.build_flags}
|
||||||
@@ -35,7 +35,6 @@ build_flags =
|
|||||||
-D INPUTDRIVER_MATRIX_TYPE=1
|
-D INPUTDRIVER_MATRIX_TYPE=1
|
||||||
-D USE_PIN_BUZZER=PIN_BUZZER
|
-D USE_PIN_BUZZER=PIN_BUZZER
|
||||||
-D USE_SX127x
|
-D USE_SX127x
|
||||||
-D MAX_NUM_NODES=200
|
|
||||||
-D HAS_SCREEN=0
|
-D HAS_SCREEN=0
|
||||||
-D HAS_TFT=1
|
-D HAS_TFT=1
|
||||||
-D RAM_SIZE=1024
|
-D RAM_SIZE=1024
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ build_flags = ${native_base.build_flags} -Os -lX11 -linput -lxkbcommon -ffunctio
|
|||||||
-D USE_X11=1
|
-D USE_X11=1
|
||||||
-D HAS_TFT=1
|
-D HAS_TFT=1
|
||||||
-D HAS_SCREEN=0
|
-D HAS_SCREEN=0
|
||||||
|
-D LV_CACHE_DEF_SIZE=6291456
|
||||||
-D LV_BUILD_TEST=0
|
-D LV_BUILD_TEST=0
|
||||||
-D LV_USE_LIBINPUT=1
|
-D LV_USE_LIBINPUT=1
|
||||||
-D LV_LVGL_H_INCLUDE_SIMPLE
|
-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 USE_X11=1
|
||||||
-D HAS_TFT=1
|
-D HAS_TFT=1
|
||||||
-D HAS_SCREEN=0
|
-D HAS_SCREEN=0
|
||||||
; -D CALIBRATE_TOUCH=0
|
-D LV_CACHE_DEF_SIZE=6291456
|
||||||
-D LV_BUILD_TEST=0
|
-D LV_BUILD_TEST=0
|
||||||
-D LV_USE_LOG=1
|
-D LV_USE_LOG=1
|
||||||
-D LV_USE_SYSMON=1
|
-D LV_USE_SYSMON=1
|
||||||
|
|||||||
@@ -1,36 +1,23 @@
|
|||||||
[env:rak3172]
|
[env:rak3172]
|
||||||
extends = stm32_base
|
extends = stm32_base
|
||||||
board = wiscore_rak3172
|
board = wiscore_rak3172
|
||||||
|
board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem
|
||||||
build_flags =
|
build_flags =
|
||||||
${stm32_base.build_flags}
|
${stm32_base.build_flags}
|
||||||
-Ivariants/rak3172
|
-Ivariants/rak3172
|
||||||
-DSERIAL_UART_INSTANCE=1
|
|
||||||
-DPIN_SERIAL_RX=PB7
|
|
||||||
-DPIN_SERIAL_TX=PB6
|
|
||||||
-DHAL_DAC_MODULE_ONLY
|
-DHAL_DAC_MODULE_ONLY
|
||||||
-DHAL_ADC_MODULE_DISABLED
|
-DHAL_RNG_MODULE_ENABLED
|
||||||
-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
|
|
||||||
-DRADIOLIB_EXCLUDE_SX128X=1
|
-DRADIOLIB_EXCLUDE_SX128X=1
|
||||||
-DRADIOLIB_EXCLUDE_SX127X=1
|
-DRADIOLIB_EXCLUDE_SX127X=1
|
||||||
-DRADIOLIB_EXCLUDE_LR11X0=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.
|
This variant is a work in progress.
|
||||||
Do not expect a working Meshtastic device with this target.
|
Do not expect a working Meshtastic device with this target.
|
||||||
@@ -7,6 +12,8 @@ Do not expect a working Meshtastic device with this target.
|
|||||||
#define _VARIANT_RAK3172_
|
#define _VARIANT_RAK3172_
|
||||||
|
|
||||||
#define USE_STM32WLx
|
#define USE_STM32WLx
|
||||||
#define MAX_NUM_NODES 10
|
|
||||||
|
|
||||||
#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
|
-DHAS_WIFI=1
|
||||||
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m33"
|
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m33"
|
||||||
-fexceptions # for exception handling in MQTT
|
-fexceptions # for exception handling in MQTT
|
||||||
|
-DHAS_UDP_MULTICAST=1
|
||||||
build_src_filter = ${rp2350_base.build_src_filter} +<mesh/wifi/>
|
build_src_filter = ${rp2350_base.build_src_filter} +<mesh/wifi/>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${rp2350_base.lib_deps}
|
${rp2350_base.lib_deps}
|
||||||
${networking_base.lib_deps}
|
${networking_base.lib_deps}
|
||||||
debug_build_flags = ${rp2350_base.build_flags}, -g
|
debug_build_flags = ${rp2350_base.build_flags}, -g
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user