Compare commits

..

105 Commits

Author SHA1 Message Date
Ben Meadors
dc2ca9c32b Report special battery_level of > 100 instead of zero to indicate USB (#2341)
* Report special battery_level of > 100 instead of zero to indicate USB

* Protos

* Helps if you click save

* Wrong method

* Fmt
2023-03-10 19:50:08 -06:00
Ben Meadors
fddc49273e Reboot seconds bump 2023-03-09 16:08:18 -06:00
Ben Meadors
e737a22120 Platform updates (#2340)
* 6.1.0

* Update libs

* Update nrf52 while we're at it

* Remove temporary heltec platform packages

* Update install scripts to flash s3 ota partition bin
2023-03-09 12:45:38 -06:00
Thomas Göttgens
a8f2e3ddbd pack the bleota-s3 in the omnibus zip 2023-03-09 09:10:16 +01:00
Thomas Göttgens
67be6aa53b fmt 2023-03-09 09:04:08 +01:00
Thomas Göttgens
68e17ab905 avoid a couple of downloads and build seconds by building the littlefs for the current target instead of 'tbeam' 2023-03-09 09:00:59 +01:00
Thomas Göttgens
a56403987b use the s3 build script 2023-03-09 08:45:49 +01:00
Thomas Göttgens
7acacb3bba Add a separate workflow for s3 boards
they use the same batch file but require a different OTA firmware.
2023-03-09 08:45:49 +01:00
A. Rager
e6d69e2b67 Refactor i2cScan.h To Handle 2 Bus (#2337)
* Break i2cScan out into a set of classes for scanning i2c

* refactor i2cscan addresses to be structs that allow addressing by port + address

* build whoopsies

* trunk fmt

* trunk fmt

* lost some build fixes from the merge

* more cleaning for build safety, RTC behavior
2023-03-08 21:13:46 -06:00
Thomas Göttgens
9150c2e568 fix stuff i somehow inadvertently broke. 2023-03-08 17:12:25 +01:00
Thomas Göttgens
944d5066e9 update lib dependency 2023-03-08 17:12:25 +01:00
Thomas Göttgens
a538a96c90 fmt 2023-03-08 17:12:25 +01:00
Thomas Göttgens
31ef82557f try revert protos 2023-03-08 17:12:25 +01:00
Thomas Göttgens
9d440b7dba revert overcommit 2023-03-08 17:12:25 +01:00
Thomas Göttgens
267db05d69 - G1 Explorer use correct display controller
- adhere UA font in modules
2023-03-08 17:12:25 +01:00
github-actions[bot]
20bcf310d1 [create-pull-request] automated change (#2334)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-03-06 17:09:41 -06:00
Ben Meadors
331a1afc37 Update minor for new release 2023-03-06 16:17:31 -06:00
Ben Meadors
321e41a3aa Update protos 2023-03-06 16:17:09 -06:00
GUVWAF
3ca1e62b1f SX126x/8x: Add HEADER_VALID IRQ flag for actively receiving check (#2333)
* Add HEADER_VALID IRQ flag for SX126x/8x to detect actively receiving
Needs new RadioLib commit

* Update comments

* Use latest RadioLib release

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-03-06 15:53:59 -06:00
Thomas Göttgens
5044169e8d fixes #2330 2023-03-06 14:12:24 +01:00
Thomas Göttgens
8e197fc35b fixes #2327 2023-03-06 12:50:05 +01:00
A. Rager
f63505038f add psram for lilygo t3 s3 2023-03-06 12:44:51 +01:00
Thomas Göttgens
4a0dfb5401 T3S3-1.1 SX1276 config (and cosmetic change for SX1280 in PA mode) 2023-03-04 18:39:19 +01:00
GUVWAF
eb4ab26e1f Check if packet is decrypted before searching node in DB (#2320)
* Check whether TraceRouteModule exists
In case in the future we don't enable it

* Check whether packet is decrypted before searching node in DB
2023-03-02 13:22:14 -06:00
github-actions[bot]
8c059a8a9e [create-pull-request] automated change (#2317)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-03-02 08:34:00 -06:00
github-actions[bot]
7bb281d5c5 [create-pull-request] automated change (#2316)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-03-01 12:31:58 -06:00
A. Rager
214feb1f21 Add Hardware: BetaFPV 900 Nano TX (#2249)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-03-01 08:36:25 -06:00
Ben Meadors
d17aafa91a Trying to debug transient "disconnects" in iOS (#2312)
* Add back lines from original Adafruit example sketch

* Stop advertising debug message

* Yank it
2023-03-01 08:35:52 -06:00
code8buster
2fe5eae183 Fix overlapping of GPS message on screen carousel #1 (#2314)
* Fix overlapping of GPS message on screen carousel #1

* Any reason we shouldn't display this on a RAK w/ E-ink or similar non-PMU equipped boards?

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-03-01 08:34:07 -06:00
Manuel
9008c75517 Fixed: Tlora-t3s3-v1 SX1262 firmware reboots continuously (#2308) (#2315) 2023-02-28 07:45:10 -06:00
GUVWAF
408c555f0f Add airtime of current received/transmitted packet to nextTx time of all pending retransmissions (#2309)
To avoid unnecessary retransmissions when sending them too early

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-02-25 19:51:38 -06:00
github-actions[bot]
c9ae90f03c [create-pull-request] automated change (#2306)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-02-24 15:07:39 -06:00
Ben Meadors
fbfd0f12b5 Change to 5 minutes for Garth's sanity 2023-02-24 12:49:10 -06:00
Ben Meadors
9650adb616 Set reasonable defaults for sensor role and adjust packet priority (#2305) 2023-02-24 11:25:50 -06:00
Thomas Göttgens
fab5e4c5cc potential fix for Range Test Leak. Poking around in the dark. 2023-02-23 22:19:23 +01:00
Ben Meadors
46fa08dc33 Air quality specific prefs (#2303) 2023-02-23 13:05:24 -06:00
github-actions[bot]
05b1fc83bd [create-pull-request] automated change (#2300)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2023-02-22 16:16:38 -06:00
Thomas Göttgens
9fc18c2a19 Merge pull request #2295 from meshtastic/2228-bug-heap-leak-in-rangetestmodule
tryfix #2228 as suggested by @mverch67
2023-02-21 20:40:20 +01:00
Thomas Göttgens
d830398fc5 Check if there's something there before we free it 2023-02-21 20:01:56 +01:00
Thomas Göttgens
2e80a4ed87 tryfix #2228 as suggested by @mverch67 2023-02-21 14:53:27 +01:00
Ben Meadors
e1924f188f Remove extra 2023-02-21 07:18:08 -06:00
github-actions[bot]
732caff2b8 [create-pull-request] automated change (#2294)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-02-21 06:23:02 -06:00
Ben Meadors
c60c00ba85 Add da explora 2023-02-20 16:23:02 -06:00
GUVWAF
83e6cea280 RadioLib's startChannel returns LORA_DETECTED for SX126x and SX128x (#2293) 2023-02-20 14:11:54 -06:00
Ben Meadors
f8498ba03f Trunk fix 2023-02-20 12:33:01 -06:00
Ben Meadors
f83adf1796 Trunk fmt 2023-02-20 10:05:11 -06:00
Krezalis
73c1c5913b Update Screen.h (#2285)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-02-20 10:03:32 -06:00
Krezalis
fd1c54fd15 Add Ukrainian symbols (#2286)
* Update Screen.cpp

* Add files via upload

* Update Screen.cpp

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-02-20 10:03:13 -06:00
GUVWAF
95bbcd2cb7 Use LORA_DIO1 as RadioLib GPIO for SX127x chips (#2290)
* When channel is active, first try receiving that packet
Afterwards we'll try transmitting again

* Remove setStandby in startSend
Already done in isChannelActive()

* Set LORA_DIO1 as RadioLib GPIO for SX127x

* LORA_DIO1 for Heltec v1, overlaps with GPS_TX
Set to RADIOLIB_NC for now

* If receive was not successful, startReceive doesn't trigger the interrupt
So we have to go back to transmitting anyway

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2023-02-20 07:40:44 -06:00
Ben Meadors
187f3969c2 Missed a reference 2023-02-20 07:22:33 -06:00
Ben Meadors
15458309f8 Remove pico from build for now 2023-02-20 07:20:14 -06:00
Ben Meadors
253d133319 Merge pull request #2287 from neilhao/master
Nano G1 Explorer
2023-02-18 19:06:37 -06:00
Ben Meadors
7264621149 Don't auto set to default primary channel 2023-02-18 18:32:46 -06:00
Neil Hao
27d93c5f66 Update extensions.json 2023-02-18 05:00:43 +08:00
neil
b33632f21a 'nano-g1-explorer' 2023-02-18 04:49:37 +08:00
Ben Meadors
89f06d6b40 Merge pull request #2283 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2023-02-17 06:52:37 -06:00
thebentern
7102fec7b3 [create-pull-request] automated change 2023-02-17 12:50:01 +00:00
Ben Meadors
c39645419a Merge pull request #2279 from meshtastic/preamble-halving
Preamble change
2023-02-16 20:42:05 -06:00
Ben Meadors
6f4ac904a5 Merge branch 'master' into preamble-halving 2023-02-16 19:26:48 -06:00
Ben Meadors
643237162e Regen protos 2023-02-16 19:26:21 -06:00
Ben Meadors
cef11968eb Merge branch 'master' into preamble-halving 2023-02-16 19:09:47 -06:00
Ben Meadors
5c72967aa5 Merge pull request #2278 from meshtastic/metadata-phone-api
Add metadata to phone api want config messages
2023-02-16 19:09:37 -06:00
GUVWAF
8aede61adb Fix setting preambleLength for SX127x
Don't set currentLimit, it is set automatically in begin()
2023-02-16 20:58:10 +01:00
Ben Meadors
07b90a61e1 For science 2023-02-16 13:51:20 -06:00
Ben Meadors
221a145d2d Whoops 2023-02-16 12:58:54 -06:00
Ben Meadors
b3fac71a8d Missed some stuff 2023-02-16 12:52:03 -06:00
Ben Meadors
2e6e0644d4 Move it around and kill old device metadata gen 2023-02-16 12:18:27 -06:00
Ben Meadors
b78e0dce46 Merge branch 'master' into metadata-phone-api 2023-02-16 10:21:31 -06:00
Ben Meadors
3ae1fdf661 Add metadata to phone api want config messages 2023-02-16 10:21:03 -06:00
Ben Meadors
cbfa2dcc0e Merge pull request #2276 from GUVWAF/NodeInfoSanityCheck
Sanity check for sending NodeInfo
2023-02-16 10:20:16 -06:00
Ben Meadors
2aabeafefe Merge branch 'master' into NodeInfoSanityCheck 2023-02-15 12:42:39 -06:00
GUVWAF
b7895f7038 Sanity check for sending NodeInfo
Don't send it if we've done so less than 1 min. ago
2023-02-15 19:31:09 +01:00
Ben Meadors
3f4780479f Merge pull request #2274 from GUVWAF/roleFixes
NodeInfo fixes for other roles
2023-02-11 19:25:04 -06:00
GUVWAF
5ca3d9169a Only set node_info_broadcast_secs when not a Router 2023-02-11 17:17:11 +01:00
GUVWAF
c834252f1c Check if nodeInfoModule exists (e.g. for Repeater) 2023-02-11 17:16:48 +01:00
GUVWAF
16852da8d4 Set node_info_broadcast_secs to 3 hours instead of default_broadcast_interval 2023-02-11 15:58:26 +01:00
GUVWAF
2d2633d4cf Increase default NodeInfo broadcast to 3 hours 2023-02-11 15:58:26 +01:00
GUVWAF
5f28ef6814 When hearing a node we don't know, send NodeInfo and ask for response 2023-02-11 15:58:26 +01:00
GUVWAF
5cadcd355f Send DeviceTelemetry only after NodeInfo is sent 2023-02-11 15:58:26 +01:00
GUVWAF
40d98b9d8d Merge pull request #2272 from GUVWAF/portduinoDeviceTelemetry
Enable DeviceTelemetry on Portduino
2023-02-11 15:21:24 +01:00
Ben Meadors
0f47584a50 Merge branch 'master' into portduinoDeviceTelemetry 2023-02-11 06:56:23 -06:00
Ben Meadors
dbb827e5e0 Merge pull request #2271 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2023-02-11 06:43:54 -06:00
Ben Meadors
f95061b965 Merge branch 'master' into create-pull-request/patch 2023-02-11 06:43:46 -06:00
GUVWAF
4061870841 Don't need a Portduino guard clause here as it will not be compiled 2023-02-11 12:04:53 +01:00
GUVWAF
abf3a5840b trunk fmt 2023-02-11 11:46:54 +01:00
GUVWAF
7063acdda6 Ignore syslog on portduino
Breaks when running since mesh/http is not compiled
2023-02-11 11:32:10 +01:00
GUVWAF
97c1cf628a SimRadio in separate thread
To use notifyLater when transmitting, fixes packetPool issues
2023-02-11 10:34:08 +01:00
GUVWAF
03f584a5ab Add HAS_TELEMETRY to portduino 2023-02-11 10:09:48 +01:00
GUVWAF
680550b76c Add HAS_SENSOR flag
To separate DeviceTelemetry and EnvironmentTelemetry
2023-02-11 10:08:25 +01:00
GUVWAF
a280d7f796 Guard simulator handling with HAS_RADIO flag 2023-02-11 10:00:19 +01:00
Ben Meadors
09f2ea8938 Portduino isn't extra. It's extra special 2023-02-10 07:47:43 -06:00
thebentern
fcbeeac28f [create-pull-request] automated change 2023-02-10 13:30:51 +00:00
Ben Meadors
7100416142 Add short_name 2023-02-09 19:32:32 -06:00
Thomas Göttgens
83e309f3bf label boards as secondary to split the core firmware archive by support level.
Ref: https://docs.platformio.org/en/latest/scripting/examples/platformio_ini_custom_options.html
2023-02-10 01:35:25 +01:00
Thomas Göttgens
dc6f6af7fb Update to Espressif32 Platform 6.0 and ESP-IDF 5.0 2023-02-10 00:21:15 +01:00
Ben Meadors
aaba99f792 Add changed back 2023-02-09 10:48:17 -06:00
Ben Meadors
4375a0101e Remove setOwner's business logic for licensed operation 2023-02-09 08:58:28 -06:00
Ben Meadors
b1677e0312 Rebroadcast mode to local_only for hams 2023-02-09 07:51:41 -06:00
Ben Meadors
0c240a1dff Merge pull request #2266 from meshtastic/nodeinfo
Ham mode should broadcast in plaintext and nodeinfo every 10 minutes
2023-02-08 21:07:17 -06:00
Ben Meadors
b24376b1fc Well it helps if I commit the thing 2023-02-08 20:21:33 -06:00
Ben Meadors
bcaf834853 Interval or default 2023-02-08 18:04:21 -06:00
Ben Meadors
1c3970efab Default node info broadcast secs for ham operation 2023-02-08 15:36:23 -06:00
Ben Meadors
79850c6d03 Set open psk for ham mode 2023-02-08 15:29:33 -06:00
Ben Meadors
440074af62 Merge pull request #2263 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2023-02-07 20:03:21 -06:00
thebentern
dc23096723 [create-pull-request] automated change 2023-02-07 21:59:05 +00:00
121 changed files with 1892 additions and 760 deletions

59
.github/workflows/build_esp32_s3.yml vendored Normal file
View File

@@ -0,0 +1,59 @@
name: Build ESP32-S3
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-esp32-s3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "meshtastic/web"
file: "build.tar"
target: "build.tar"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "meshtastic/firmware-ota"
file: "firmware-s3.bin"
target: "release/bleota-s3.bin"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v3
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.bin
release/*.elf

View File

@@ -62,8 +62,6 @@ jobs:
- board: heltec-v1
- board: heltec-v2.0
- board: heltec-v2.1
- board: heltec-v3
- board: heltec-wsl-v3
- board: tbeam0.7
- board: meshtastic-diy-v1
- board: meshtastic-dr-dev
@@ -71,9 +69,21 @@ jobs:
- board: station-g1
- board: m5stack-core
- board: m5stack-coreink
- board: nano-g1-explorer
uses: ./.github/workflows/build_esp32.yml
with:
board: ${{ matrix.board }}
build-esp32-s3:
strategy:
fail-fast: false
matrix:
include:
- board: heltec-v3
- board: heltec-wsl-v3
- board: tbeam-s3-core
- board: tlora-t3s3-v1
uses: ./.github/workflows/build_esp32.yml
uses: ./.github/workflows/build_esp32_s3.yml
with:
board: ${{ matrix.board }}
@@ -92,16 +102,16 @@ jobs:
with:
board: ${{ matrix.board }}
build-rpi2040:
strategy:
fail-fast: false
max-parallel: 2
matrix:
include:
- board: pico
uses: ./.github/workflows/build_rpi2040.yml
with:
board: ${{ matrix.board }}
# build-rpi2040:
# strategy:
# fail-fast: false
# max-parallel: 2
# matrix:
# include:
# - board: pico
# uses: ./.github/workflows/build_rpi2040.yml
# with:
# board: ${{ matrix.board }}
build-native:
runs-on: ubuntu-latest
@@ -175,7 +185,7 @@ jobs:
gather-artifacts:
runs-on: ubuntu-latest
needs: [build-esp32, build-nrf52, build-native, build-rpi2040]
needs: [build-esp32, build-esp32-s3, build-nrf52, build-native] #, build-rpi2040]
steps:
- name: Checkout code
uses: actions/checkout@v3
@@ -192,7 +202,7 @@ jobs:
id: version
- name: Move files up
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v3

View File

@@ -1,7 +1,7 @@
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base
platform = platformio/espressif32@^5.2.0
platform = platformio/espressif32@^6.1.0
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
upload_speed = 921600
@@ -26,7 +26,7 @@ build_flags =
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DDEBUG_HEAP
;-DDEBUG_HEAP
lib_deps =
${arduino_base.lib_deps}

View File

@@ -1,6 +1,6 @@
[esp32s2_base]
extends = arduino_base
platform = platformio/espressif32@^5.2.0
platform = platformio/espressif32@^6.1.0
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<nimble/>
upload_speed = 961200
@@ -27,7 +27,7 @@ build_flags =
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DHAS_BLUETOOTH=0
-DDEBUG_HEAP
;-DDEBUG_HEAP
lib_deps =
${arduino_base.lib_deps}

View File

@@ -1,6 +1,6 @@
[esp32s3_base]
extends = arduino_base
platform = platformio/espressif32@^5.2.0
platform = platformio/espressif32@^6.1.0
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
upload_speed = 961200
@@ -26,7 +26,7 @@ build_flags =
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DDEBUG_HEAP
;-DDEBUG_HEAP
lib_deps =
${arduino_base.lib_deps}

View File

@@ -1,6 +1,6 @@
[nrf52_base]
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
platform = platformio/nordicnrf52@^9.4.0
platform = platformio/nordicnrf52@^9.5.0
extends = arduino_base
build_type = debug ; I'm debugging with ICE a lot now

View File

@@ -12,7 +12,9 @@ build_src_filter =
-<mesh/http/>
-<mesh/eth/>
-<modules/esp32>
-<modules/Telemetry>
-<modules/Telemetry/EnvironmentTelemetry.cpp>
-<modules/Telemetry/AirQualityTelemetry.cpp>
-<modules/Telemetry/Sensor>
+<../variants/portduino>
lib_deps =
${env.lib_deps}

View File

@@ -34,7 +34,7 @@ SRCBIN=.pio/build/$1/firmware.bin
cp $SRCBIN $OUTDIR/$basename-update.bin
echo "Building Filesystem for ESP32 targets"
pio run --environment tbeam -t buildfs
cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
pio run --environment $1 -t buildfs
cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR

View File

@@ -30,7 +30,13 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
%PYTHON% -m esptool --baud 115200 erase_flash
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
@REM Account for S3 board's different OTA partition
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
) else (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin
)
for %%f in (littlefs-*.bin) do (
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
)

View File

@@ -49,7 +49,12 @@ if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
"$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
# Account for S3 board's different OTA partition
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ]; then
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
else
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
fi
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
else

View File

@@ -9,12 +9,13 @@
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
"-DARDUINO_EVENT_RUNNING_CORE=1",
"-DBOARD_HAS_PSRAM"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
"hwids": [["0X303A", "0x1001"]],
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "tlora-t3s3-v1"
},

View File

@@ -13,6 +13,7 @@ default_envs = tbeam
;default_envs = tlora_v1_3
;default_envs = tlora-v2
;default_envs = tlora-v2-1-1.6
;default_envs = tlora-t3s3-v1
;default_envs = lora-relay-v1 # nrf board
;default_envs = t-echo
;default_envs = nrf52840dk-geeksville
@@ -58,15 +59,14 @@ build_flags = -Wno-missing-field-initializers
monitor_speed = 115200
lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#da1ede4dfcd91074283b029080759fd744120909 ; ESP8266_SSD1306
https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
nanopb/Nanopb@^0.4.6
nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1
; jgromes/RadioLib@^5.5.1
https://github.com/jgromes/RadioLib.git#1afa947030c5637f71f6563bc22aa75032e53a57
jgromes/RadioLib@^5.7.0
; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck
@@ -100,7 +100,7 @@ lib_deps =
[environmental_base]
lib_deps =
adafruit/Adafruit BusIO@^1.11.4
adafruit/Adafruit Unified Sensor@^1.1.4
adafruit/Adafruit Unified Sensor@^1.1.9
adafruit/Adafruit BMP280 Library@^2.6.6
adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BME680 Library@^2.0.1

View File

@@ -2,6 +2,6 @@
#ifdef USE_RF95
#define RF95_RESET LORA_RESET
#define RF95_IRQ LORA_DIO0 // on SX1262 version this is a no connect DIO0
#define RF95_DIO1 LORA_DIO1 // Note: not really used for RF95
#define RF95_DIO1 LORA_DIO1 // Note: not really used for RF95, but used for pure SX127x
#define RF95_DIO2 LORA_DIO2 // Note: not really used for RF95
#endif

View File

@@ -103,7 +103,7 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
}
r += vprintf(format, arg);
#if HAS_WIFI || HAS_ETHERNET
#if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO)
// if syslog is in use, collect the log messages and send them to syslog
if (syslog.isEnabled()) {
int ll = 0;

70
src/detect/ScanI2C.cpp Normal file
View File

@@ -0,0 +1,70 @@
#include "ScanI2C.h"
const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress();
const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE);
ScanI2C::ScanI2C() = default;
void ScanI2C::scanPort(ScanI2C::I2CPort port) {}
void ScanI2C::setSuppressScreen()
{
shouldSuppressScreen = true;
}
ScanI2C::FoundDevice ScanI2C::firstScreen() const
{
// Allow to override the scanner results for screen
if (shouldSuppressScreen)
return DEVICE_NONE;
ScanI2C::DeviceType types[] = {SCREEN_SSD1306, SCREEN_SH1106, SCREEN_ST7567, SCREEN_UNKNOWN};
return firstOfOrNONE(4, types);
}
ScanI2C::FoundDevice ScanI2C::firstRTC() const
{
ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563};
return firstOfOrNONE(2, types);
}
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{
ScanI2C::DeviceType types[] = {CARDKB, RAK14004};
return firstOfOrNONE(2, types);
}
ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const
{
return DEVICE_NONE;
}
bool ScanI2C::exists(ScanI2C::DeviceType) const
{
return false;
}
ScanI2C::FoundDevice ScanI2C::firstOfOrNONE(size_t count, ScanI2C::DeviceType *types) const
{
return DEVICE_NONE;
}
size_t ScanI2C::countDevices() const
{
return 0;
}
ScanI2C::DeviceAddress::DeviceAddress(ScanI2C::I2CPort port, uint8_t address) : port(port), address(address) {}
ScanI2C::DeviceAddress::DeviceAddress() : DeviceAddress(I2CPort::NO_I2C, 0) {}
bool ScanI2C::DeviceAddress::operator<(const ScanI2C::DeviceAddress &other) const
{
return
// If this one has no port and other has a port
(port == NO_I2C && other.port != NO_I2C)
// if both have a port and this one's address is lower
|| (port != NO_I2C && other.port != NO_I2C && (address < other.address));
}
ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {}

93
src/detect/ScanI2C.h Normal file
View File

@@ -0,0 +1,93 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
class ScanI2C
{
public:
typedef enum DeviceType {
NONE,
SCREEN_SSD1306,
SCREEN_SH1106,
SCREEN_UNKNOWN, // has the same address as the two above but does not respond to the same commands
SCREEN_ST7567,
ATECC608B,
RTC_RV3028,
RTC_PCF8563,
CARDKB,
RAK14004,
PMU_AXP192_AXP2101,
BME_680,
BME_280,
BMP_280,
INA260,
INA219,
MCP9808,
SHT31,
SHTC3,
LPS22HB,
QMC6310,
QMI8658,
QMC5883L,
PMSA0031,
} DeviceType;
// typedef uint8_t DeviceAddress;
typedef enum I2CPort {
NO_I2C,
WIRE,
WIRE1,
} I2CPort;
typedef struct DeviceAddress {
I2CPort port;
uint8_t address;
explicit DeviceAddress(I2CPort port, uint8_t address);
DeviceAddress();
bool operator<(const DeviceAddress &other) const;
} DeviceAddress;
static const DeviceAddress ADDRESS_NONE;
typedef uint8_t RegisterAddress;
typedef struct FoundDevice {
DeviceType type;
DeviceAddress address;
explicit FoundDevice(DeviceType = DeviceType::NONE, DeviceAddress = ADDRESS_NONE);
} FoundDevice;
static const FoundDevice DEVICE_NONE;
public:
ScanI2C();
virtual void scanPort(ScanI2C::I2CPort);
/*
* A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it.
*/
void setSuppressScreen();
FoundDevice firstScreen() const;
FoundDevice firstRTC() const;
FoundDevice firstKeyboard() const;
virtual FoundDevice find(DeviceType) const;
virtual bool exists(DeviceType) const;
virtual size_t countDevices() const;
protected:
virtual FoundDevice firstOfOrNONE(size_t, DeviceType[]) const;
private:
bool shouldSuppressScreen = false;
};

View File

@@ -0,0 +1,297 @@
#include "ScanI2CTwoWire.h"
#include "concurrency/LockGuard.h"
#include "configuration.h"
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "main.h" // atecc
#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
ScanI2C::FoundDevice ScanI2CTwoWire::find(ScanI2C::DeviceType type) const
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
return exists(type) ? ScanI2C::FoundDevice(type, deviceAddresses.at(type)) : DEVICE_NONE;
}
bool ScanI2CTwoWire::exists(ScanI2C::DeviceType type) const
{
return deviceAddresses.find(type) != deviceAddresses.end();
}
ScanI2C::FoundDevice ScanI2CTwoWire::firstOfOrNONE(size_t count, DeviceType types[]) const
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
for (size_t k = 0; k < count; k++) {
ScanI2C::DeviceType current = types[k];
if (exists(current)) {
return ScanI2C::FoundDevice(current, deviceAddresses.at(current));
}
}
return DEVICE_NONE;
}
ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const
{
TwoWire *i2cBus = fetchI2CBus(addr);
uint8_t r = 0;
uint8_t r_prev = 0;
uint8_t c = 0;
ScanI2C::DeviceType o_probe = ScanI2C::DeviceType::SCREEN_UNKNOWN;
do {
r_prev = r;
i2cBus->beginTransmission(addr.address);
i2cBus->write((uint8_t)0x00);
i2cBus->endTransmission();
i2cBus->requestFrom((int)addr.address, 1);
if (i2cBus->available()) {
r = i2cBus->read();
}
r &= 0x0f;
if (r == 0x08 || r == 0x00) {
LOG_INFO("sh1106 display found\n");
o_probe = SCREEN_SH1106; // SH1106
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
LOG_INFO("ssd1306 display found\n");
o_probe = SCREEN_SSD1306; // SSD1306
}
c++;
} while ((r != r_prev) && (c < 4));
LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c);
return o_probe;
}
void ScanI2CTwoWire::printATECCInfo() const
{
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
atecc.readConfigZone(false);
LOG_DEBUG("ATECC608B Serial Number: ");
for (int i = 0; i < 9; i++) {
LOG_DEBUG("%02x", atecc.serialNumber[i]);
}
LOG_DEBUG(", Rev Number: ");
for (int i = 0; i < 4; i++) {
LOG_DEBUG("%02x", atecc.revisionNumber[i]);
}
LOG_DEBUG("\n");
LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked");
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
if (atecc.generatePublicKey() == false) {
LOG_DEBUG("ATECC608B Error generating public key\n");
} else {
LOG_DEBUG("ATECC608B Public Key: ");
for (int i = 0; i < 64; i++) {
LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]);
}
LOG_DEBUG("\n");
}
}
#endif
}
uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation &registerLocation,
ScanI2CTwoWire::ResponseWidth responseWidth) const
{
uint16_t value = 0x00;
TwoWire *i2cBus = fetchI2CBus(registerLocation.i2cAddress);
i2cBus->beginTransmission(registerLocation.i2cAddress.address);
i2cBus->write(registerLocation.registerAddress);
i2cBus->endTransmission();
delay(20);
i2cBus->requestFrom(registerLocation.i2cAddress.address, responseWidth);
LOG_DEBUG("Wire.available() = %d\n", i2cBus->available());
if (i2cBus->available() == 2) {
// Read MSB, then LSB
value = (uint16_t)i2cBus->read() << 8;
value |= i2cBus->read();
} else if (i2cBus->available()) {
value = i2cBus->read();
}
return value;
}
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
case ADDR: \
LOG_INFO(__VA_ARGS__); \
type = T; \
break;
void ScanI2CTwoWire::scanPort(I2CPort port)
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
LOG_DEBUG("Scanning for i2c devices on port %d\n", port);
uint8_t err;
DeviceAddress addr(port, 0x00);
uint16_t registerValue = 0x00;
ScanI2C::DeviceType type;
TwoWire *i2cBus;
#ifdef RV3028_RTC
Melopero_RV3028 rtc;
#endif
#ifdef I2C_SDA1
if (port == I2CPort::WIRE1) {
i2cBus = &Wire1;
} else {
#endif
i2cBus = &Wire;
#ifdef I2C_SDA1
}
#endif
for (addr.address = 1; addr.address < 127; addr.address++) {
i2cBus->beginTransmission(addr.address);
err = i2cBus->endTransmission();
type = NONE;
if (err == 0) {
LOG_DEBUG("I2C device found at address 0x%x\n", addr.address);
switch (addr.address) {
case SSD1306_ADDRESS:
type = probeOLED(addr);
break;
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
case ATECC608B_ADDR:
type = ATECC608B;
if (atecc.begin(addr.address) == true) {
LOG_INFO("ATECC608B initialized\n");
} else {
LOG_WARN("ATECC608B initialization failed\n");
}
printATECCInfo();
break;
#endif
#ifdef RV3028_RTC
case RV3028_RTC:
// foundDevices[addr] = RTC_RV3028;
type = RTC_RV3028;
LOG_INFO("RV3028 RTC found\n");
rtc.initI2C(*i2cBus);
rtc.writeToRegister(0x35, 0x07); // no Clkout
rtc.writeToRegister(0x37, 0xB4);
break;
#endif
#ifdef PCF8563_RTC
SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563 RTC found\n")
#endif
case CARDKB_ADDR:
// Do we have the RAK14006 instead?
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1);
if (registerValue == 0x02) {
// KEYPAD_VERSION
LOG_INFO("RAK14004 found\n");
type = RAK14004;
} else {
LOG_INFO("m5 cardKB found\n");
type = CARDKB;
}
break;
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n")
#ifdef HAS_PMU
SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "axp192/axp2101 PMU found\n")
#endif
case BME_ADDR:
case BME_ADDR_ALTERNATE:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID
switch (registerValue) {
case 0x61:
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BME_680;
break;
case 0x60:
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BME_280;
break;
default:
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BMP_280;
}
break;
case INA_ADDR:
case INA_ADDR_ALTERNATE:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
if (registerValue == 0x5449) {
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = INA260;
} else { // Assume INA219 if INA260 ID is not found
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = INA219;
}
break;
SCAN_SIMPLE_CASE(MCP9808_ADDR, MCP9808, "MCP9808 sensor found\n")
SCAN_SIMPLE_CASE(SHT31_ADDR, SHT31, "SHT31 sensor found\n")
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found\n")
case LPS22HB_ADDR_ALT:
SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB sensor found\n")
SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310 Highrate 3-Axis magnetic sensor found\n")
SCAN_SIMPLE_CASE(QMI8658_ADDR, QMI8658, "QMI8658 Highrate 6-Axis inertial measurement sensor found\n")
SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found\n")
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n")
default:
LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address);
}
} else if (err == 4) {
LOG_ERROR("Unknown error at address 0x%x\n", addr);
}
// Check if a type was found for the enumerated device - save, if so
if (type != NONE) {
deviceAddresses[type] = addr;
foundDevices[addr] = type;
}
}
}
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
{
if (address.port == ScanI2C::I2CPort::WIRE1) {
return &Wire;
} else {
#ifdef I2C_SDA1
return &Wire1;
#else
return &Wire;
#endif
}
}
size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
}

View File

@@ -0,0 +1,56 @@
#pragma once
#include <map>
#include <memory>
#include <stddef.h>
#include <stdint.h>
#include <Wire.h>
#include "ScanI2C.h"
#include "../concurrency/Lock.h"
class ScanI2CTwoWire : public ScanI2C
{
public:
void scanPort(ScanI2C::I2CPort) override;
ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override;
bool exists(ScanI2C::DeviceType) const override;
size_t countDevices() const override;
protected:
FoundDevice firstOfOrNONE(size_t, DeviceType[]) const override;
private:
typedef struct RegisterLocation {
DeviceAddress i2cAddress;
RegisterAddress registerAddress;
RegisterLocation(DeviceAddress deviceAddress, RegisterAddress registerAddress)
: i2cAddress(deviceAddress), registerAddress(registerAddress)
{
}
} RegisterLocation;
typedef uint8_t ResponseWidth;
std::map<ScanI2C::DeviceAddress, ScanI2C::DeviceType> foundDevices;
// note: prone to overwriting if multiple devices of a type are added at different addresses (rare?)
std::map<ScanI2C::DeviceType, ScanI2C::DeviceAddress> deviceAddresses;
concurrency::Lock lock;
void printATECCInfo() const;
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const;
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
};

View File

@@ -1,237 +0,0 @@
#include "../configuration.h"
#include "../main.h"
#include "mesh/generated/meshtastic/telemetry.pb.h"
#include <Wire.h>
// 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
#if HAS_WIRE
void printATECCInfo()
{
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
atecc.readConfigZone(false);
LOG_DEBUG("ATECC608B Serial Number: ");
for (int i = 0; i < 9; i++) {
LOG_DEBUG("%02x", atecc.serialNumber[i]);
}
LOG_DEBUG(", Rev Number: ");
for (int i = 0; i < 4; i++) {
LOG_DEBUG("%02x", atecc.revisionNumber[i]);
}
LOG_DEBUG("\n");
LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked");
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
if (atecc.generatePublicKey() == false) {
LOG_DEBUG("ATECC608B Error generating public key\n");
} else {
LOG_DEBUG("ATECC608B Public Key: ");
for (int i = 0; i < 64; i++) {
LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]);
}
LOG_DEBUG("\n");
}
}
#endif
}
uint16_t getRegisterValue(uint8_t address, uint8_t reg, uint8_t length)
{
uint16_t value = 0x00;
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
delay(20);
Wire.requestFrom(address, length);
LOG_DEBUG("Wire.available() = %d\n", Wire.available());
if (Wire.available() == 2) {
// Read MSB, then LSB
value = (uint16_t)Wire.read() << 8;
value |= Wire.read();
} else if (Wire.available()) {
value = Wire.read();
}
return value;
}
uint8_t oled_probe(byte addr)
{
uint8_t r = 0;
uint8_t r_prev = 0;
uint8_t c = 0;
uint8_t o_probe = 0;
do {
r_prev = r;
Wire.beginTransmission(addr);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom((int)addr, 1);
if (Wire.available()) {
r = Wire.read();
}
r &= 0x0f;
if (r == 0x08 || r == 0x00) {
o_probe = 2; // SH1106
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
o_probe = 1; // SSD1306
}
c++;
} while ((r != r_prev) && (c < 4));
LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c);
return o_probe;
}
void scanI2Cdevice()
{
byte err, addr;
uint16_t registerValue = 0x00;
int nDevices = 0;
for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
err = Wire.endTransmission();
if (err == 0) {
LOG_DEBUG("I2C device found at address 0x%x\n", addr);
nDevices++;
if (addr == SSD1306_ADDRESS) {
screen_found = addr;
screen_model = oled_probe(addr);
if (screen_model == 1) {
LOG_INFO("ssd1306 display found\n");
} else if (screen_model == 2) {
LOG_INFO("sh1106 display found\n");
} else {
LOG_INFO("unknown display found\n");
}
}
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
if (addr == ATECC608B_ADDR) {
keystore_found = addr;
if (atecc.begin(keystore_found) == true) {
LOG_INFO("ATECC608B initialized\n");
} else {
LOG_WARN("ATECC608B initialization failed\n");
}
printATECCInfo();
}
#endif
#ifdef RV3028_RTC
if (addr == RV3028_RTC) {
rtc_found = addr;
LOG_INFO("RV3028 RTC found\n");
Melopero_RV3028 rtc;
rtc.initI2C();
rtc.writeToRegister(0x35, 0x07); // no Clkout
rtc.writeToRegister(0x37, 0xB4);
}
#endif
#ifdef PCF8563_RTC
if (addr == PCF8563_RTC) {
rtc_found = addr;
LOG_INFO("PCF8563 RTC found\n");
}
#endif
if (addr == CARDKB_ADDR) {
cardkb_found = addr;
// Do we have the RAK14006 instead?
registerValue = getRegisterValue(addr, 0x04, 1);
if (registerValue == 0x02) { // KEYPAD_VERSION
LOG_INFO("RAK14004 found\n");
kb_model = 0x02;
} else {
LOG_INFO("m5 cardKB found\n");
kb_model = 0x00;
}
}
if (addr == ST7567_ADDRESS) {
screen_found = addr;
LOG_INFO("st7567 display found\n");
}
#ifdef HAS_PMU
if (addr == XPOWERS_AXP192_AXP2101_ADDRESS) {
pmu_found = true;
LOG_INFO("axp192/axp2101 PMU found\n");
}
#endif
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
if (registerValue == 0x61) {
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME680] = addr;
} else if (registerValue == 0x60) {
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME280] = addr;
} else {
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BMP280] = addr;
}
}
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
registerValue = getRegisterValue(addr, 0xFE, 2);
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
if (registerValue == 0x5449) {
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] = addr;
} else { // Assume INA219 if INA260 ID is not found
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] = addr;
}
}
if (addr == MCP9808_ADDR) {
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MCP9808] = addr;
LOG_INFO("MCP9808 sensor found\n");
}
if (addr == SHT31_ADDR) {
LOG_INFO("SHT31 sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHT31] = addr;
}
if (addr == SHTC3_ADDR) {
LOG_INFO("SHTC3 sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHTC3] = addr;
}
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
LOG_INFO("LPS22HB sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_LPS22] = addr;
}
// High rate sensors, will be processed internally
if (addr == QMC6310_ADDR) {
LOG_INFO("QMC6310 Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC6310] = addr;
}
if (addr == QMI8658_ADDR) {
LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMI8658] = addr;
}
if (addr == QMC5883L_ADDR) {
LOG_INFO("QMC5883L Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC5883L] = addr;
}
if (addr == PMSA0031_ADDR) {
LOG_INFO("PMSA0031 air quality sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I] = addr;
}
} else if (err == 4) {
LOG_ERROR("Unknow error at address 0x%x\n", addr);
}
}
if (nDevices == 0)
LOG_INFO("No I2C devices found\n");
else
LOG_INFO("%i I2C devices found\n", nDevices);
}
#else
void scanI2Cdevice() {}
#endif

View File

@@ -1,5 +1,6 @@
#include "RTC.h"
#include "configuration.h"
#include "detect/ScanI2C.h"
#include "main.h"
#include <sys/time.h>
#include <time.h>
@@ -20,10 +21,14 @@ void readFromRTC()
{
struct timeval tv; /* btw settimeofday() is helpfull here too*/
#ifdef RV3028_RTC
if (rtc_found == RV3028_RTC) {
if (rtc_found.address == RV3028_RTC) {
uint32_t now = millis();
Melopero_RV3028 rtc;
#ifdef I2C_SDA1
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.initI2C();
#endif
tm t;
t.tm_year = rtc.getYear() - 1900;
t.tm_mon = rtc.getMonth() - 1;
@@ -41,14 +46,16 @@ void readFromRTC()
}
}
#elif defined(PCF8563_RTC)
if (rtc_found == PCF8563_RTC) {
if (rtc_found.address == PCF8563_RTC) {
uint32_t now = millis();
PCF8563_Class rtc;
#ifdef RTC_USE_WIRE1
rtc.begin(Wire1);
#ifdef I2C_SDA1
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.begin();
#endif
auto tc = rtc.getDateTime();
tm t;
t.tm_year = tc.year - 1900;
@@ -103,19 +110,24 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
// If this platform has a setable RTC, set it
#ifdef RV3028_RTC
if (rtc_found == RV3028_RTC) {
if (rtc_found.address == RV3028_RTC) {
Melopero_RV3028 rtc;
#ifdef I2C_SDA1
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.initI2C();
#endif
tm *t = localtime(&tv->tv_sec);
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
}
#elif defined(PCF8563_RTC)
if (rtc_found == PCF8563_RTC) {
if (rtc_found.address == PCF8563_RTC) {
PCF8563_Class rtc;
#ifdef RTC_USE_WIRE1
rtc.begin(Wire1);
#ifdef I2C_SDA1
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.begin();
#endif

View File

@@ -41,7 +41,7 @@
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model)
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{
#if defined(TTGO_T_ECHO)
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);

View File

@@ -22,7 +22,7 @@ class EInkDisplay : public OLEDDisplay
/* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/
EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model);
EInkDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
// Write the buffer to the display memory (for eink we only do this occasionally)
virtual void display(void) override;

View File

@@ -19,6 +19,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Screen.h"
#include "configuration.h"
#if HAS_SCREEN
#include <OLEDDisplay.h>
@@ -26,7 +27,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "Screen.h"
#include "gps/GeoCoord.h"
#include "gps/RTC.h"
#include "graphics/images.h"
@@ -50,6 +50,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "fonts/OLEDDisplayFontsRU.h"
#endif
#ifdef OLED_UA
#include "fonts/OLEDDisplayFontsUA.h"
#endif
using namespace meshtastic; /** @todo remove */
namespace graphics
@@ -106,8 +110,12 @@ static uint16_t displayWidth, displayHeight;
#ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU
#else
#ifdef OLED_UA
#define FONT_SMALL ArialMT_Plain_10_UA
#else
#define FONT_SMALL ArialMT_Plain_10 // Height: 13
#endif
#endif
#define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
#endif
@@ -510,18 +518,12 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
// Draw status when gps is disabled by PMU
static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{
#ifdef HAS_PMU
String displayLine = "GPS disabled";
int16_t xPos = display->getStringWidth(displayLine);
if (!config.position.gps_enabled) {
display->drawString(x + xPos, y, displayLine);
#ifdef GPS_POWER_TOGGLE
display->drawString(x + xPos, y - 2 + FONT_HEIGHT_SMALL, " by button");
#endif
// display->drawString(x + xPos, y + 2, displayLine);
}
#endif
}
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
@@ -884,13 +886,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
// }
// }
// #else
Screen::Screen(uint8_t address, int sda, int scl)
: OSThread("Screen"), cmdQueue(32),
dispdev(address, sda, scl,
screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 ? GEOMETRY_128_128 : GEOMETRY_128_64),
Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32),
dispdev(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE),
ui(&dispdev)
{
address_found = address;
cmdQueue.setReader(this);
}
// #endif
@@ -938,9 +938,11 @@ void Screen::setup()
useDisplay = true;
#ifdef AutoOLEDWire_h
if (screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107)
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1106;
dispdev.setDetected(screen_model);
dispdev.setDetected(model);
#endif
#ifdef USE_SH1107_128_64
dispdev.setSubtype(7);
#endif
// Initialising the UI will init the display too.
@@ -1175,7 +1177,7 @@ void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiStat
* it is expected that this will be used during the boot phase */
void Screen::setSSLFrames()
{
if (address_found) {
if (address_found.address) {
// LOG_DEBUG("showing SSL frames\n");
static FrameCallback sslFrames[] = {drawSSLScreen};
ui.setFrames(sslFrames, 1);
@@ -1187,7 +1189,7 @@ void Screen::setSSLFrames()
* it is expected that this will be used during the boot phase */
void Screen::setWelcomeFrames()
{
if (address_found) {
if (address_found.address) {
// LOG_DEBUG("showing Welcome frames\n");
ui.disableAllIndicators();
@@ -1432,11 +1434,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
}
// Display GPS status
if (!config.position.gps_enabled) {
int16_t yPos = y + 2;
#ifdef GPS_POWER_TOGGLE
yPos = (y + 10 + FONT_HEIGHT_SMALL);
#endif
drawGPSpowerstat(display, x, yPos, gpsStatus);
drawGPSpowerstat(display, x, y + 2, gpsStatus);
} else {
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
@@ -1753,6 +1751,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
} else {
drawGPSpowerstat(display, x - (SCREEN_WIDTH / 4), y + FONT_HEIGHT_SMALL * 2, gpsStatus);
#ifdef GPS_POWER_TOGGLE
display->drawString(x + 30, (y + FONT_HEIGHT_SMALL * 3), " by button");
#endif
}
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS
@@ -1820,5 +1821,6 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
}
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
#endif // HAS_SCREEN

View File

@@ -2,6 +2,10 @@
#include "configuration.h"
#include "detect/ScanI2C.h"
#include "mesh/generated/meshtastic/config.pb.h"
#include <OLEDDisplay.h>
#if !HAS_SCREEN
#include "power.h"
namespace graphics
@@ -10,7 +14,7 @@ namespace graphics
class Screen
{
public:
explicit Screen(char) {}
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
void onPress() {}
void setup() {}
void setOn(bool) {}
@@ -24,7 +28,6 @@ class Screen
void startFirmwareUpdateScreen() {}
};
} // namespace graphics
#else
#include <cstring>
@@ -34,7 +37,7 @@ class Screen
#ifdef USE_ST7567
#include <ST7567Wire.h>
#elif defined(USE_SH1106) || defined(USE_SH1107)
#elif defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
#include <SH1106Wire.h>
#elif defined(USE_SSD1306)
#include <SSD1306Wire.h>
@@ -116,12 +119,14 @@ class Screen : public concurrency::OSThread
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
public:
explicit Screen(uint8_t address, int sda = -1, int scl = -1);
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
Screen(const Screen &) = delete;
Screen &operator=(const Screen &) = delete;
uint8_t address_found;
ScanI2C::DeviceAddress address_found;
meshtastic_Config_DisplayConfig_OledType model;
OLEDDISPLAY_GEOMETRY geometry;
/// Initializes the UI, turns on the display, starts showing boot screen.
//
@@ -240,6 +245,12 @@ class Screen : public concurrency::OSThread
// library have empty chars for non-latin ASCII symbols
case 0xD0: {
SKIPREST = false;
if (ch == 132)
return (uint8_t)(170); // Є
if (ch == 134)
return (uint8_t)(178); // І
if (ch == 135)
return (uint8_t)(175); // Ї
if (ch == 129)
return (uint8_t)(168); // Ё
if (ch > 143 && ch < 192)
@@ -248,12 +259,26 @@ class Screen : public concurrency::OSThread
}
case 0xD1: {
SKIPREST = false;
if (ch == 148)
return (uint8_t)(186); // є
if (ch == 150)
return (uint8_t)(179); // і
if (ch == 151)
return (uint8_t)(191); // ї
if (ch == 145)
return (uint8_t)(184); // ё
if (ch > 127 && ch < 144)
return (uint8_t)(ch + 112);
break;
}
case 0xD2: {
SKIPREST = false;
if (ch == 144)
return (uint8_t)(165); // Ґ
if (ch == 145)
return (uint8_t)(180); // ґ
break;
}
}
// We want to strip out prefix chars for two-byte char formats
@@ -350,7 +375,7 @@ class Screen : public concurrency::OSThread
/// Display device
#if defined(USE_SH1106) || defined(USE_SH1107)
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
SH1106Wire dispdev;
#elif defined(USE_SSD1306)
SSD1306Wire dispdev;

View File

@@ -8,7 +8,7 @@
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model)
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{
#ifdef SCREEN_ROTATE
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);

View File

@@ -18,7 +18,7 @@ class TFTDisplay : public OLEDDisplay
/* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/
TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model);
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
// Write the buffer to the display memory
virtual void display(void) override;

View File

@@ -0,0 +1,424 @@
#include "OLEDDisplayFontsUA.h"
// Font generated or edited with the glyphEditor
const uint8_t ArialMT_Plain_10_UA[] PROGMEM = {
0x0A, // Width: 10
0x0D, // Height: 13
0x20, // First char: 32
0xE0, // Number of chars: 224
// Jump Table:
0xFF, 0xFF, 0x00, 0x0A, // 32
0x00, 0x00, 0x04, 0x03, // 33
0x00, 0x04, 0x05, 0x04, // 34
0x00, 0x09, 0x09, 0x06, // 35
0x00, 0x12, 0x0A, 0x06, // 36
0x00, 0x1C, 0x10, 0x09, // 37
0x00, 0x2C, 0x0E, 0x08, // 38
0x00, 0x3A, 0x01, 0x02, // 39
0x00, 0x3B, 0x06, 0x04, // 40
0x00, 0x41, 0x06, 0x04, // 41
0x00, 0x47, 0x05, 0x04, // 42
0x00, 0x4C, 0x09, 0x06, // 43
0x00, 0x55, 0x04, 0x03, // 44
0x00, 0x59, 0x03, 0x03, // 45
0x00, 0x5C, 0x04, 0x03, // 46
0x00, 0x60, 0x05, 0x04, // 47
0x00, 0x65, 0x0A, 0x06, // 48
0x00, 0x6F, 0x08, 0x05, // 49
0x00, 0x77, 0x0A, 0x06, // 50
0x00, 0x81, 0x0A, 0x06, // 51
0x00, 0x8B, 0x0B, 0x07, // 52
0x00, 0x96, 0x0A, 0x06, // 53
0x00, 0xA0, 0x0A, 0x06, // 54
0x00, 0xAA, 0x09, 0x06, // 55
0x00, 0xB3, 0x0A, 0x06, // 56
0x00, 0xBD, 0x0A, 0x06, // 57
0x00, 0xC7, 0x04, 0x03, // 58
0x00, 0xCB, 0x04, 0x03, // 59
0x00, 0xCF, 0x0A, 0x06, // 60
0x00, 0xD9, 0x09, 0x06, // 61
0x00, 0xE2, 0x09, 0x06, // 62
0x00, 0xEB, 0x0B, 0x07, // 63
0x00, 0xF6, 0x14, 0x0B, // 64
0x01, 0x0A, 0x0E, 0x08, // 65
0x01, 0x18, 0x0C, 0x07, // 66
0x01, 0x24, 0x0C, 0x07, // 67
0x01, 0x30, 0x0B, 0x07, // 68
0x01, 0x3B, 0x0C, 0x07, // 69
0x01, 0x47, 0x09, 0x06, // 70
0x01, 0x50, 0x0D, 0x08, // 71
0x01, 0x5D, 0x0C, 0x07, // 72
0x01, 0x69, 0x04, 0x03, // 73
0x01, 0x6D, 0x08, 0x05, // 74
0x01, 0x75, 0x0E, 0x08, // 75
0x01, 0x83, 0x0C, 0x07, // 76
0x01, 0x8F, 0x10, 0x09, // 77
0x01, 0x9F, 0x0C, 0x07, // 78
0x01, 0xAB, 0x0E, 0x08, // 79
0x01, 0xB9, 0x0B, 0x07, // 80
0x01, 0xC4, 0x0E, 0x08, // 81
0x01, 0xD2, 0x0C, 0x07, // 82
0x01, 0xDE, 0x0C, 0x07, // 83
0x01, 0xEA, 0x0B, 0x07, // 84
0x01, 0xF5, 0x0C, 0x07, // 85
0x02, 0x01, 0x0D, 0x08, // 86
0x02, 0x0E, 0x11, 0x0A, // 87
0x02, 0x1F, 0x0E, 0x08, // 88
0x02, 0x2D, 0x0D, 0x08, // 89
0x02, 0x3A, 0x0C, 0x07, // 90
0x02, 0x46, 0x06, 0x04, // 91
0x02, 0x4C, 0x06, 0x04, // 92
0x02, 0x52, 0x04, 0x03, // 93
0x02, 0x56, 0x09, 0x06, // 94
0x02, 0x5F, 0x0C, 0x07, // 95
0x02, 0x6B, 0x03, 0x03, // 96
0x02, 0x6E, 0x0A, 0x06, // 97
0x02, 0x78, 0x0A, 0x06, // 98
0x02, 0x82, 0x0A, 0x06, // 99
0x02, 0x8C, 0x0A, 0x06, // 100
0x02, 0x96, 0x0A, 0x06, // 101
0x02, 0xA0, 0x05, 0x04, // 102
0x02, 0xA5, 0x0A, 0x06, // 103
0x02, 0xAF, 0x0A, 0x06, // 104
0x02, 0xB9, 0x04, 0x03, // 105
0x02, 0xBD, 0x04, 0x03, // 106
0x02, 0xC1, 0x08, 0x05, // 107
0x02, 0xC9, 0x04, 0x03, // 108
0x02, 0xCD, 0x10, 0x09, // 109
0x02, 0xDD, 0x0A, 0x06, // 110
0x02, 0xE7, 0x0A, 0x06, // 111
0x02, 0xF1, 0x0A, 0x06, // 112
0x02, 0xFB, 0x0A, 0x06, // 113
0x03, 0x05, 0x05, 0x04, // 114
0x03, 0x0A, 0x08, 0x05, // 115
0x03, 0x12, 0x06, 0x04, // 116
0x03, 0x18, 0x0A, 0x06, // 117
0x03, 0x22, 0x09, 0x06, // 118
0x03, 0x2B, 0x0E, 0x08, // 119
0x03, 0x39, 0x0A, 0x06, // 120
0x03, 0x43, 0x09, 0x06, // 121
0x03, 0x4C, 0x0A, 0x06, // 122
0x03, 0x56, 0x06, 0x04, // 123
0x03, 0x5C, 0x04, 0x03, // 124
0x03, 0x60, 0x05, 0x04, // 125
0x03, 0x65, 0x09, 0x06, // 126
0xFF, 0xFF, 0x00, 0x0A, // 127
0xFF, 0xFF, 0x00, 0x0A, // 128
0xFF, 0xFF, 0x00, 0x0A, // 129
0xFF, 0xFF, 0x00, 0x0A, // 130
0xFF, 0xFF, 0x00, 0x0A, // 131
0xFF, 0xFF, 0x00, 0x0A, // 132
0xFF, 0xFF, 0x00, 0x0A, // 133
0xFF, 0xFF, 0x00, 0x0A, // 134
0xFF, 0xFF, 0x00, 0x0A, // 135
0xFF, 0xFF, 0x00, 0x0A, // 136
0xFF, 0xFF, 0x00, 0x0A, // 137
0xFF, 0xFF, 0x00, 0x0A, // 138
0xFF, 0xFF, 0x00, 0x0A, // 139
0xFF, 0xFF, 0x00, 0x0A, // 140
0xFF, 0xFF, 0x00, 0x0A, // 141
0xFF, 0xFF, 0x00, 0x0A, // 142
0xFF, 0xFF, 0x00, 0x0A, // 143
0xFF, 0xFF, 0x00, 0x0A, // 144
0xFF, 0xFF, 0x00, 0x0A, // 145
0xFF, 0xFF, 0x00, 0x0A, // 146
0xFF, 0xFF, 0x00, 0x0A, // 147
0xFF, 0xFF, 0x00, 0x0A, // 148
0xFF, 0xFF, 0x00, 0x0A, // 149
0xFF, 0xFF, 0x00, 0x0A, // 150
0xFF, 0xFF, 0x00, 0x0A, // 151
0xFF, 0xFF, 0x00, 0x0A, // 152
0xFF, 0xFF, 0x00, 0x0A, // 153
0xFF, 0xFF, 0x00, 0x0A, // 154
0xFF, 0xFF, 0x00, 0x0A, // 155
0xFF, 0xFF, 0x00, 0x0A, // 156
0xFF, 0xFF, 0x00, 0x0A, // 157
0xFF, 0xFF, 0x00, 0x0A, // 158
0xFF, 0xFF, 0x00, 0x0A, // 159
0xFF, 0xFF, 0x00, 0x0A, // 160
0x03, 0x6E, 0x04, 0x03, // 161
0x03, 0x72, 0x0A, 0x06, // 162
0x03, 0x7C, 0x0C, 0x07, // 163
0x03, 0x88, 0x0A, 0x06, // 164
0x03, 0x92, 0x09, 0x06, // 165
0x03, 0x9B, 0x04, 0x03, // 166
0x03, 0x9F, 0x0A, 0x06, // 167
0x03, 0xA9, 0x0C, 0x07, // 168
0x03, 0xB5, 0x0D, 0x08, // 169
0x03, 0xC2, 0x0C, 0x07, // 170
0x03, 0xCE, 0x0A, 0x06, // 171
0x03, 0xD8, 0x09, 0x06, // 172
0x03, 0xE1, 0x03, 0x03, // 173
0x03, 0xE4, 0x0D, 0x08, // 174
0x03, 0xF1, 0x0C, 0x07, // 175
0x03, 0xFD, 0x07, 0x05, // 176
0x04, 0x04, 0x0A, 0x06, // 177
0x04, 0x0E, 0x0C, 0x07, // 178
0x04, 0x1A, 0x0C, 0x07, // 179
0x04, 0x26, 0x07, 0x05, // 180
0x04, 0x2D, 0x0A, 0x06, // 181
0x04, 0x37, 0x09, 0x06, // 182
0x04, 0x40, 0x03, 0x03, // 183
0x04, 0x43, 0x0B, 0x07, // 184
0x04, 0x4E, 0x0B, 0x07, // 185
0x04, 0x59, 0x0C, 0x07, // 186
0x04, 0x65, 0x0A, 0x06, // 187
0x04, 0x6F, 0x10, 0x09, // 188
0x04, 0x7F, 0x10, 0x09, // 189
0x04, 0x8F, 0x10, 0x09, // 190
0x04, 0x9F, 0x0A, 0x06, // 191
0x04, 0xA9, 0x0C, 0x07, // 192
0x04, 0xB5, 0x0C, 0x07, // 193
0x04, 0xC1, 0x0C, 0x07, // 194
0x04, 0xCD, 0x0B, 0x07, // 195
0x04, 0xD8, 0x0C, 0x07, // 196
0x04, 0xE4, 0x0C, 0x07, // 197
0x04, 0xF0, 0x0C, 0x07, // 198
0x04, 0xFC, 0x0C, 0x07, // 199
0x05, 0x08, 0x0C, 0x07, // 200
0x05, 0x14, 0x0C, 0x07, // 201
0x05, 0x20, 0x0C, 0x07, // 202
0x05, 0x2C, 0x0C, 0x07, // 203
0x05, 0x38, 0x0C, 0x07, // 204
0x05, 0x44, 0x0C, 0x07, // 205
0x05, 0x50, 0x0C, 0x07, // 206
0x05, 0x5C, 0x0C, 0x07, // 207
0x05, 0x68, 0x0B, 0x07, // 208
0x05, 0x73, 0x0C, 0x07, // 209
0x05, 0x7F, 0x0B, 0x07, // 210
0x05, 0x8A, 0x0C, 0x07, // 211
0x05, 0x96, 0x0B, 0x07, // 212
0x05, 0xA1, 0x0C, 0x07, // 213
0x05, 0xAD, 0x0C, 0x07, // 214
0x05, 0xB9, 0x0C, 0x07, // 215
0x05, 0xC5, 0x0C, 0x07, // 216
0x05, 0xD1, 0x0E, 0x08, // 217
0x05, 0xDF, 0x0C, 0x07, // 218
0x05, 0xEB, 0x0C, 0x07, // 219
0x05, 0xF7, 0x0C, 0x07, // 220
0x06, 0x03, 0x0C, 0x07, // 221
0x06, 0x0F, 0x0C, 0x07, // 222
0x06, 0x1B, 0x0C, 0x07, // 223
0x06, 0x27, 0x0C, 0x07, // 224
0x06, 0x33, 0x0C, 0x07, // 225
0x06, 0x3F, 0x0C, 0x07, // 226
0x06, 0x4B, 0x0B, 0x07, // 227
0x06, 0x56, 0x0C, 0x07, // 228
0x06, 0x62, 0x0B, 0x07, // 229
0x06, 0x6D, 0x0C, 0x07, // 230
0x06, 0x79, 0x0C, 0x07, // 231
0x06, 0x85, 0x0C, 0x07, // 232
0x06, 0x91, 0x0C, 0x07, // 233
0x06, 0x9D, 0x0C, 0x07, // 234
0x06, 0xA9, 0x0C, 0x07, // 235
0x06, 0xB5, 0x0C, 0x07, // 236
0x06, 0xC1, 0x0C, 0x07, // 237
0x06, 0xCD, 0x0C, 0x07, // 238
0x06, 0xD9, 0x0C, 0x07, // 239
0x06, 0xE5, 0x0B, 0x07, // 240
0x06, 0xF0, 0x0C, 0x07, // 241
0x06, 0xFC, 0x0B, 0x07, // 242
0x07, 0x07, 0x0C, 0x07, // 243
0x07, 0x13, 0x0B, 0x07, // 244
0x07, 0x1E, 0x0C, 0x07, // 245
0x07, 0x2A, 0x0C, 0x07, // 246
0x07, 0x36, 0x0C, 0x07, // 247
0x07, 0x42, 0x0C, 0x07, // 248
0x07, 0x4E, 0x0E, 0x08, // 249
0x07, 0x5C, 0x0C, 0x07, // 250
0x07, 0x68, 0x0C, 0x07, // 251
0x07, 0x74, 0x0C, 0x07, // 252
0x07, 0x80, 0x0C, 0x07, // 253
0x07, 0x8C, 0x0C, 0x07, // 254
0x07, 0x98, 0x0C, 0x07, // 255
// Font Data:
0x00, 0x00, 0xF8, 0x02, // 33
0x38, 0x00, 0x00, 0x00, 0x38, // 34
0xA0, 0x03, 0xE0, 0x00, 0xB8, 0x03, 0xE0, 0x00, 0xB8, // 35
0x30, 0x01, 0x28, 0x02, 0xF8, 0x07, 0x48, 0x02, 0x90, 0x01, // 36
0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x30, 0x03, 0xC0, 0x00, 0xB0, 0x01, 0x48, 0x02, 0x80, 0x01, // 37
0x80, 0x01, 0x50, 0x02, 0x68, 0x02, 0xA8, 0x02, 0x18, 0x01, 0x80, 0x03, 0x80, 0x02, // 38
0x38, // 39
0xE0, 0x03, 0x10, 0x04, 0x08, 0x08, // 40
0x08, 0x08, 0x10, 0x04, 0xE0, 0x03, // 41
0x28, 0x00, 0x18, 0x00, 0x28, // 42
0x40, 0x00, 0x40, 0x00, 0xF0, 0x01, 0x40, 0x00, 0x40, // 43
0x00, 0x00, 0x00, 0x06, // 44
0x80, 0x00, 0x80, // 45
0x00, 0x00, 0x00, 0x02, // 46
0x00, 0x03, 0xE0, 0x00, 0x18, // 47
0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 48
0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0xF8, 0x03, // 49
0x10, 0x02, 0x08, 0x03, 0x88, 0x02, 0x48, 0x02, 0x30, 0x02, // 50
0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 51
0xC0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x80, // 52
0x60, 0x01, 0x38, 0x02, 0x28, 0x02, 0x28, 0x02, 0xC8, 0x01, // 53
0xF0, 0x01, 0x28, 0x02, 0x28, 0x02, 0x28, 0x02, 0xD0, 0x01, // 54
0x08, 0x00, 0x08, 0x03, 0xC8, 0x00, 0x38, 0x00, 0x08, // 55
0xB0, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 56
0x70, 0x01, 0x88, 0x02, 0x88, 0x02, 0x88, 0x02, 0xF0, 0x01, // 57
0x00, 0x00, 0x20, 0x02, // 58
0x00, 0x00, 0x20, 0x06, // 59
0x00, 0x00, 0x40, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 60
0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, // 61
0x00, 0x00, 0x10, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 62
0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0xC8, 0x02, 0x48, 0x00, 0x30, // 63
0x00, 0x00, 0xC0, 0x03, 0x30, 0x04, 0xD0, 0x09, 0x28, 0x0A, 0x28, 0x0A, 0xC8, 0x0B, 0x68, 0x0A, 0x10, 0x05, 0xE0, 0x04, // 64
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x88, 0x00, 0xB0, 0x00, 0xC0, 0x01, 0x00, 0x02, // 65
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 66
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 67
0x00, 0x00, 0xF8, 0x03, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, 0xE0, // 68
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 69
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x08, // 70
0x00, 0x00, 0xE0, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x50, 0x01, 0xC0, // 71
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 72
0x00, 0x00, 0xF8, 0x03, // 73
0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 74
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 75
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 76
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x30, 0x00, 0xF8, 0x03, // 77
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0x40, 0x00, 0x80, 0x01, 0xF8, 0x03, // 78
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 79
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 80
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x03, 0x08, 0x03, 0xF0, 0x02, // 81
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0xC8, 0x00, 0x30, 0x03, // 82
0x00, 0x00, 0x30, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x90, 0x01, // 83
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 84
0x00, 0x00, 0xF8, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 85
0x08, 0x00, 0x70, 0x00, 0x80, 0x01, 0x00, 0x02, 0x80, 0x01, 0x70, 0x00, 0x08, // 86
0x18, 0x00, 0xE0, 0x01, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x18, // 87
0x00, 0x02, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 88
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x20, 0x00, 0x10, 0x00, 0x08, // 89
0x08, 0x03, 0x88, 0x02, 0xC8, 0x02, 0x68, 0x02, 0x38, 0x02, 0x18, 0x02, // 90
0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, // 91
0x18, 0x00, 0xE0, 0x00, 0x00, 0x03, // 92
0x08, 0x08, 0xF8, 0x0F, // 93
0x40, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x40, // 94
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 95
0x08, 0x00, 0x10, // 96
0x00, 0x00, 0x00, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x03, // 97
0x00, 0x00, 0xF8, 0x03, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 98
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, 0x01, // 99
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xF8, 0x03, // 100
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 101
0x20, 0x00, 0xF0, 0x03, 0x28, // 102
0x00, 0x00, 0xC0, 0x05, 0x20, 0x0A, 0x20, 0x0A, 0xE0, 0x07, // 103
0x00, 0x00, 0xF8, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 104
0x00, 0x00, 0xE8, 0x03, // 105
0x00, 0x08, 0xE8, 0x07, // 106
0xF8, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, // 107
0x00, 0x00, 0xF8, 0x03, // 108
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 109
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 110
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 111
0x00, 0x00, 0xE0, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 112
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xE0, 0x0F, // 113
0x00, 0x00, 0xE0, 0x03, 0x20, // 114
0x40, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x20, 0x01, // 115
0x20, 0x00, 0xF8, 0x03, 0x20, 0x02, // 116
0x00, 0x00, 0xE0, 0x01, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 117
0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, // 118
0xE0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xE0, 0x01, // 119
0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 120
0x20, 0x00, 0xC0, 0x09, 0x00, 0x06, 0xC0, 0x01, 0x20, // 121
0x20, 0x02, 0x20, 0x03, 0xA0, 0x02, 0x60, 0x02, 0x20, 0x02, // 122
0x80, 0x00, 0x78, 0x0F, 0x08, 0x08, // 123
0x00, 0x00, 0xF8, 0x0F, // 124
0x08, 0x08, 0x78, 0x0F, 0x80, // 125
0xC0, 0x00, 0x40, 0x00, 0xC0, 0x00, 0x80, 0x00, 0xC0, // 126
0x00, 0x00, 0xA0, 0x0F, // 161
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x0F, 0x78, 0x02, 0x40, 0x01, // 162
0x40, 0x02, 0x70, 0x03, 0xC8, 0x02, 0x48, 0x02, 0x08, 0x02, 0x10, 0x02, // 163
0x00, 0x00, 0xE0, 0x01, 0x20, 0x01, 0x20, 0x01, 0xE0, 0x01, // 164
0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x0C, // 165
0x00, 0x00, 0x38, 0x0F, // 166
0xD0, 0x04, 0x28, 0x09, 0x48, 0x09, 0x48, 0x0A, 0x90, 0x05, // 167
0x00, 0x00, 0xE0, 0x03, 0xA8, 0x02, 0xA0, 0x02, 0xA8, 0x02, 0x20, 0x02, // 168
0xE0, 0x00, 0x10, 0x01, 0x48, 0x02, 0xA8, 0x02, 0xA8, 0x02, 0x10, 0x01, 0xE0, // 169
0x00, 0x00, 0xF0, 0x01, 0x58, 0x03, 0x48, 0x02, 0x08, 0x02, 0x10, 0x01, // 170
0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, // 171
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, // 172
0x80, 0x00, 0x80, // 173
0xE0, 0x00, 0x10, 0x01, 0xE8, 0x02, 0x68, 0x02, 0xC8, 0x02, 0x10, 0x01, 0xE0, // 174
0x00, 0x00, 0x08, 0x02, 0x0A, 0x02, 0xF8, 0x03, 0x0A, 0x02, 0x08, 0x02, // 175
0x00, 0x00, 0x38, 0x00, 0x28, 0x00, 0x38, // 176
0x40, 0x02, 0x40, 0x02, 0xF0, 0x03, 0x40, 0x02, 0x40, 0x02, // 177
0x00, 0x00, 0x08, 0x02, 0x08, 0x02, 0xF8, 0x03, 0x08, 0x02, 0x08, 0x02, // 178
0x00, 0x00, 0x20, 0x02, 0x20, 0x02, 0xE8, 0x03, 0x20, 0x02, 0x20, 0x02, // 179
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x30, // 180
0x00, 0x00, 0xE0, 0x0F, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 181
0x70, 0x00, 0xF8, 0x0F, 0x08, 0x00, 0xF8, 0x0F, 0x08, // 182
0x00, 0x00, 0x40, // 183
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA0, 0x02, 0xA8, 0x02, 0xC0, // 184
0x00, 0x00, 0xF0, 0x03, 0x40, 0x00, 0x80, 0x00, 0xF8, 0x03, 0x08, // 185
0x00, 0x00, 0xE0, 0x01, 0x50, 0x02, 0x50, 0x02, 0x10, 0x02, 0x20, 0x01, // 186
0x00, 0x00, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, // 187
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0xC0, 0x00, 0x20, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 188
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0x80, 0x00, 0x60, 0x00, 0x50, 0x02, 0x48, 0x03, 0xC0, 0x02, // 189
0x48, 0x00, 0x58, 0x00, 0x68, 0x03, 0x80, 0x00, 0x60, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 190
0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0xE0, 0x03, 0x28, 0x02, // 191
0x00, 0x00, 0xF0, 0x03, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xF0, 0x03, // 192
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x88, 0x01, // 193
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 194
0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x18, // 195
0x00, 0x00, 0x00, 0x02, 0xFC, 0x03, 0x04, 0x02, 0xFC, 0x03, 0x00, 0x02, // 196
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x08, 0x02, // 197
0x00, 0x00, 0xB8, 0x03, 0x40, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xB8, 0x03, // 198
0x00, 0x00, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 199
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0xF8, 0x03, // 200
0x00, 0x00, 0xE0, 0x03, 0x08, 0x01, 0x90, 0x00, 0x48, 0x00, 0xE0, 0x03, // 201
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xA0, 0x00, 0x10, 0x01, 0x08, 0x02, // 202
0x00, 0x00, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 203
0x00, 0x00, 0xF8, 0x03, 0x10, 0x00, 0x60, 0x00, 0x10, 0x00, 0xF8, 0x03, // 204
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 205
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 206
0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 207
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 208
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 209
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 210
0x00, 0x00, 0x38, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xF8, 0x01, // 211
0x00, 0x00, 0x70, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x88, 0x00, 0x70, // 212
0x00, 0x00, 0x18, 0x03, 0xA0, 0x00, 0x40, 0x00, 0xA0, 0x00, 0x18, 0x03, // 213
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, // 214
0x00, 0x00, 0x38, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 215
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, // 216
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x06, // 217
0x00, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 218
0x00, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, 0xF8, 0x03, // 219
0x00, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 220
0x00, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 221
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xF0, 0x01, 0x08, 0x02, 0xF0, 0x01, // 222
0x00, 0x00, 0x30, 0x02, 0x48, 0x01, 0xC8, 0x00, 0x48, 0x00, 0xF8, 0x03, // 223
0x00, 0x00, 0x00, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x03, // 224
0x00, 0x00, 0xE0, 0x01, 0x50, 0x02, 0x50, 0x02, 0x48, 0x02, 0x88, 0x01, // 225
0x00, 0x00, 0xE0, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 226
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, // 227
0x00, 0x00, 0x00, 0x02, 0xC0, 0x03, 0x20, 0x02, 0xE0, 0x03, 0x00, 0x02, // 228
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, // 229
0x00, 0x00, 0x60, 0x03, 0x80, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x60, 0x03, // 230
0x00, 0x00, 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 231
0x00, 0x00, 0xE0, 0x03, 0x00, 0x01, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 232
0x00, 0x00, 0xE0, 0x03, 0x00, 0x01, 0x98, 0x00, 0x40, 0x00, 0xE0, 0x03, // 233
0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 234
0x00, 0x00, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 235
0x00, 0x00, 0xE0, 0x03, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 236
0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 237
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 238
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 239
0x00, 0x00, 0xE0, 0x03, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 240
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x40, 0x02, // 241
0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, // 242
0x00, 0x00, 0x60, 0x00, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0xE0, 0x01, // 243
0x00, 0x00, 0xC0, 0x00, 0x20, 0x01, 0xE0, 0x03, 0x20, 0x01, 0xC0, // 244
0x00, 0x00, 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 245
0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, // 246
0x00, 0x00, 0x60, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 247
0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, // 248
0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x06, // 249
0x00, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 250
0x00, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, 0xE0, 0x03, // 251
0x00, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 252
0x00, 0x00, 0x40, 0x01, 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x01, // 253
0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, 0xC0, 0x01, // 254
0x00, 0x00, 0x40, 0x02, 0xA0, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0xE0, 0x03, // 255
};

View File

@@ -0,0 +1,11 @@
#ifndef OLEDDISPLAYFONTSUA_h
#define OLEDDISPLAYFONTSUA_h
#ifdef ARDUINO
#include <Arduino.h>
#elif __MBED__
#define PROGMEM
#endif
extern const uint8_t ArialMT_Plain_10_UA[] PROGMEM;
#endif

View File

@@ -7,7 +7,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
void CardKbI2cImpl::init()
{
if (cardkb_found != CARDKB_ADDR) {
if (cardkb_found.address != CARDKB_ADDR) {
disable();
return;
}

View File

@@ -1,8 +1,9 @@
#include "kbI2cBase.h"
#include "configuration.h"
#include <Wire.h>
extern uint8_t cardkb_found;
#include "configuration.h"
#include "detect/ScanI2C.h"
extern ScanI2C::DeviceAddress cardkb_found;
extern uint8_t kb_model;
KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
@@ -10,43 +11,64 @@ KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
this->_originName = name;
}
uint8_t read_from_14004(uint8_t reg, uint8_t *data, uint8_t length)
uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t length)
{
uint8_t readflag = 0;
Wire.beginTransmission(CARDKB_ADDR);
Wire.write(reg);
Wire.endTransmission(); // stop transmitting
i2cBus->beginTransmission(CARDKB_ADDR);
i2cBus->write(reg);
i2cBus->endTransmission(); // stop transmitting
delay(20);
Wire.requestFrom(CARDKB_ADDR, (int)length);
i2cBus->requestFrom(CARDKB_ADDR, (int)length);
int i = 0;
while (Wire.available()) // slave may send less than requested
while (i2cBus->available()) // slave may send less than requested
{
data[i++] = Wire.read(); // receive a byte as a proper uint8_t
data[i++] = i2cBus->read(); // receive a byte as a proper uint8_t
readflag = 1;
}
return readflag;
}
void write_to_14004(uint8_t reg, uint8_t data)
// Unused for now - flagging it off
#if 0
void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data)
{
Wire.beginTransmission(CARDKB_ADDR);
Wire.write(reg);
Wire.write(data);
Wire.endTransmission(); // stop transmitting
i2cBus->beginTransmission(CARDKB_ADDR);
i2cBus->write(reg);
i2cBus->write(data);
i2cBus->endTransmission(); // stop transmitting
}
#endif
int32_t KbI2cBase::runOnce()
{
if (cardkb_found != CARDKB_ADDR) {
if (cardkb_found.address != CARDKB_ADDR) {
// Input device is not detected.
return INT32_MAX;
}
if (!i2cBus) {
switch (cardkb_found.port) {
case ScanI2C::WIRE1:
#ifdef I2C_SDA1
LOG_DEBUG("Using I2C Bus 1 (the second one)\n");
i2cBus = &Wire1;
break;
#endif
case ScanI2C::WIRE:
LOG_DEBUG("Using I2C Bus 0 (the first one)\n");
i2cBus = &Wire;
break;
case ScanI2C::NO_I2C:
default:
i2cBus = 0;
}
}
if (kb_model == 0x02) {
// RAK14004
uint8_t rDataBuf[8] = {0};
uint8_t PrintDataBuf = 0;
if (read_from_14004(0x01, rDataBuf, 0x04) == 1) {
if (read_from_14004(i2cBus, 0x01, rDataBuf, 0x04) == 1) {
for (uint8_t aCount = 0; aCount < 0x04; aCount++) {
for (uint8_t bCount = 0; bCount < 0x04; bCount++) {
if (((rDataBuf[aCount] >> bCount) & 0x01) == 0x01) {
@@ -65,10 +87,10 @@ int32_t KbI2cBase::runOnce()
}
} else {
// m5 cardkb
Wire.requestFrom(CARDKB_ADDR, 1);
i2cBus->requestFrom(CARDKB_ADDR, 1);
while (Wire.available()) {
char c = Wire.read();
while (i2cBus->available()) {
char c = i2cBus->read();
InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.source = this->_originName;

View File

@@ -2,6 +2,7 @@
#include "InputBroker.h"
#include "SinglePortModule.h" // TODO: what header file to include?
#include "Wire.h"
class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OSThread
{
@@ -13,4 +14,6 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
private:
const char *_originName;
TwoWire *i2cBus = 0;
};

View File

@@ -15,16 +15,19 @@
#include "SPILock.h"
#include "concurrency/OSThread.h"
#include "concurrency/Periodic.h"
#include "detect/ScanI2C.h"
#include "detect/ScanI2CTwoWire.h"
#include "detect/axpDebug.h"
#include "detect/einkScan.h"
#include "detect/i2cScan.h"
#include "graphics/Screen.h"
#include "main.h"
#include "mesh/generated/meshtastic/config.pb.h"
#include "modules/Modules.h"
#include "shutdown.h"
#include "sleep.h"
#include "target_specific.h"
#include <Wire.h>
#include <memory>
// #include <driver/rtc_io.h>
#include "mesh/eth/ethClient.h"
@@ -79,20 +82,19 @@ meshtastic::GPSStatus *gpsStatus = new meshtastic::GPSStatus();
// Global Node status
meshtastic::NodeStatus *nodeStatus = new meshtastic::NodeStatus();
// Scan for I2C Devices
/// The I2C address of our display (if found)
uint8_t screen_found;
uint8_t screen_model;
ScanI2C::DeviceAddress screen_found = ScanI2C::ADDRESS_NONE;
// The I2C address of the cardkb or RAK14004 (if found)
uint8_t cardkb_found;
ScanI2C::DeviceAddress cardkb_found = ScanI2C::ADDRESS_NONE;
// 0x02 for RAK14004 and 0x00 for cardkb
uint8_t kb_model;
// The I2C address of the RTC Module (if found)
uint8_t rtc_found;
ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE;
// Keystore Chips
uint8_t keystore_found;
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
ATECCX08A atecc;
#endif
@@ -175,6 +177,9 @@ __attribute__((weak, noinline)) bool loopCanSleep()
void setup()
{
concurrency::hasBeenSetup = true;
meshtastic_Config_DisplayConfig_OledType screen_model =
meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO;
OLEDDISPLAY_GEOMETRY screen_geometry = GEOMETRY_128_64;
#ifdef SEGGER_STDOUT_CH
auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM;
@@ -261,23 +266,118 @@ void setup()
#endif
// Currently only the tbeam has a PMU
// PMU initialization needs to be placed before scanI2Cdevice
// PMU initialization needs to be placed before i2c scanning
power = new Power();
power->setStatusHandler(powerStatus);
powerStatus->observe(&power->newStatus);
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
#ifdef LILYGO_TBEAM_S3_CORE
// In T-Beam-S3-core, the I2C device cannot be scanned before power initialization, otherwise the device will be stuck
// PCF8563 RTC in tbeam-s3 uses Wire1 to share I2C bus
Wire1.beginTransmission(PCF8563_RTC);
if (Wire1.endTransmission() == 0) {
rtc_found = PCF8563_RTC;
LOG_INFO("PCF8563 RTC found\n");
// We need to scan here to decide if we have a screen for nodeDB.init() and because power has been applied to
// accessories
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
LOG_INFO("Scanning for i2c devices...\n");
#ifdef I2C_SDA1
Wire1.begin(I2C_SDA1, I2C_SCL1);
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
#endif
#ifdef I2C_SDA
Wire.begin(I2C_SDA, I2C_SCL);
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
#elif HAS_WIRE
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
#endif
auto i2cCount = i2cScanner->countDevices();
if (i2cCount == 0) {
LOG_INFO("No I2C devices found\n");
} else {
LOG_INFO("%i I2C devices found\n", i2cCount);
}
#ifdef ARCH_ESP32
// Don't init display if we don't have one or we are waking headless due to a timer event
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
LOG_DEBUG("suppress screen wake because this is a headless timer wakeup");
i2cScanner->setSuppressScreen();
}
#endif
// We need to scan here to decide if we have a screen for nodeDB.init()
scanI2Cdevice();
auto screenInfo = i2cScanner->firstScreen();
screen_found = screenInfo.type != ScanI2C::DeviceType::NONE ? screenInfo.address : ScanI2C::ADDRESS_NONE;
if (screen_found.port != ScanI2C::I2CPort::NO_I2C) {
switch (screenInfo.type) {
case ScanI2C::DeviceType::SCREEN_SH1106:
screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_SH1106;
break;
case ScanI2C::DeviceType::SCREEN_SSD1306:
screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_SSD1306;
break;
case ScanI2C::DeviceType::SCREEN_ST7567:
case ScanI2C::DeviceType::SCREEN_UNKNOWN:
default:
screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO;
}
}
#define UPDATE_FROM_SCANNER(FIND_FN)
auto rtc_info = i2cScanner->firstRTC();
rtc_found = rtc_info.type != ScanI2C::DeviceType::NONE ? rtc_info.address : rtc_found;
auto kb_info = i2cScanner->firstKeyboard();
if (kb_info.type != ScanI2C::DeviceType::NONE) {
cardkb_found = kb_info.address;
switch (kb_info.type) {
case ScanI2C::DeviceType::RAK14004:
kb_model = 0x02;
break;
case ScanI2C::DeviceType::CARDKB:
default:
// use this as default since it's also just zero
kb_model = 0x00;
}
}
pmu_found = i2cScanner->exists(ScanI2C::DeviceType::PMU_AXP192_AXP2101);
/*
* There are a bunch of sensors that have no further logic than to be found and stuffed into the
* nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field
* "found".
*/
#define STRING(S) #S
#define SCANNER_TO_SENSORS_MAP(SCANNER_T, PB_T) \
{ \
auto found = i2cScanner->find(SCANNER_T); \
if (found.type != ScanI2C::DeviceType::NONE) { \
nodeTelemetrySensorsMap[PB_T] = found.address.address; \
LOG_DEBUG("found i2c sensor %s\n", STRING(PB_T)); \
} \
}
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I)
i2cScanner.reset();
#ifdef HAS_SDCARD
setupSDCard();
@@ -301,10 +401,6 @@ void setup()
LOG_INFO("Meshtastic hwvendor=%d, swver=%s\n", HW_VENDOR, optstr(APP_VERSION));
#ifdef ARCH_ESP32
// Don't init display if we don't have one or we are waking headless due to a timer event
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER)
screen_found = 0; // forget we even have the hardware
esp32Setup();
#endif
@@ -326,7 +422,12 @@ void setup()
screen_model = config.display.oled;
#if defined(USE_SH1107)
screen_model = Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128
display_geometry = GEOMETRY_128_128;
#endif
#if defined(USE_SH1107_128_64)
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // keep dimension of 128x64
#endif
// Init our SPI controller (must be before screen and lora)
@@ -340,7 +441,7 @@ void setup()
#endif
// Initialize the screen first so we can show the logo while we start up everything else.
screen = new graphics::Screen(screen_found);
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
@@ -369,7 +470,7 @@ void setup()
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER)
screen->setup();
#else
if (screen_found)
if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
screen->setup();
#endif
@@ -394,9 +495,22 @@ void setup()
// radio init MUST BE AFTER service.init, so we have our radio config settings (from nodedb init)
#if !HAS_RADIO && defined(ARCH_PORTDUINO)
if (!rIf) {
rIf = new SimRadio;
if (!rIf->init()) {
LOG_WARN("Failed to find simulated radio\n");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("Using SIMULATED radio!\n");
}
}
#endif
#if defined(RF95_IRQ)
if (!rIf) {
rIf = new RF95Interface(RF95_NSS, RF95_IRQ, RF95_RESET, SPI);
rIf = new RF95Interface(RF95_NSS, RF95_IRQ, RF95_RESET, RF95_DIO1, SPI);
if (!rIf->init()) {
LOG_WARN("Failed to find RF95 radio\n");
delete rIf;
@@ -407,19 +521,6 @@ void setup()
}
#endif
#if defined(USE_SX1280)
if (!rIf) {
rIf = new SX1280Interface(SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY, SPI);
if (!rIf->init()) {
LOG_WARN("Failed to find SX1280 radio\n");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("SX1280 Radio init succeeded, using SX1280 radio\n");
}
}
#endif
#if defined(USE_SX1262)
if (!rIf) {
rIf = new SX1262Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
@@ -459,15 +560,15 @@ void setup()
}
#endif
#ifdef ARCH_PORTDUINO
#if defined(USE_SX1280)
if (!rIf) {
rIf = new SimRadio;
rIf = new SX1280Interface(SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY, SPI);
if (!rIf->init()) {
LOG_WARN("Failed to find simulated radio\n");
LOG_WARN("Failed to find SX1280 radio\n");
delete rIf;
rIf = NULL;
} else {
LOG_INFO("Using SIMULATED radio!\n");
LOG_INFO("SX1280 Radio init succeeded, using SX1280 radio\n");
}
}
#endif
@@ -537,6 +638,21 @@ uint32_t shutdownAtMsec; // If not zero we will shutdown at this time (used to s
// This will supress the current delay and instead try to run ASAP.
bool runASAP;
extern meshtastic_DeviceMetadata getDeviceMetadata()
{
meshtastic_DeviceMetadata deviceMetadata;
strncpy(deviceMetadata.firmware_version, myNodeInfo.firmware_version, 18);
deviceMetadata.device_state_version = DEVICESTATE_CUR_VER;
deviceMetadata.canShutdown = pmu_found || HAS_CPU_SHUTDOWN;
deviceMetadata.hasBluetooth = HAS_BLUETOOTH;
deviceMetadata.hasWifi = HAS_WIFI;
deviceMetadata.hasEthernet = HAS_ETHERNET;
deviceMetadata.role = config.device.role;
deviceMetadata.position_flags = config.position.position_flags;
deviceMetadata.hw_model = HW_VENDOR;
return deviceMetadata;
}
void loop()
{
runASAP = false;

View File

@@ -3,7 +3,9 @@
#include "GPSStatus.h"
#include "NodeStatus.h"
#include "PowerStatus.h"
#include "detect/ScanI2C.h"
#include "graphics/Screen.h"
#include "mesh/generated/meshtastic/config.pb.h"
#include "mesh/generated/meshtastic/telemetry.pb.h"
#include <map>
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
@@ -18,12 +20,10 @@ extern NimbleBluetooth *nimbleBluetooth;
extern NRF52Bluetooth *nrf52Bluetooth;
#endif
extern uint8_t screen_found;
extern uint8_t screen_model;
extern uint8_t cardkb_found;
extern ScanI2C::DeviceAddress screen_found;
extern ScanI2C::DeviceAddress cardkb_found;
extern uint8_t kb_model;
extern uint8_t rtc_found;
extern uint8_t keystore_found;
extern ScanI2C::DeviceAddress rtc_found;
extern bool eink_found;
extern bool pmu_found;
@@ -61,3 +61,5 @@ extern uint32_t serialSinceMsec;
extern bool runASAP;
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), clearBonds();
meshtastic_DeviceMetadata getDeviceMetadata();

View File

@@ -44,7 +44,8 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
tosend->hop_limit--; // bump down the hop count
// If it is a traceRoute request, update the route that it went via me
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && traceRouteModule->wantPacket(p)) {
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && traceRouteModule &&
traceRouteModule->wantPacket(p)) {
traceRouteModule->updateRoute(tosend);
}

View File

@@ -77,6 +77,8 @@ void MeshModule::callPlugins(const meshtastic_MeshPacket &mp, RxSource src)
currentReply = NULL; // No reply yet
bool ignoreRequest = false; // No module asked to ignore the request yet
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
auto ourNodeNum = nodeDB.getNodeNum();
bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum;
@@ -135,7 +137,8 @@ void MeshModule::callPlugins(const meshtastic_MeshPacket &mp, RxSource src)
// any other node.
if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) && !currentReply) {
pi.sendResponse(mp);
LOG_INFO("Module '%s' sent a response\n", pi.name);
ignoreRequest = ignoreRequest || pi.ignoreRequest; // If at least one module asks it, we may ignore a request
LOG_INFO("Asked module '%s' to send a response\n", pi.name);
} else {
LOG_DEBUG("Module '%s' considered\n", pi.name);
}
@@ -162,8 +165,9 @@ void MeshModule::callPlugins(const meshtastic_MeshPacket &mp, RxSource src)
printPacket("Sending response", currentReply);
service.sendToMesh(currentReply);
currentReply = NULL;
} else if (mp.from != ourNodeNum) {
// Note: if the message started with the local node we don't want to send a no response reply
} else if (mp.from != ourNodeNum && !ignoreRequest) {
// Note: if the message started with the local node or a module asked to ignore the request, we don't want to send a
// no response reply
// No one wanted to reply to this requst, tell the requster that happened
LOG_DEBUG("No one responded, send a nak\n");

View File

@@ -94,6 +94,9 @@ class MeshModule
* flag */
bool encryptedOk = false;
/* We allow modules to ignore a request without sending an error if they have a specific reason for it. */
bool ignoreRequest = false;
/** If a bound channel name is set, we will only accept received packets that come in on that channel.
* A special exception (FIXME, not sure if this is a good idea) - packets that arrive on the local interface
* are allowed on any channel (this lets the local user do anything).

View File

@@ -75,9 +75,13 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
{
powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping
printPacket("Forwarding to phone", mp);
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB.getNode(mp->from)->has_user && nodeInfoModule) {
LOG_INFO("Heard a node we don't know, sending NodeInfo and asking for a response.\n");
nodeInfoModule->sendOurNodeInfo(mp->from, true);
}
printPacket("Forwarding to phone", mp);
sendToPhone((meshtastic_MeshPacket *)mp);
return 0;
@@ -132,7 +136,7 @@ void MeshService::reloadOwner(bool shouldSave)
*/
void MeshService::handleToRadio(meshtastic_MeshPacket &p)
{
#ifdef ARCH_PORTDUINO
#if defined(ARCH_PORTDUINO) && !HAS_RADIO
// Simulates device is receiving a packet via the LoRa chip
if (p.decoded.portnum == meshtastic_PortNum_SIMULATOR_APP) {
// Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first

View File

@@ -10,7 +10,7 @@
#include "MeshTypes.h"
#include "Observer.h"
#include "PointerQueue.h"
#ifdef ARCH_PORTDUINO
#if defined(ARCH_PORTDUINO) && !HAS_RADIO
#include "../platform/portduino/SimRadio.h"
#endif

View File

@@ -1,5 +1,6 @@
#include "configuration.h"
#include "../detect/ScanI2C.h"
#include "Channels.h"
#include "CryptoEngine.h"
#include "FSCommon.h"
@@ -170,6 +171,8 @@ void NodeDB::installDefaultConfig()
config.lora.hop_limit = HOP_RELIABLE;
config.position.gps_enabled = true;
config.position.position_broadcast_smart_enabled = true;
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER)
config.device.node_info_broadcast_secs = 3 * 60 * 60;
config.device.serial_enabled = true;
resetRadioConfig();
strncpy(config.network.ntp_server, "0.pool.ntp.org", 32);
@@ -179,7 +182,7 @@ void NodeDB::installDefaultConfig()
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER)
bool hasScreen = true;
#else
bool hasScreen = screen_found;
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
#endif
config.bluetooth.mode = hasScreen ? meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN
: meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;
@@ -233,15 +236,13 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
initModuleConfigIntervals();
} else if (role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
config.display.screen_on_secs = 1;
meshtastic_Channel &ch = channels.getByIndex(channels.getPrimaryIndex());
meshtastic_ChannelSettings &channelSettings = ch.settings;
uint8_t defaultpskIndex = 1;
channelSettings.psk.bytes[0] = defaultpskIndex;
channelSettings.psk.size = 1;
} else if (role == meshtastic_Config_DeviceConfig_Role_TRACKER) {
config.position.position_broadcast_smart_enabled = false;
config.position.position_broadcast_secs = 120;
config.position.gps_update_interval = 60;
} else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) {
moduleConfig.telemetry.environment_measurement_enabled = true;
moduleConfig.telemetry.environment_update_interval = 300;
}
}
@@ -249,6 +250,7 @@ void NodeDB::initModuleConfigIntervals()
{
moduleConfig.telemetry.device_update_interval = default_broadcast_interval_secs;
moduleConfig.telemetry.environment_update_interval = default_broadcast_interval_secs;
moduleConfig.telemetry.air_quality_interval = default_broadcast_interval_secs;
}
void NodeDB::installDefaultChannels()

View File

@@ -6,6 +6,7 @@
#include "PowerFSM.h"
#include "RadioInterface.h"
#include "configuration.h"
#include "main.h"
#include "xmodem.h"
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
@@ -120,6 +121,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
* STATE_SEND_NODEINFO, // states progress in this order as the device sends to the client
STATE_SEND_CONFIG,
STATE_SEND_MODULE_CONFIG,
STATE_SEND_METADATA,
STATE_SEND_COMPLETE_ID,
STATE_SEND_PACKETS // send packets or debug strings
*/
@@ -277,11 +279,15 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
config_state++;
// Advance when we have sent all of our ModuleConfig objects
if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) {
state = STATE_SEND_COMPLETE_ID;
state = STATE_SEND_METADATA;
config_state = 0;
}
break;
case STATE_SEND_METADATA:
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_metadata_tag;
fromRadioScratch.metadata = getDeviceMetadata();
state = STATE_SEND_COMPLETE_ID;
break;
case STATE_SEND_COMPLETE_ID:
LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag;
@@ -361,6 +367,7 @@ bool PhoneAPI::available()
case STATE_SEND_CHANNELS:
case STATE_SEND_CONFIG:
case STATE_SEND_MODULECONFIG:
case STATE_SEND_METADATA:
case STATE_SEND_COMPLETE_ID:
return true;

View File

@@ -26,6 +26,7 @@ class PhoneAPI
STATE_SEND_CHANNELS, // Send all channels
STATE_SEND_CONFIG, // Replacement for the old Radioconfig
STATE_SEND_MODULECONFIG, // Send Module specific config
STATE_SEND_METADATA,
STATE_SEND_COMPLETE_ID,
STATE_SEND_PACKETS // send packets or debug strings
};

View File

@@ -11,8 +11,9 @@
#define POWER_DEFAULT 17 // How much power to use if the user hasn't set a power level
RF95Interface::RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi)
: RadioLibInterface(cs, irq, rst, RADIOLIB_NC, spi)
RF95Interface::RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
SPIClass &spi)
: RadioLibInterface(cs, irq, rst, busy, spi)
{
// FIXME - we assume devices never get destroyed
}
@@ -67,19 +68,12 @@ bool RF95Interface::init()
#endif
setTransmitEnable(false);
int res = lora->begin(getFreq(), bw, sf, cr, syncWord, power, currentLimit, preambleLength);
int res = lora->begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength);
LOG_INFO("RF95 init result %d\n", res);
LOG_INFO("Frequency set to %f\n", getFreq());
LOG_INFO("Bandwidth set to %f\n", bw);
LOG_INFO("Power output set to %d\n", power);
// current limit was removed from module' ctor
// override default value (60 mA)
res = lora->setCurrentLimit(currentLimit);
LOG_DEBUG("Current limit set to %f\n", currentLimit);
LOG_DEBUG("Current limit set result %d\n", res);
if (res == RADIOLIB_ERR_NONE)
res = lora->setCRC(RADIOLIB_SX126X_LORA_CRC_ON);

View File

@@ -12,7 +12,7 @@ class RF95Interface : public RadioLibInterface
RadioLibRF95 *lora = NULL; // Either a RFM95 or RFM96 depending on what was stuffed on this board
public:
RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi);
RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
// TODO: Verify that this irq flag works with RFM95 / SX1276 radios the way it used to
bool isIRQPending() override { return lora->getIRQFlags() & RADIOLIB_SX127X_MASK_IRQ_FLAG_VALID_HEADER; }

View File

@@ -175,7 +175,7 @@ uint32_t RadioInterface::getPacketTime(uint32_t pl)
return msecs;
}
uint32_t RadioInterface::getPacketTime(meshtastic_MeshPacket *p)
uint32_t RadioInterface::getPacketTime(const meshtastic_MeshPacket *p)
{
uint32_t pl = 0;
if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag) {
@@ -281,7 +281,7 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p)
if (p->priority != 0)
out += DEBUG_PORT.mt_sprintf(" priority=%d", p->priority);
out + ")\n";
out += ")\n";
LOG_DEBUG("%s", out.c_str());
}

View File

@@ -63,7 +63,7 @@ class RadioInterface
- Tx/Rx turnaround time (maximum of SX126x and SX127x);
- MAC processing time (measured on T-beam) */
uint32_t slotTimeMsec = 8.5 * pow(2, sf) / bw + 0.2 + 0.4 + 7;
uint16_t preambleLength = 32; // 8 is default, but we use longer to increase the amount of sleep time when receiving
uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving
const uint32_t PROCESSING_TIME_MSEC =
4500; // time to construct, process and construct a packet again (empirically determined)
const uint8_t CWmin = 2; // minimum CWsize
@@ -154,7 +154,7 @@ class RadioInterface
*
* @return num msecs for the packet
*/
uint32_t getPacketTime(meshtastic_MeshPacket *p);
uint32_t getPacketTime(const meshtastic_MeshPacket *p);
uint32_t getPacketTime(uint32_t totalPacketLen);
/**

View File

@@ -218,8 +218,9 @@ void RadioLibInterface::onNotify(uint32_t notification)
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
} else {
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
// LOG_DEBUG("Channel is active: set random delay\n");
setTransmitDelay(); // reset random delay
// LOG_DEBUG("Channel is active, try receiving first.\n");
startReceive(); // try receiving this packet, afterwards we'll be trying to transmit again
setTransmitDelay();
} else {
// Send any outgoing packets we have ready
meshtastic_MeshPacket *txp = txQueue.dequeue();
@@ -388,8 +389,6 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
LOG_WARN("startSend is dropping tx packet because we are disabled\n");
packetPool.release(txp);
} else {
setStandby(); // Cancel any already in process receives
configHardwareForSend(); // must be after setStandby
size_t numbytes = beginSending(txp);

View File

@@ -24,6 +24,15 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p)
startRetransmission(copy);
}
/* If we have pending retransmissions, add the airtime of this packet to it, because during that time we cannot receive an
(implicit) ACK. Otherwise, we might retransmit too early.
*/
for (auto i = pending.begin(); i != pending.end(); i++) {
if (i->first.id != p->id) {
i->second.nextTxMsec += iface->getPacketTime(p);
}
}
return FloodingRouter::send(p);
}
@@ -53,6 +62,15 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
}
}
/* At this point we have already deleted the pending retransmission if this packet was an (implicit) ACK to it.
Now for all other pending retransmissions, we have to add the airtime of this received packet to the retransmission timer,
because while receiving this packet, we could not have received an (implicit) ACK for it.
If we don't add this, we will likely retransmit too early.
*/
for (auto i = pending.begin(); i != pending.end(); i++) {
i->second.nextTxMsec += iface->getPacketTime(p);
}
/* Resend implicit ACKs for repeated packets (assuming the original packet was sent with HOP_RELIABLE)
* this way if an implicit ACK is dropped and a packet is resent we'll rebroadcast again.
* Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and
@@ -148,7 +166,11 @@ bool ReliableRouter::stopRetransmission(GlobalPacketId key)
if (old) {
auto numErased = pending.erase(key);
assert(numErased == 1);
// remove the 'original' (identified by originator and packet->id) from the txqueue and free it
cancelSending(getFrom(old->packet), old->packet->id);
// now free the pooled copy for retransmission too. tryfix for #2228
if (old->packet)
packetPool.release(old->packet);
return true;
} else
return false;

View File

@@ -212,9 +212,10 @@ template <typename T> void SX126xInterface<T>::startReceive()
setStandby();
// int err = lora.startReceive();
int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in
// standby mostly.
// We use a 16 bit preamble so this should save some power by letting radio sit in standby mostly.
// Furthermore, we need the HEADER_VALID IRQ flag to detect whether we are actively receiving
int err =
lora.startReceiveDutyCycleAuto(preambleLength, 8, RADIOLIB_SX126X_IRQ_RX_DEFAULT | RADIOLIB_SX126X_IRQ_HEADER_VALID);
assert(err == RADIOLIB_ERR_NONE);
isReceiving = true;
@@ -224,7 +225,7 @@ template <typename T> void SX126xInterface<T>::startReceive()
#endif
}
/** Could we send right now (i.e. either not actively receving or transmitting)? */
/** Is the channel currently active? */
template <typename T> bool SX126xInterface<T>::isChannelActive()
{
// check if we can detect a LoRa preamble on the current channel
@@ -232,7 +233,7 @@ template <typename T> bool SX126xInterface<T>::isChannelActive()
setStandby();
result = lora.scanChannel();
if (result == RADIOLIB_PREAMBLE_DETECTED)
if (result == RADIOLIB_LORA_DETECTED)
return true;
assert(result != RADIOLIB_ERR_WRONG_MODEM);
@@ -245,17 +246,12 @@ template <typename T> bool SX126xInterface<T>::isActivelyReceiving()
{
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
// received and handled the interrupt for reading the packet/handling errors.
// FIXME: it would be better to check for preamble, but we currently have our ISR not set to fire for packets that
// never even get a valid header, so we don't want preamble to get set and stay set due to noise on the network.
uint16_t irq = lora.getIrqStatus();
bool hasPreamble = (irq & RADIOLIB_SX126X_IRQ_HEADER_VALID);
bool headerValid = (irq & RADIOLIB_SX126X_IRQ_HEADER_VALID);
// this is not correct - often always true - need to add an extra conditional
// size_t bytesPending = lora.getPacketLength();
// if (hasPreamble) LOG_DEBUG("rx hasPreamble\n");
return hasPreamble;
// if (headerValid) LOG_DEBUG("rx headerValid\n");
return headerValid;
}
template <typename T> bool SX126xInterface<T>::sleep()

View File

@@ -203,7 +203,9 @@ template <typename T> void SX128xInterface<T>::startReceive()
digitalWrite(SX128X_TXEN, LOW);
#endif
int err = lora.startReceive();
// We use the HEADER_VALID IRQ flag to detect whether we are actively receiving
int err =
lora.startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT | RADIOLIB_SX128X_IRQ_HEADER_VALID);
assert(err == RADIOLIB_ERR_NONE);
@@ -214,7 +216,7 @@ template <typename T> void SX128xInterface<T>::startReceive()
#endif
}
/** Could we send right now (i.e. either not actively receving or transmitting)? */
/** Is the channel currently active? */
template <typename T> bool SX128xInterface<T>::isChannelActive()
{
// check if we can detect a LoRa preamble on the current channel
@@ -222,7 +224,7 @@ template <typename T> bool SX128xInterface<T>::isChannelActive()
setStandby();
result = lora.scanChannel();
if (result == RADIOLIB_PREAMBLE_DETECTED)
if (result == RADIOLIB_LORA_DETECTED)
return true;
assert(result != RADIOLIB_ERR_WRONG_MODEM);
@@ -234,8 +236,8 @@ template <typename T> bool SX128xInterface<T>::isChannelActive()
template <typename T> bool SX128xInterface<T>::isActivelyReceiving()
{
uint16_t irq = lora.getIrqStatus();
bool hasPreamble = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID);
return hasPreamble;
bool hasHeader = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID);
return hasHeader;
}
template <typename T> bool SX128xInterface<T>::sleep()

View File

@@ -6,7 +6,6 @@
#include <pb.h>
#include "meshtastic/channel.pb.h"
#include "meshtastic/config.pb.h"
#include "meshtastic/device_metadata.pb.h"
#include "meshtastic/mesh.pb.h"
#include "meshtastic/module_config.pb.h"
#include "meshtastic/connection_status.pb.h"
@@ -67,6 +66,8 @@ typedef struct _meshtastic_HamParameters {
Please respect your local laws, regulations, and band plans.
Ensure your radio is capable of operating of the selected frequency before setting this. */
float frequency;
/* Optional short name of user */
char short_name[6];
} meshtastic_HamParameters;
/* This message is handled by the Admin module and is responsible for all settings/channel read/write operations.
@@ -134,7 +135,7 @@ typedef struct _meshtastic_AdminMessage {
/* Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot)
Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. */
int32_t reboot_ota_seconds;
/* This message is only supported for the simulator porduino build.
/* This message is only supported for the simulator Portduino build.
If received the simulator will exit successfully. */
bool exit_simulator;
/* Tell the node to reboot in this many seconds (or <0 to cancel reboot) */
@@ -169,14 +170,15 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_AdminMessage_init_default {0, {0}}
#define meshtastic_HamParameters_init_default {"", 0, 0}
#define meshtastic_HamParameters_init_default {"", 0, 0, ""}
#define meshtastic_AdminMessage_init_zero {0, {0}}
#define meshtastic_HamParameters_init_zero {"", 0, 0}
#define meshtastic_HamParameters_init_zero {"", 0, 0, ""}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_HamParameters_call_sign_tag 1
#define meshtastic_HamParameters_tx_power_tag 2
#define meshtastic_HamParameters_frequency_tag 3
#define meshtastic_HamParameters_short_name_tag 4
#define meshtastic_AdminMessage_get_channel_request_tag 1
#define meshtastic_AdminMessage_get_channel_response_tag 2
#define meshtastic_AdminMessage_get_owner_request_tag 3
@@ -259,7 +261,8 @@ X(a, STATIC, ONEOF, INT32, (payload_variant,nodedb_reset,nodedb_reset),
#define meshtastic_HamParameters_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, call_sign, 1) \
X(a, STATIC, SINGULAR, INT32, tx_power, 2) \
X(a, STATIC, SINGULAR, FLOAT, frequency, 3)
X(a, STATIC, SINGULAR, FLOAT, frequency, 3) \
X(a, STATIC, SINGULAR, STRING, short_name, 4)
#define meshtastic_HamParameters_CALLBACK NULL
#define meshtastic_HamParameters_DEFAULT NULL
@@ -272,7 +275,7 @@ extern const pb_msgdesc_t meshtastic_HamParameters_msg;
/* Maximum encoded size of messages (where known) */
#define meshtastic_AdminMessage_size 234
#define meshtastic_HamParameters_size 25
#define meshtastic_HamParameters_size 32
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -31,7 +31,10 @@ typedef enum _meshtastic_Config_DeviceConfig_Role {
meshtastic_Config_DeviceConfig_Role_REPEATER = 4,
/* Tracker device role
Position Mesh packets will be prioritized higher and sent more frequently by default. */
meshtastic_Config_DeviceConfig_Role_TRACKER = 5
meshtastic_Config_DeviceConfig_Role_TRACKER = 5,
/* Sensor device role
Telemetry Mesh packets will be prioritized higher and sent more frequently by default. */
meshtastic_Config_DeviceConfig_Role_SENSOR = 6
} meshtastic_Config_DeviceConfig_Role;
/* Defines the device's behavior for how messages are rebroadcast */
@@ -149,7 +152,7 @@ typedef enum _meshtastic_Config_LoRaConfig_RegionCode {
meshtastic_Config_LoRaConfig_RegionCode_US = 1,
/* European Union 433mhz */
meshtastic_Config_LoRaConfig_RegionCode_EU_433 = 2,
/* European Union 433mhz */
/* European Union 868mhz */
meshtastic_Config_LoRaConfig_RegionCode_EU_868 = 3,
/* China */
meshtastic_Config_LoRaConfig_RegionCode_CN = 4,
@@ -199,11 +202,11 @@ typedef enum _meshtastic_Config_LoRaConfig_ModemPreset {
} meshtastic_Config_LoRaConfig_ModemPreset;
typedef enum _meshtastic_Config_BluetoothConfig_PairingMode {
/* Device generates a random pin that will be shown on the screen of the device for pairing */
/* Device generates a random PIN that will be shown on the screen of the device for pairing */
meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN = 0,
/* Device requires a specified fixed pin for pairing */
/* Device requires a specified fixed PIN for pairing */
meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN = 1,
/* Device requires no pin for pairing */
/* Device requires no PIN for pairing */
meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN = 2
} meshtastic_Config_BluetoothConfig_PairingMode;
@@ -225,6 +228,9 @@ typedef struct _meshtastic_Config_DeviceConfig {
uint32_t buzzer_gpio;
/* Sets the role of node */
meshtastic_Config_DeviceConfig_RebroadcastMode rebroadcast_mode;
/* Send our nodeinfo this often
Defaults to 900 Seconds (15 minutes) */
uint32_t node_info_broadcast_secs;
} meshtastic_Config_DeviceConfig;
/* Position Config */
@@ -358,7 +364,7 @@ typedef struct _meshtastic_Config_DisplayConfig {
/* Lora Config */
typedef struct _meshtastic_Config_LoRaConfig {
/* When enabled, the `modem_preset` fields will be adheared to, else the `bandwidth`/`spread_factor`/`coding_rate`
/* When enabled, the `modem_preset` fields will be adhered to, else the `bandwidth`/`spread_factor`/`coding_rate`
will be taked from their respective manually defined fields */
bool use_preset;
/* Either modem_config or bandwidth/spreading/coding will be specified - NOT BOTH.
@@ -389,12 +395,12 @@ typedef struct _meshtastic_Config_LoRaConfig {
/* Disable TX from the LoRa radio. Useful for hot-swapping antennas and other tests.
Defaults to false */
bool tx_enabled;
/* If zero then, use default max legal continuous power (ie. something that won't
/* If zero, then use default max legal continuous power (ie. something that won't
burn out the radio hardware)
In most cases you should use zero here.
Units are in dBm. */
int8_t tx_power;
/* This is controlling the actual hardware frequency the radio is transmitting on.
/* This controls the actual hardware frequency the radio transmits on.
Most users should never need to be exposed to this field/concept.
A channel number between 1 and NUM_CHANNELS (whatever the max is in the current region).
If ZERO then the rule is "use the old channel name hash based
@@ -416,7 +422,7 @@ typedef struct _meshtastic_Config_LoRaConfig {
float override_frequency;
/* For testing it is useful sometimes to force a node to never listen to
particular other nodes (simulating radio out of range). All nodenums listed
in ignore_incoming will have packets they send droped on receive (by router.cpp) */
in ignore_incoming will have packets they send dropped on receive (by router.cpp) */
pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3];
} meshtastic_Config_LoRaConfig;
@@ -426,7 +432,7 @@ typedef struct _meshtastic_Config_BluetoothConfig {
bool enabled;
/* Determines the pairing strategy for the device */
meshtastic_Config_BluetoothConfig_PairingMode mode;
/* Specified pin for PairingMode.FixedPin */
/* Specified PIN for PairingMode.FixedPin */
uint32_t fixed_pin;
} meshtastic_Config_BluetoothConfig;
@@ -450,8 +456,8 @@ extern "C" {
/* Helper constants for enums */
#define _meshtastic_Config_DeviceConfig_Role_MIN meshtastic_Config_DeviceConfig_Role_CLIENT
#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_TRACKER
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_TRACKER+1))
#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_SENSOR
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_SENSOR+1))
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY
@@ -515,7 +521,7 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}}
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN}
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0}
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""}
@@ -524,7 +530,7 @@ extern "C" {
#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
#define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}}
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN}
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0}
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""}
@@ -540,6 +546,7 @@ extern "C" {
#define meshtastic_Config_DeviceConfig_button_gpio_tag 4
#define meshtastic_Config_DeviceConfig_buzzer_gpio_tag 5
#define meshtastic_Config_DeviceConfig_rebroadcast_mode_tag 6
#define meshtastic_Config_DeviceConfig_node_info_broadcast_secs_tag 7
#define meshtastic_Config_PositionConfig_position_broadcast_secs_tag 1
#define meshtastic_Config_PositionConfig_position_broadcast_smart_enabled_tag 2
#define meshtastic_Config_PositionConfig_fixed_position_tag 3
@@ -629,7 +636,8 @@ X(a, STATIC, SINGULAR, BOOL, serial_enabled, 2) \
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 3) \
X(a, STATIC, SINGULAR, UINT32, button_gpio, 4) \
X(a, STATIC, SINGULAR, UINT32, buzzer_gpio, 5) \
X(a, STATIC, SINGULAR, UENUM, rebroadcast_mode, 6)
X(a, STATIC, SINGULAR, UENUM, rebroadcast_mode, 6) \
X(a, STATIC, SINGULAR, UINT32, node_info_broadcast_secs, 7)
#define meshtastic_Config_DeviceConfig_CALLBACK NULL
#define meshtastic_Config_DeviceConfig_DEFAULT NULL
@@ -741,7 +749,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
/* Maximum encoded size of messages (where known) */
#define meshtastic_Config_BluetoothConfig_size 10
#define meshtastic_Config_DeviceConfig_size 20
#define meshtastic_Config_DeviceConfig_size 26
#define meshtastic_Config_DisplayConfig_size 26
#define meshtastic_Config_LoRaConfig_size 77
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20

View File

@@ -27,9 +27,9 @@ typedef struct _meshtastic_WifiConnectionStatus {
/* Connection status */
bool has_status;
meshtastic_NetworkConnectionStatus status;
/* WiFi access point ssid */
/* WiFi access point SSID */
char ssid[33];
/* Rssi of wireless connection */
/* RSSI of wireless connection */
int32_t rssi;
} meshtastic_WifiConnectionStatus;
@@ -42,9 +42,9 @@ typedef struct _meshtastic_EthernetConnectionStatus {
/* Bluetooth connection status */
typedef struct _meshtastic_BluetoothConnectionStatus {
/* The pairing pin for bluetooth */
/* The pairing PIN for bluetooth */
uint32_t pin;
/* Rssi of bluetooth connection */
/* RSSI of bluetooth connection */
int32_t rssi;
/* Whether the device has an active connection or not */
bool is_connected;
@@ -52,7 +52,7 @@ typedef struct _meshtastic_BluetoothConnectionStatus {
/* Serial connection status */
typedef struct _meshtastic_SerialConnectionStatus {
/* The serial baud rate */
/* Serial baud rate */
uint32_t baud;
/* Whether the device has an active connection or not */
bool is_connected;

View File

@@ -1,12 +0,0 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.7 */
#include "meshtastic/device_metadata.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(meshtastic_DeviceMetadata, meshtastic_DeviceMetadata, AUTO)

View File

@@ -1,83 +0,0 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.7 */
#ifndef PB_MESHTASTIC_MESHTASTIC_DEVICE_METADATA_PB_H_INCLUDED
#define PB_MESHTASTIC_MESHTASTIC_DEVICE_METADATA_PB_H_INCLUDED
#include <pb.h>
#include "meshtastic/config.pb.h"
#include "meshtastic/mesh.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
/* Device metadata response */
typedef struct _meshtastic_DeviceMetadata {
/* Device firmware version string */
char firmware_version[18];
/* Device state version */
uint32_t device_state_version;
/* Indicates whether the device can shutdown CPU natively or via power management chip */
bool canShutdown;
/* Indicates that the device has native wifi capability */
bool hasWifi;
/* Indicates that the device has native bluetooth capability */
bool hasBluetooth;
/* Indicates that the device has an ethernet peripheral */
bool hasEthernet;
/* Indicates that the device's role in the mesh */
meshtastic_Config_DeviceConfig_Role role;
/* Indicates the device's current enabled position flags */
uint32_t position_flags;
/* Device hardware model */
meshtastic_HardwareModel hw_model;
} meshtastic_DeviceMetadata;
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN}
#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_DeviceMetadata_firmware_version_tag 1
#define meshtastic_DeviceMetadata_device_state_version_tag 2
#define meshtastic_DeviceMetadata_canShutdown_tag 3
#define meshtastic_DeviceMetadata_hasWifi_tag 4
#define meshtastic_DeviceMetadata_hasBluetooth_tag 5
#define meshtastic_DeviceMetadata_hasEthernet_tag 6
#define meshtastic_DeviceMetadata_role_tag 7
#define meshtastic_DeviceMetadata_position_flags_tag 8
#define meshtastic_DeviceMetadata_hw_model_tag 9
/* Struct field encoding specification for nanopb */
#define meshtastic_DeviceMetadata_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, firmware_version, 1) \
X(a, STATIC, SINGULAR, UINT32, device_state_version, 2) \
X(a, STATIC, SINGULAR, BOOL, canShutdown, 3) \
X(a, STATIC, SINGULAR, BOOL, hasWifi, 4) \
X(a, STATIC, SINGULAR, BOOL, hasBluetooth, 5) \
X(a, STATIC, SINGULAR, BOOL, hasEthernet, 6) \
X(a, STATIC, SINGULAR, UENUM, role, 7) \
X(a, STATIC, SINGULAR, UINT32, position_flags, 8) \
X(a, STATIC, SINGULAR, UENUM, hw_model, 9)
#define meshtastic_DeviceMetadata_CALLBACK NULL
#define meshtastic_DeviceMetadata_DEFAULT NULL
extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_DeviceMetadata_fields &meshtastic_DeviceMetadata_msg
/* Maximum encoded size of messages (where known) */
#define meshtastic_DeviceMetadata_size 44
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -54,7 +54,7 @@ typedef struct _meshtastic_DeviceState {
/* Used only during development.
Indicates developer is testing and changes should never be saved to flash. */
bool no_save;
/* Some GPSes seem to have bogus settings from the factory, so we always do one factory reset. */
/* Some GPS receivers seem to have bogus settings from the factory, so we always do one factory reset. */
bool did_gps_reset;
} meshtastic_DeviceState;
@@ -72,13 +72,13 @@ typedef struct _meshtastic_ChannelFile {
typedef PB_BYTES_ARRAY_T(2048) meshtastic_OEMStore_oem_icon_bits_t;
typedef PB_BYTES_ARRAY_T(32) meshtastic_OEMStore_oem_aes_key_t;
/* This can be used for customizing the firmware distribution. If populated,
show a secondary bootup screen with cuatom logo and text for 2.5 seconds. */
show a secondary bootup screen with custom logo and text for 2.5 seconds. */
typedef struct _meshtastic_OEMStore {
/* The Logo width in Px */
uint32_t oem_icon_width;
/* The Logo height in Px */
uint32_t oem_icon_height;
/* The Logo in xbm bytechar format */
/* The Logo in XBM bytechar format */
meshtastic_OEMStore_oem_icon_bits_t oem_icon_bits;
/* Use this font for the OEM text. */
meshtastic_ScreenFonts oem_font;
@@ -188,7 +188,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg;
/* Maximum encoded size of messages (where known) */
#define meshtastic_ChannelFile_size 638
#define meshtastic_DeviceState_size 21800
#define meshtastic_OEMStore_size 2992
#define meshtastic_OEMStore_size 3006
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -156,8 +156,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
#define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */
#define meshtastic_LocalConfig_size 434
#define meshtastic_LocalModuleConfig_size 412
#define meshtastic_LocalConfig_size 440
#define meshtastic_LocalModuleConfig_size 420
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -48,6 +48,9 @@ PB_BIND(meshtastic_ToRadio, meshtastic_ToRadio, 2)
PB_BIND(meshtastic_Compressed, meshtastic_Compressed, AUTO)
PB_BIND(meshtastic_DeviceMetadata, meshtastic_DeviceMetadata, AUTO)

View File

@@ -57,9 +57,13 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_TLORA_V2_1_1P8 = 15,
/* TODO: REPLACE */
meshtastic_HardwareModel_TLORA_T3_S3 = 16,
/* B&Q Consulting Nano G1 Explorer: https://wiki.uniteng.com/en/meshtastic/nano-g1-explorer */
meshtastic_HardwareModel_NANO_G1_EXPLORER = 17,
/* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */
meshtastic_HardwareModel_STATION_G1 = 25,
/* Less common/prototype boards listed here (needs one more byte over the air) */
/* ---------------------------------------------------------------------------
Less common/prototype boards listed here (needs one more byte over the air)
--------------------------------------------------------------------------- */
meshtastic_HardwareModel_LORA_RELAY_V1 = 32,
/* TODO: REPLACE */
meshtastic_HardwareModel_NRF52840DK = 33,
@@ -87,7 +91,11 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_HELTEC_WSL_V3 = 44,
/* New BETAFPV ELRS Micro TX Module 2.4G with ESP32 CPU */
meshtastic_HardwareModel_BETAFPV_2400_TX = 45,
/* 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. */
/* BetaFPV ExpressLRS "Nano" TX Module 900MHz with ESP32 CPU */
meshtastic_HardwareModel_BETAFPV_900_NANO_TX = 46,
/* ------------------------------------------------------------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------------------------------------------------------------ */
meshtastic_HardwareModel_PRIVATE_HW = 255
} meshtastic_HardwareModel;
@@ -637,6 +645,61 @@ typedef struct _meshtastic_QueueStatus {
uint32_t mesh_packet_id;
} meshtastic_QueueStatus;
/* Packets/commands to the radio will be written (reliably) to the toRadio characteristic.
Once the write completes the phone can assume it is handled. */
typedef struct _meshtastic_ToRadio {
pb_size_t which_payload_variant;
union {
/* Send this packet on the mesh */
meshtastic_MeshPacket packet;
/* Phone wants radio to send full node db to the phone, This is
typically the first packet sent to the radio when the phone gets a
bluetooth connection. The radio will respond by sending back a
MyNodeInfo, a owner, a radio config and a series of
FromRadio.node_infos, and config_complete
the integer you write into this field will be reported back in the
config_complete_id response this allows clients to never be confused by
a stale old partially sent config. */
uint32_t want_config_id;
/* Tell API server we are disconnecting now.
This is useful for serial links where there is no hardware/protocol based notification that the client has dropped the link.
(Sending this message is optional for clients) */
bool disconnect;
meshtastic_XModem xmodemPacket;
};
} meshtastic_ToRadio;
typedef PB_BYTES_ARRAY_T(237) meshtastic_Compressed_data_t;
/* Compressed message payload */
typedef struct _meshtastic_Compressed {
/* PortNum to determine the how to handle the compressed payload. */
meshtastic_PortNum portnum;
/* Compressed data. */
meshtastic_Compressed_data_t data;
} meshtastic_Compressed;
/* Device metadata response */
typedef struct _meshtastic_DeviceMetadata {
/* Device firmware version string */
char firmware_version[18];
/* Device state version */
uint32_t device_state_version;
/* Indicates whether the device can shutdown CPU natively or via power management chip */
bool canShutdown;
/* Indicates that the device has native wifi capability */
bool hasWifi;
/* Indicates that the device has native bluetooth capability */
bool hasBluetooth;
/* Indicates that the device has an ethernet peripheral */
bool hasEthernet;
/* Indicates that the device's role in the mesh */
meshtastic_Config_DeviceConfig_Role role;
/* Indicates the device's current enabled position flags */
uint32_t position_flags;
/* Device hardware model */
meshtastic_HardwareModel hw_model;
} meshtastic_DeviceMetadata;
/* Packets from the radio to the phone will appear on the fromRadio characteristic.
It will support READ and NOTIFY. When a new packet arrives the device will BLE notify?
It will sit in that descriptor until consumed by the phone,
@@ -677,42 +740,11 @@ typedef struct _meshtastic_FromRadio {
meshtastic_QueueStatus queueStatus;
/* File Transfer Chunk */
meshtastic_XModem xmodemPacket;
/* Device metadata message */
meshtastic_DeviceMetadata metadata;
};
} meshtastic_FromRadio;
/* Packets/commands to the radio will be written (reliably) to the toRadio characteristic.
Once the write completes the phone can assume it is handled. */
typedef struct _meshtastic_ToRadio {
pb_size_t which_payload_variant;
union {
/* Send this packet on the mesh */
meshtastic_MeshPacket packet;
/* Phone wants radio to send full node db to the phone, This is
typically the first packet sent to the radio when the phone gets a
bluetooth connection. The radio will respond by sending back a
MyNodeInfo, a owner, a radio config and a series of
FromRadio.node_infos, and config_complete
the integer you write into this field will be reported back in the
config_complete_id response this allows clients to never be confused by
a stale old partially sent config. */
uint32_t want_config_id;
/* Tell API server we are disconnecting now.
This is useful for serial links where there is no hardware/protocol based notification that the client has dropped the link.
(Sending this message is optional for clients) */
bool disconnect;
meshtastic_XModem xmodemPacket;
};
} meshtastic_ToRadio;
typedef PB_BYTES_ARRAY_T(237) meshtastic_Compressed_data_t;
/* Compressed message payload */
typedef struct _meshtastic_Compressed {
/* PortNum to determine the how to handle the compressed payload. */
meshtastic_PortNum portnum;
/* Compressed data. */
meshtastic_Compressed_data_t data;
} meshtastic_Compressed;
#ifdef __cplusplus
extern "C" {
@@ -779,6 +811,9 @@ extern "C" {
#define meshtastic_Compressed_portnum_ENUMTYPE meshtastic_PortNum
#define meshtastic_DeviceMetadata_role_ENUMTYPE meshtastic_Config_DeviceConfig_Role
#define meshtastic_DeviceMetadata_hw_model_ENUMTYPE meshtastic_HardwareModel
/* Initializer values for message structs */
#define meshtastic_Position_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
@@ -795,6 +830,7 @@ extern "C" {
#define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}}
#define meshtastic_ToRadio_init_default {0, {meshtastic_MeshPacket_init_default}}
#define meshtastic_Compressed_init_default {_meshtastic_PortNum_MIN, {0, {0}}}
#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN}
#define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0}
#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
@@ -809,6 +845,7 @@ extern "C" {
#define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}}
#define meshtastic_ToRadio_init_zero {0, {meshtastic_MeshPacket_init_zero}}
#define meshtastic_Compressed_init_zero {_meshtastic_PortNum_MIN, {0, {0}}}
#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_Position_latitude_i_tag 1
@@ -902,6 +939,21 @@ extern "C" {
#define meshtastic_QueueStatus_free_tag 2
#define meshtastic_QueueStatus_maxlen_tag 3
#define meshtastic_QueueStatus_mesh_packet_id_tag 4
#define meshtastic_ToRadio_packet_tag 1
#define meshtastic_ToRadio_want_config_id_tag 3
#define meshtastic_ToRadio_disconnect_tag 4
#define meshtastic_ToRadio_xmodemPacket_tag 5
#define meshtastic_Compressed_portnum_tag 1
#define meshtastic_Compressed_data_tag 2
#define meshtastic_DeviceMetadata_firmware_version_tag 1
#define meshtastic_DeviceMetadata_device_state_version_tag 2
#define meshtastic_DeviceMetadata_canShutdown_tag 3
#define meshtastic_DeviceMetadata_hasWifi_tag 4
#define meshtastic_DeviceMetadata_hasBluetooth_tag 5
#define meshtastic_DeviceMetadata_hasEthernet_tag 6
#define meshtastic_DeviceMetadata_role_tag 7
#define meshtastic_DeviceMetadata_position_flags_tag 8
#define meshtastic_DeviceMetadata_hw_model_tag 9
#define meshtastic_FromRadio_id_tag 1
#define meshtastic_FromRadio_packet_tag 2
#define meshtastic_FromRadio_my_info_tag 3
@@ -914,12 +966,7 @@ extern "C" {
#define meshtastic_FromRadio_channel_tag 10
#define meshtastic_FromRadio_queueStatus_tag 11
#define meshtastic_FromRadio_xmodemPacket_tag 12
#define meshtastic_ToRadio_packet_tag 1
#define meshtastic_ToRadio_want_config_id_tag 3
#define meshtastic_ToRadio_disconnect_tag 4
#define meshtastic_ToRadio_xmodemPacket_tag 5
#define meshtastic_Compressed_portnum_tag 1
#define meshtastic_Compressed_data_tag 2
#define meshtastic_FromRadio_metadata_tag 13
/* Struct field encoding specification for nanopb */
#define meshtastic_Position_FIELDLIST(X, a) \
@@ -1075,7 +1122,8 @@ X(a, STATIC, ONEOF, BOOL, (payload_variant,rebooted,rebooted), 8) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig), 9) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,queueStatus,queueStatus), 11) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 12)
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 12) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13)
#define meshtastic_FromRadio_CALLBACK NULL
#define meshtastic_FromRadio_DEFAULT NULL
#define meshtastic_FromRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket
@@ -1087,6 +1135,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket),
#define meshtastic_FromRadio_payload_variant_channel_MSGTYPE meshtastic_Channel
#define meshtastic_FromRadio_payload_variant_queueStatus_MSGTYPE meshtastic_QueueStatus
#define meshtastic_FromRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem
#define meshtastic_FromRadio_payload_variant_metadata_MSGTYPE meshtastic_DeviceMetadata
#define meshtastic_ToRadio_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \
@@ -1104,6 +1153,19 @@ X(a, STATIC, SINGULAR, BYTES, data, 2)
#define meshtastic_Compressed_CALLBACK NULL
#define meshtastic_Compressed_DEFAULT NULL
#define meshtastic_DeviceMetadata_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, firmware_version, 1) \
X(a, STATIC, SINGULAR, UINT32, device_state_version, 2) \
X(a, STATIC, SINGULAR, BOOL, canShutdown, 3) \
X(a, STATIC, SINGULAR, BOOL, hasWifi, 4) \
X(a, STATIC, SINGULAR, BOOL, hasBluetooth, 5) \
X(a, STATIC, SINGULAR, BOOL, hasEthernet, 6) \
X(a, STATIC, SINGULAR, UENUM, role, 7) \
X(a, STATIC, SINGULAR, UINT32, position_flags, 8) \
X(a, STATIC, SINGULAR, UENUM, hw_model, 9)
#define meshtastic_DeviceMetadata_CALLBACK NULL
#define meshtastic_DeviceMetadata_DEFAULT NULL
extern const pb_msgdesc_t meshtastic_Position_msg;
extern const pb_msgdesc_t meshtastic_User_msg;
extern const pb_msgdesc_t meshtastic_RouteDiscovery_msg;
@@ -1118,6 +1180,7 @@ extern const pb_msgdesc_t meshtastic_QueueStatus_msg;
extern const pb_msgdesc_t meshtastic_FromRadio_msg;
extern const pb_msgdesc_t meshtastic_ToRadio_msg;
extern const pb_msgdesc_t meshtastic_Compressed_msg;
extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_Position_fields &meshtastic_Position_msg
@@ -1134,10 +1197,12 @@ extern const pb_msgdesc_t meshtastic_Compressed_msg;
#define meshtastic_FromRadio_fields &meshtastic_FromRadio_msg
#define meshtastic_ToRadio_fields &meshtastic_ToRadio_msg
#define meshtastic_Compressed_fields &meshtastic_Compressed_msg
#define meshtastic_DeviceMetadata_fields &meshtastic_DeviceMetadata_msg
/* Maximum encoded size of messages (where known) */
#define meshtastic_Compressed_size 243
#define meshtastic_Data_size 270
#define meshtastic_DeviceMetadata_size 44
#define meshtastic_FromRadio_size 330
#define meshtastic_LogRecord_size 81
#define meshtastic_MeshPacket_size 321

View File

@@ -222,6 +222,11 @@ typedef struct _meshtastic_ModuleConfig_TelemetryConfig {
/* We'll always read the sensor in Celsius, but sometimes we might want to
display the results in Fahrenheit as a "user preference". */
bool environment_display_fahrenheit;
/* Enable/Disable the air quality metrics */
bool air_quality_enabled;
/* Interval in seconds of how often we should try to send our
air quality metrics to the mesh */
uint32_t air_quality_interval;
} meshtastic_ModuleConfig_TelemetryConfig;
/* TODO: REPLACE */
@@ -325,7 +330,7 @@ extern "C" {
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define meshtastic_ModuleConfig_init_zero {0, {meshtastic_ModuleConfig_MQTTConfig_init_zero}}
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0}
@@ -335,7 +340,7 @@ extern "C" {
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
/* Field tags (for use in manual encoding/decoding) */
@@ -387,6 +392,8 @@ extern "C" {
#define meshtastic_ModuleConfig_TelemetryConfig_environment_measurement_enabled_tag 3
#define meshtastic_ModuleConfig_TelemetryConfig_environment_screen_enabled_tag 4
#define meshtastic_ModuleConfig_TelemetryConfig_environment_display_fahrenheit_tag 5
#define meshtastic_ModuleConfig_TelemetryConfig_air_quality_enabled_tag 6
#define meshtastic_ModuleConfig_TelemetryConfig_air_quality_interval_tag 7
#define meshtastic_ModuleConfig_CannedMessageConfig_rotary1_enabled_tag 1
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3
@@ -507,7 +514,9 @@ X(a, STATIC, SINGULAR, UINT32, device_update_interval, 1) \
X(a, STATIC, SINGULAR, UINT32, environment_update_interval, 2) \
X(a, STATIC, SINGULAR, BOOL, environment_measurement_enabled, 3) \
X(a, STATIC, SINGULAR, BOOL, environment_screen_enabled, 4) \
X(a, STATIC, SINGULAR, BOOL, environment_display_fahrenheit, 5)
X(a, STATIC, SINGULAR, BOOL, environment_display_fahrenheit, 5) \
X(a, STATIC, SINGULAR, BOOL, air_quality_enabled, 6) \
X(a, STATIC, SINGULAR, UINT32, air_quality_interval, 7)
#define meshtastic_ModuleConfig_TelemetryConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_TelemetryConfig_DEFAULT NULL
@@ -558,7 +567,7 @@ extern const pb_msgdesc_t meshtastic_ModuleConfig_CannedMessageConfig_msg;
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 2
#define meshtastic_ModuleConfig_SerialConfig_size 26
#define meshtastic_ModuleConfig_StoreForwardConfig_size 22
#define meshtastic_ModuleConfig_TelemetryConfig_size 18
#define meshtastic_ModuleConfig_TelemetryConfig_size 26
#define meshtastic_ModuleConfig_size 204
#ifdef __cplusplus

View File

@@ -45,7 +45,7 @@ typedef enum _meshtastic_TelemetrySensorType {
/* Struct definitions */
/* Key native device metrics such as battery level */
typedef struct _meshtastic_DeviceMetrics {
/* 1-100 (0 means powered) */
/* 0-100 (>100 means powered) */
uint32_t battery_level;
/* Voltage measured */
float voltage;

View File

@@ -20,7 +20,7 @@
#include "mqtt/MQTT.h"
#endif
#define DEFAULT_REBOOT_SECONDS 5
#define DEFAULT_REBOOT_SECONDS 7
AdminModule *adminModule;
bool hasOpenEditTransaction;
@@ -212,7 +212,6 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
void AdminModule::handleSetOwner(const meshtastic_User &o)
{
int changed = 0;
bool licensed_changed = false;
if (*o.long_name) {
changed |= strcmp(owner.long_name, o.long_name);
@@ -228,14 +227,12 @@ void AdminModule::handleSetOwner(const meshtastic_User &o)
}
if (owner.is_licensed != o.is_licensed) {
changed = 1;
licensed_changed = true;
owner.is_licensed = o.is_licensed;
config.lora.override_duty_cycle = owner.is_licensed; // override duty cycle for licensed operators
}
if (changed) { // If nothing really changed, don't broadcast on the network or write to flash
service.reloadOwner(!hasOpenEditTransaction);
licensed_changed ? saveChanges(SEGMENT_CONFIG | SEGMENT_DEVICESTATE) : saveChanges(SEGMENT_DEVICESTATE);
saveChanges(SEGMENT_DEVICESTATE);
}
}
@@ -493,19 +490,7 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
void AdminModule::handleGetDeviceMetadata(const meshtastic_MeshPacket &req)
{
meshtastic_AdminMessage r = meshtastic_AdminMessage_init_default;
meshtastic_DeviceMetadata deviceMetadata;
strncpy(deviceMetadata.firmware_version, myNodeInfo.firmware_version, 18);
deviceMetadata.device_state_version = DEVICESTATE_CUR_VER;
deviceMetadata.canShutdown = pmu_found || HAS_CPU_SHUTDOWN;
deviceMetadata.hasBluetooth = HAS_BLUETOOTH;
deviceMetadata.hasWifi = HAS_WIFI;
deviceMetadata.hasEthernet = HAS_ETHERNET;
deviceMetadata.role = config.device.role;
deviceMetadata.position_flags = config.position.position_flags;
deviceMetadata.hw_model = HW_VENDOR;
r.get_device_metadata_response = deviceMetadata;
r.get_device_metadata_response = getDeviceMetadata();
r.which_payload_variant = meshtastic_AdminMessage_get_device_metadata_response_tag;
myReply = allocDataProtobuf(r);
}
@@ -604,14 +589,28 @@ void AdminModule::saveChanges(int saveWhat, bool shouldReboot)
void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p)
{
// Set call sign and override lora limitations for licensed use
strncpy(owner.long_name, p.call_sign, sizeof(owner.long_name));
strncpy(owner.short_name, p.short_name, sizeof(owner.short_name));
owner.is_licensed = true;
config.lora.override_duty_cycle = true;
config.lora.tx_power = p.tx_power;
config.lora.override_frequency = p.frequency;
// Set node info broadcast interval to 10 minutes
// For FCC minimum call-sign announcement
config.device.node_info_broadcast_secs = 600;
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY;
// Remove PSK of primary channel for plaintext amateur usage
auto primaryChannel = channels.getByIndex(channels.getPrimaryIndex());
auto &channelSettings = primaryChannel.settings;
channelSettings.psk.bytes[0] = 0;
channelSettings.psk.size = 0;
channels.setChannel(primaryChannel);
channels.onConfigChanged();
service.reloadOwner(false);
service.reloadConfig(SEGMENT_CONFIG | SEGMENT_DEVICESTATE);
service.reloadConfig(SEGMENT_CONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
}
AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_APP, &meshtastic_AdminMessage_msg)

View File

@@ -5,12 +5,19 @@
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerFSM.h" // neede for button bypass
#include "detect/ScanI2C.h"
#include "mesh/generated/meshtastic/cannedmessages.pb.h"
#include "main.h" // for cardkb_found
#ifdef OLED_RU
#include "graphics/fonts/OLEDDisplayFontsRU.h"
#endif
#ifdef OLED_UA
#include "graphics/fonts/OLEDDisplayFontsUA.h"
#endif
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
// The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16
@@ -20,8 +27,12 @@
#ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU
#else
#ifdef OLED_UA
#define FONT_SMALL ArialMT_Plain_10_UA
#else
#define FONT_SMALL ArialMT_Plain_10
#endif
#endif
#define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24
#endif
@@ -35,7 +46,7 @@
// Remove Canned message screen if no action is taken for some milliseconds
#define INACTIVATE_AFTER_MS 20000
extern uint8_t cardkb_found;
extern ScanI2C::DeviceAddress cardkb_found;
static const char *cannedMessagesConfigFile = "/prefs/cannedConf.proto";
@@ -48,7 +59,7 @@ CannedMessageModule::CannedMessageModule()
{
if (moduleConfig.canned_message.enabled) {
this->loadProtoForModule();
if ((this->splitConfiguredMessages() <= 0) && (cardkb_found != CARDKB_ADDR)) {
if ((this->splitConfiguredMessages() <= 0) && (cardkb_found.address != CARDKB_ADDR)) {
LOG_INFO("CannedMessageModule: No messages are configured. Module is disabled\n");
this->runState = CANNED_MESSAGE_RUN_STATE_DISABLED;
disable();

View File

@@ -14,8 +14,10 @@
#include "modules/TraceRouteModule.h"
#include "modules/WaypointModule.h"
#if HAS_TELEMETRY
#include "modules/Telemetry/AirQualityTelemetry.h"
#include "modules/Telemetry/DeviceTelemetry.h"
#endif
#if HAS_SENSOR
#include "modules/Telemetry/AirQualityTelemetry.h"
#include "modules/Telemetry/EnvironmentTelemetry.h"
#endif
#ifdef ARCH_ESP32
@@ -63,6 +65,8 @@ void setupModules()
#endif
#if HAS_TELEMETRY
new DeviceTelemetryModule();
#endif
#if HAS_SENSOR
new EnvironmentTelemetryModule();
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I] > 0) {
new AirQualityTelemetryModule();

View File

@@ -34,20 +34,32 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies)
service.cancelSending(prevPacketId);
meshtastic_MeshPacket *p = allocReply();
p->to = dest;
p->decoded.want_response = wantReplies;
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
prevPacketId = p->id;
if (p) { // Check whether we didn't ignore it
p->to = dest;
p->decoded.want_response = wantReplies;
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
prevPacketId = p->id;
service.sendToMesh(p);
service.sendToMesh(p);
}
}
meshtastic_MeshPacket *NodeInfoModule::allocReply()
{
meshtastic_User &u = owner;
uint32_t now = millis();
// If we sent our NodeInfo less than 1 min. ago, don't send it again as it may be still underway.
if (lastSentToMesh && (now - lastSentToMesh) < 60 * 1000) {
LOG_DEBUG("Sending NodeInfo will be ignored since we just sent it.\n");
ignoreRequest = true; // Mark it as ignored for MeshModule
return NULL;
} else {
ignoreRequest = false; // Don't ignore requests anymore
meshtastic_User &u = owner;
LOG_INFO("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name);
return allocDataProtobuf(u);
LOG_INFO("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name);
lastSentToMesh = now;
return allocDataProtobuf(u);
}
}
NodeInfoModule::NodeInfoModule()
@@ -71,5 +83,5 @@ int32_t NodeInfoModule::runOnce()
sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
}
return default_broadcast_interval_secs * 1000;
return getConfiguredOrDefaultMs(config.device.node_info_broadcast_secs, default_broadcast_interval_secs);
}

View File

@@ -35,6 +35,9 @@ class NodeInfoModule : public ProtobufModule<meshtastic_User>, private concurren
/** Does our periodic broadcast */
virtual int32_t runOnce() override;
private:
uint32_t lastSentToMesh = 0; // Last time we sent our NodeInfo to the mesh
};
extern NodeInfoModule *nodeInfoModule;

View File

@@ -10,16 +10,15 @@
int32_t AirQualityTelemetryModule::runOnce()
{
#ifndef ARCH_PORTDUINO
int32_t result = INT32_MAX;
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
*/
// moduleConfig.telemetry.environment_measurement_enabled = 1;
// moduleConfig.telemetry.air_quality_enabled = 1;
if (!(moduleConfig.telemetry.environment_measurement_enabled)) {
if (!(moduleConfig.telemetry.air_quality_enabled)) {
// 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();
}
@@ -28,7 +27,7 @@ int32_t AirQualityTelemetryModule::runOnce()
// This is the first time the OSThread library has called this function, so do some setup
firstTime = 0;
if (moduleConfig.telemetry.environment_measurement_enabled) {
if (moduleConfig.telemetry.air_quality_enabled) {
LOG_INFO("Air quality Telemetry: Initializing\n");
if (!aqi.begin_I2C()) {
LOG_WARN("Could not establish i2c connection to AQI sensor\n");
@@ -39,12 +38,12 @@ int32_t AirQualityTelemetryModule::runOnce()
return result;
} else {
// if we somehow got to a second run of this module with measurement disabled, then just wait forever
if (!moduleConfig.telemetry.environment_measurement_enabled)
if (!moduleConfig.telemetry.air_quality_enabled)
return result;
uint32_t now = millis();
if (((lastSentToMesh == 0) ||
((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval))) &&
((now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval))) &&
airTime->isTxAllowedAirUtil()) {
sendTelemetry();
lastSentToMesh = now;
@@ -55,7 +54,6 @@ int32_t AirQualityTelemetryModule::runOnce()
}
}
return sendToPhoneIntervalMs;
#endif
}
bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
@@ -110,7 +108,10 @@ bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
meshtastic_MeshPacket *p = allocDataProtobuf(m);
p->to = dest;
p->decoded.want_response = false;
p->priority = meshtastic_MeshPacket_Priority_MIN;
if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR)
p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
else
p->priority = meshtastic_MeshPacket_Priority_MIN;
// release previous packet before occupying a new spot
if (lastMeasurementPacket != nullptr)

View File

@@ -10,6 +10,8 @@
#include <OLEDDisplay.h>
#include <OLEDDisplayUi.h>
#define MAGIC_USB_BATTERY_LEVEL 111
int32_t DeviceTelemetryModule::runOnce()
{
uint32_t now = millis();
@@ -48,7 +50,12 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
t.which_variant = meshtastic_Telemetry_device_metrics_tag;
t.variant.device_metrics.air_util_tx = myNodeInfo.air_util_tx;
t.variant.device_metrics.battery_level = powerStatus->getBatteryChargePercent();
if (powerStatus->getIsCharging()) {
t.variant.device_metrics.battery_level = MAGIC_USB_BATTERY_LEVEL;
} else {
t.variant.device_metrics.battery_level = powerStatus->getBatteryChargePercent();
}
t.variant.device_metrics.channel_utilization = myNodeInfo.channel_utilization;
t.variant.device_metrics.voltage = powerStatus->getBatteryVoltageMv() / 1000.0;

View File

@@ -12,7 +12,7 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu
: concurrency::OSThread("DeviceTelemetryModule"),
ProtobufModule("DeviceTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg)
{
setIntervalFromNow(10 * 1000);
setIntervalFromNow(45 * 1000); // Wait until NodeInfo is sent
}
virtual bool wantUIFrame() { return false; }

View File

@@ -52,7 +52,6 @@ SHT31Sensor sht31Sensor;
int32_t EnvironmentTelemetryModule::runOnce()
{
#ifndef ARCH_PORTDUINO
int32_t result = INT32_MAX;
/*
Uncomment the preferences below if you want to use the module
@@ -115,7 +114,6 @@ int32_t EnvironmentTelemetryModule::runOnce()
}
}
return sendToPhoneIntervalMs;
#endif
}
bool EnvironmentTelemetryModule::wantUIFrame()
@@ -246,8 +244,10 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
meshtastic_MeshPacket *p = allocDataProtobuf(m);
p->to = dest;
p->decoded.want_response = false;
p->priority = meshtastic_MeshPacket_Priority_MIN;
if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR)
p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
else
p->priority = meshtastic_MeshPacket_Priority_MIN;
// release previous packet before occupying a new spot
if (lastMeasurementPacket != nullptr)
packetPool.release(lastMeasurementPacket);

View File

@@ -12,6 +12,10 @@
#include "graphics/fonts/OLEDDisplayFontsRU.h"
#endif
#ifdef OLED_UA
#include "graphics/fonts/OLEDDisplayFontsUA.h"
#endif
/*
AudioModule
A interface to send raw codec2 audio data over the mesh network. Based on the example code from the ESP32_codec2 project.
@@ -53,8 +57,12 @@ AudioModule *audioModule;
#ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU
#else
#ifdef OLED_UA
#define FONT_SMALL ArialMT_Plain_10_UA
#else
#define FONT_SMALL ArialMT_Plain_10
#endif
#endif
#define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24
#endif

View File

@@ -56,7 +56,7 @@ int32_t RangeTestModule::runOnce()
return (5000); // Sending first message 5 seconds after initilization.
} else {
LOG_INFO("Initializing Range Test Module -- Receiver\n");
return (INT32_MAX);
return disable();
// This thread does not need to run as a receiver
}
@@ -91,17 +91,9 @@ int32_t RangeTestModule::runOnce()
return disable();
}
meshtastic_MeshPacket *RangeTestModuleRadio::allocReply()
{
auto reply = allocDataPacket(); // Allocate a packet for sending
return reply;
}
void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
{
meshtastic_MeshPacket *p = allocReply();
meshtastic_MeshPacket *p = allocDataPacket();
p->to = dest;
p->decoded.want_response = wantReplies;

View File

@@ -43,14 +43,7 @@ class RangeTestModuleRadio : public SinglePortModule
*/
bool appendFile(const meshtastic_MeshPacket &mp);
/**
* Kevin's magical calculation of two points to meters.
*/
float latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b);
protected:
virtual meshtastic_MeshPacket *allocReply() override;
/** Called to handle a particular incoming message
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for

View File

@@ -30,12 +30,14 @@ class MQTT : private concurrency::OSThread
#if HAS_ETHERNET
EthernetClient mqttClient;
#endif
#if !defined(DEBUG_HEAP_MQTT)
PubSubClient pubSub;
// instead we supress sleep from our runOnce() callback
// CallbackObserver<MQTT, void *> preflightSleepObserver = CallbackObserver<MQTT, void *>(this, &MQTT::preflightSleepCb);
public:
#else
public:
PubSubClient pubSub;
#endif
MQTT();
/**

View File

@@ -27,6 +27,9 @@
#ifndef HAS_TELEMETRY
#define HAS_TELEMETRY 1
#endif
#ifndef HAS_SENSOR
#define HAS_SENSOR 1
#endif
#ifndef HAS_RADIO
#define HAS_RADIO 1
#endif
@@ -92,6 +95,10 @@
#define HW_VENDOR meshtastic_HardwareModel_TLORA_T3_S3
#elif defined(BETAFPV_2400_TX)
#define HW_VENDOR meshtastic_HardwareModel_BETAFPV_2400_TX
#elif defined(NANO_G1_EXPLORER)
#define HW_VENDOR meshtastic_HardwareModel_NANO_G1_EXPLORER
#elif defined(BETAFPV_900_TX_NANO)
#define HW_VENDOR meshtastic_HardwareModel_BETAFPV_900_NANO_TX
#endif
//

View File

@@ -92,12 +92,12 @@ void startAdv(void)
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
// IncludeService UUID
// Bluefruit.ScanResponse.addService(meshBleService);
Bluefruit.ScanResponse.addService(meshBleService);
Bluefruit.ScanResponse.addTxPower();
Bluefruit.ScanResponse.addName();
// Include Name
// Bluefruit.Advertising.addName();
Bluefruit.Advertising.addName();
Bluefruit.Advertising.addService(meshBleService);
/* Start Advertising

View File

@@ -23,6 +23,9 @@
#ifndef HAS_TELEMETRY
#define HAS_TELEMETRY 1
#endif
#ifndef HAS_SENSOR
#define HAS_SENSOR 1
#endif
#ifndef HAS_RADIO
#define HAS_RADIO 1
#endif

View File

@@ -2,7 +2,7 @@
#include "MeshService.h"
#include "Router.h"
SimRadio::SimRadio()
SimRadio::SimRadio() : NotifiedWorkerThread("SimRadio")
{
instance = this;
}
@@ -53,10 +53,7 @@ void SimRadio::startTransmitTimer(bool withDelay)
if (!txQueue.empty()) {
uint32_t delayMsec = !withDelay ? 1 : getTxDelayMsec();
// LOG_DEBUG("xmit timer %d\n", delay);
delay(delayMsec);
onNotify(TRANSMIT_DELAY_COMPLETED);
} else {
LOG_DEBUG("TX QUEUE EMPTY!\n");
notifyLater(delayMsec, TRANSMIT_DELAY_COMPLETED, false);
}
}
@@ -66,8 +63,7 @@ void SimRadio::startTransmitTimerSNR(float snr)
if (!txQueue.empty()) {
uint32_t delayMsec = getTxDelayMsecWeighted(snr);
// LOG_DEBUG("xmit timer %d\n", delay);
delay(delayMsec);
onNotify(TRANSMIT_DELAY_COMPLETED);
notifyLater(delayMsec, TRANSMIT_DELAY_COMPLETED, false);
}
}
@@ -142,11 +138,12 @@ void SimRadio::onNotify(uint32_t notification)
switch (notification) {
case ISR_TX:
handleTransmitInterrupt();
LOG_DEBUG("tx complete - starting timer\n");
// LOG_DEBUG("tx complete - starting timer\n");
startTransmitTimer();
break;
case ISR_RX:
LOG_DEBUG("rx complete - starting timer\n");
// LOG_DEBUG("rx complete - starting timer\n");
startTransmitTimer();
break;
case TRANSMIT_DELAY_COMPLETED:
LOG_DEBUG("delay done\n");
@@ -170,8 +167,7 @@ void SimRadio::onNotify(uint32_t notification)
uint32_t xmitMsec = getPacketTime(txp);
airTime->logAirtime(TX_LOG, xmitMsec);
delay(xmitMsec); // Model the time it is busy sending
completeSending();
notifyLater(xmitMsec, ISR_TX, false); // Model the time it is busy sending
}
}
} else {
@@ -242,8 +238,7 @@ void SimRadio::handleReceiveInterrupt(meshtastic_MeshPacket *p)
xmitMsec = getPacketTime(length);
// LOG_DEBUG("Payload size %d vs length (includes header) %d\n", p->decoded.payload.size, length);
meshtastic_MeshPacket *mp = packetPool.allocCopy(*p); // keep a copy in packtPool
mp->which_payload_variant = meshtastic_MeshPacket_decoded_tag; // Mark that the payload is already decoded
meshtastic_MeshPacket *mp = packetPool.allocCopy(*p); // keep a copy in packetPool
printPacket("Lora RX", mp);
@@ -268,4 +263,4 @@ int16_t SimRadio::readData(uint8_t *data, size_t len)
}
return state;
}
}

View File

@@ -3,10 +3,11 @@
#include "MeshPacketQueue.h"
#include "RadioInterface.h"
#include "api/WiFiServerAPI.h"
#include "concurrency/NotifiedWorkerThread.h"
#include <RadioLib.h>
class SimRadio : public RadioInterface
class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThread
{
enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED };

View File

@@ -2,15 +2,18 @@
#define ARCH_PORTDUINO
//
// defaults for NRF52 architecture
//
//
// set HW_VENDOR
//
#define HW_VENDOR meshtastic_HardwareModel_PORTDUINO
#define HAS_RTC 1
#ifndef HAS_WIFI
#define HAS_WIFI 1
#endif
#ifndef HAS_RTC
#define HAS_RTC 1
#endif
#ifndef HAS_TELEMETRY
#define HAS_TELEMETRY 1
#endif

View File

@@ -1,6 +1,7 @@
[env:pca10059_diy_eink]
extends = nrf52840_base
board = nordic_pca10059
board_level = extra
build_flags = ${nrf52840_base.build_flags} -Ivariants/Dongle_nRF52840-pca10059-v1 -D NORDIC_PCA10059
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/Dongle_nRF52840-pca10059-v1>
lib_deps =

View File

@@ -1,6 +1,7 @@
[env:betafpv_2400_tx_micro]
extends = esp32_base
board = esp32doit-devkit-v1
board_level = extra
build_flags =
${esp32_base.build_flags}
-D BETAFPV_2400_TX

View File

@@ -0,0 +1,16 @@
[env:betafpv_900_tx_nano]
extends = esp32_base
board = esp32doit-devkit-v1
build_flags =
${esp32_base.build_flags}
-D BETAFPV_900_TX_NANO
-D VTABLES_IN_FLASH=1
-D CONFIG_DISABLE_HAL_LOCKS=1
-O2
-I variants/betafpv_900_tx_nano
board_build.f_cpu = 240000000L
upload_protocol = esptool
upload_port = /dev/ttyUSB0
upload_speed = 460800
lib_deps =
${esp32_base.lib_deps}

View File

@@ -0,0 +1,28 @@
// https://betafpv.com/products/elrs-nano-tx-module
// no screen
#define HAS_SCREEN 0
// NO GPS
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define USE_RF95
#define RF95_SCK 18
#define RF95_MISO 19
#define RF95_MOSI 23
#define RF95_NSS 5
#define LORA_DIO0 4
#define LORA_RESET 14
#define LORA_DIO1 2
#define LORA_DIO2
#define LORA_DIO3
#define LED_PIN 16 // green - blue is at 17
#define BUTTON_PIN 25
#define BUTTON_NEED_PULLUP
#undef EXT_NOTIFY_OUT

View File

@@ -2,6 +2,7 @@
[env:meshtastic-diy-v1]
extends = esp32_base
board = esp32doit-devkit-v1
board_level = extra
build_flags =
${esp32_base.build_flags}
-D DIY_V1
@@ -13,6 +14,7 @@ build_flags =
[env:meshtastic-diy-v1.1]
extends = esp32_base
board = esp32doit-devkit-v1
board_level = extra
build_flags =
${esp32_base.build_flags}
-D DIY_V1
@@ -24,6 +26,7 @@ build_flags =
[env:meshtastic-dr-dev]
extends = esp32_base
board = esp32doit-devkit-v1
board_level = extra
board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 532480
build_flags =

View File

@@ -2,6 +2,7 @@
[env:feather_diy]
extends = nrf52840_base
board = adafruit_feather_nrf52840
board_level = extra
build_flags = ${nrf52840_base.build_flags} -Ivariants/feather_diy -Dfeather_diy
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/feather_diy>
lib_deps =

View File

@@ -1,7 +0,0 @@
; The GenieBlocks LORA prototype board
; note: @geeksville disabled because genieblocks_lora is not checked into the boards directory, please send in a PR to add it ;-)
;[env:genieblocks_lora]
;extends = esp32_base
;board = genieblocks_lora
;build_flags =
; ${esp32_base.build_flags} -D GENIEBLOCKS -Ivariants/genieblocks

View File

@@ -1,26 +0,0 @@
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 5
#define GPS_TX_PIN 18
#define GPS_RESET_N 10
#define GPS_EXTINT 23 // On MAX-M8 module pin name is EXTINT. On L70 module pin name is STANDBY.
#define BATTERY_PIN 39 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define BATTERY_EN_PIN 14 // Voltage voltage divider enable pin connected to mosfet
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 2
#define LED_PIN 12 // If defined we will blink this LED
//#define BUTTON_PIN 36 // If defined, this will be used for user button presses (ToDo problem on that line on debug screen -->
// Long press start!) #define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs input only pins. These pins dont have internal
// pull-ups or pull-down resistors.
#define USE_RF95
#define LORA_DIO0 38 // a No connect on the SX1262 module
#define LORA_RESET 9
#define RF95_SCK 22
#define RF95_MISO 19
#define RF95_MOSI 13
#define RF95_NSS 21

View File

@@ -1,6 +1,7 @@
[env:heltec-v1]
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board_level = extra
board = heltec_wifi_lora_32
build_flags =
${esp32_base.build_flags} -D HELTEC_V1 -I variants/heltec_v1

View File

@@ -20,8 +20,8 @@
#ifndef USE_JTAG
#define LORA_RESET 14
#endif
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#define LORA_DIO1 RADIOLIB_NC
#define LORA_DIO2 32 // Not really used
// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
#define ADC_MULTIPLIER 3.2

View File

@@ -2,5 +2,6 @@
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32_V2
board_level = extra
build_flags =
${esp32_base.build_flags} -D HELTEC_V2_1 -I variants/heltec_v2.1

View File

@@ -24,7 +24,7 @@
#ifndef USE_JTAG
#define LORA_RESET 14
#endif
#define LORA_DIO1 35 // Not really used
#define LORA_DIO1 35 // https://www.thethingsnetwork.org/forum/t/big-esp32-sx127x-topic-part-3/18436
#define LORA_DIO2 34 // Not really used
#define ADC_MULTIPLIER 3.8

View File

@@ -2,5 +2,6 @@
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32_V2
board_level = extra
build_flags =
${esp32_base.build_flags} -D HELTEC_V2_0 -I variants/heltec_v2

View File

@@ -21,7 +21,7 @@
#ifndef USE_JTAG
#define LORA_RESET 14
#endif
#define LORA_DIO1 35 // Not really used
#define LORA_DIO1 35 // https://www.thethingsnetwork.org/forum/t/big-esp32-sx127x-topic-part-3/18436
#define LORA_DIO2 34 // Not really used
// ratio of voltage divider = 3.20 (R12=100k, R10=220k)

View File

@@ -1,9 +1,6 @@
[env:heltec-v3]
platform = https://github.com/Baptou88/platform-espressif32.git
extends = esp32s3_base
board = heltec_wifi_lora_32_V3
# Temporary until espressif creates a release with this new target
platform_packages =
framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git
build_flags =
${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/heltec_v3

View File

@@ -1,9 +1,6 @@
[env:heltec-wsl-v3]
platform = https://github.com/Baptou88/platform-espressif32.git
extends = esp32s3_base
board = heltec_wifi_lora_32_V3
# Temporary until espressif creates a release with this new target
platform_packages =
framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git
build_flags =
${esp32s3_base.build_flags} -D HELTEC_WSL_V3 -I variants/heltec_wsl_v3

View File

@@ -1,6 +1,7 @@
[env:lora_isp4520]
extends = nrf52_base
board = lora_isp4520
board_level = extra
# add our variants files to the include and src paths
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_isp4520

View File

@@ -2,6 +2,7 @@
[env:lora-relay-v1]
extends = nrf52840_base
board = lora-relay-v1
board_level = extra
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v1

View File

@@ -2,6 +2,7 @@
[env:lora-relay-v2]
extends = nrf52840_base
board = lora-relay-v2
board_level = extra
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v2

View File

@@ -1,6 +1,7 @@
[env:m5stack-core]
extends = esp32_base
board = m5stack-core-esp32
board_level = extra
upload_port = COM8
monitor_port = COM8
monitor_filters = esp32_exception_decoder

Some files were not shown because too many files have changed in this diff Show More