Compare commits

...

60 Commits

Author SHA1 Message Date
Kevin Hester
b6740548f3 todo update 2021-08-28 13:46:28 -07:00
Kevin Hester
5fe3ec09de Merge pull request #840 from geeksville/dev
bugs
2021-08-18 12:35:49 -07:00
Kevin Hester
079843d777 add native build to bin zip 2021-08-18 11:10:20 -07:00
Kevin Hester
bd7171a7a2 1.2.45 2021-08-18 10:57:26 -07:00
Kevin Hester
eaa15076cd WIP debug logging over TCP 2021-08-18 10:31:30 -07:00
Kevin Hester
2fd74d8f47 cleanup ssl cert generation 2021-08-17 20:40:46 -07:00
Kevin Hester
0e91d39b27 don't shutdown bluetooth if we didn't start it 2021-08-17 20:40:13 -07:00
Kevin Hester
52d7a6b8e4 immediately reconnect to mqtt server on wifi reconnect 2021-08-17 19:59:56 -07:00
Kevin Hester
472e880280 fix race condition when starting web service 2021-08-17 17:04:09 -07:00
Kevin Hester
189889489b disable bluetooth while using wifi (esp32 drops networks otherwise) 2021-08-17 16:58:21 -07:00
Kevin Hester
0d758347af Fix rare assertion failure which could occur due to pending interrupts
* fix assertion failure
```
22:57:36 64409 [PositionPlugin] FIXME-update-db Sniffing packet
22:57:36 64409 [PositionPlugin] Delivering rx packet (id=0x5851f437 Fr0xa1 To0xff, WantAck0, HopLim3 Ch0x0 Portnum=3 rxtime=1628895456 priority=10)
22:57:36 64409 [PositionPlugin] Forwarding to phone (id=0x5851f437 Fr0xa1 To0xff, WantAck0, HopLim3 Ch0x0 Portnum=3 rxtime=1628895456 priority=10)
22:57:36 64409 [PositionPlugin] Update DB node 0x85f4da1, rx_time=1628895456
22:57:36 64409 [PositionPlugin] Plugin routing considered
22:57:36 64409 [PositionPlugin] Add packet record (id=0x5851f437 Fr0xa1 To0xff, WantAck0, HopLim3 Ch0x0 Portnum=3 rxtime=1628895456 priority=10)
22:57:36 64409 [PositionPlugin] Expanding short PSK #1
22:57:36 64409 [PositionPlugin] Installing AES128 key!
22:57:36 64409 [PositionPlugin] enqueuing for send (id=0x5851f437 Fr0xa1 To0xff, WantAck0, HopLim3 Ch0xb1 encrypted rxtime=1628895456 priority=10)
22:57:36 64409 [PositionPlugin] (bw=125, sf=12, cr=4/8) packet symLen=32 ms, payloadSize=22, time 2596 ms
22:57:36 64409 [PositionPlugin] txGood=6,rxGood=10,rxBad=0
22:57:36 64409 [PositionPlugin] AirTime - Packet transmitted : 2596ms
22:57:36 64409 [RadioIf] assert failed src/mesh/RadioLibInterface.cpp: 240, void RadioLibInterface::handleReceiveInterrupt(), test=isReceiving
```
2021-08-17 16:31:01 -07:00
Kevin Hester
3266d57cfb todo updates 2021-08-17 16:14:08 -07:00
Kevin Hester
f2c9c5553c Merge pull request #839 from geeksville/dev
bugs
2021-08-15 10:52:51 -07:00
Kevin Hester
bcdc42816b 1.2.44 2021-08-15 10:35:07 -07:00
Kevin Hester
b04e313665 minor debug output 2021-08-15 10:34:57 -07:00
Kevin Hester
700e799125 check our host PC using the new nrf52 api 2021-08-12 22:07:30 -07:00
Kevin Hester
a9f8080ee7 cope with race on available() vs read() found while looking at #838 2021-08-12 22:06:51 -07:00
Kevin Hester
9f450cb1c5 Merge pull request #837 from claesg/master
No SuperDeepSleep for RAK4631 and T-Echo
2021-08-12 17:01:28 -07:00
Kevin Hester
388f19da79 Merge branch 'master' into master 2021-08-12 16:32:52 -07:00
Kevin Hester
4f11598112 Merge pull request #831 from geeksville/dev
bugs
2021-08-12 16:32:37 -07:00
Kevin Hester
bcb54b643f Merge branch 'master' into dev 2021-08-12 16:09:30 -07:00
Kevin Hester
04d3f44179 Updates to work with latest adafruit nrf52 arduino 2021-08-12 15:50:54 -07:00
claes
5110a6de82 Battery sense for T-Echo
Copied battery stuff from RAK4631 to T-Echo
I got the voltage divider figures for T_Echo from SoftRF at
https://github.com/lyusupov/SoftRF/blob/master/software/firmware/source/SoftRF/src/platform/nRF52.h

I dont have a T-Echo so this code
HAS NOT BEEN TESTED
2021-08-10 10:07:40 +02:00
claes
04c5ac0d7c Voltage and sleep fix for NRF52
Dont let the NRF52 go to SDS Super Deep Sleep
Show bat percentage on NRF52 when above 4210 mV
2021-08-10 09:23:26 +02:00
Kevin Hester
6d2cd73599 show a max of four node screens in the scrolling list 2021-08-04 09:10:34 -07:00
Kevin Hester
057b04a88a treat RECEIVED_PACKET like PACKET_FOR_PHONE 2021-08-02 22:07:39 -07:00
Kevin Hester
28af18389b If MQTT connected don't let the board enter LS state 2021-08-02 21:34:14 -07:00
Kevin Hester
2af4c619e1 fix #801 (I think) we were sometimes dropping packets in light sleep
Because of failure to enter the NB state packets were not getting queued
for sending.
2021-08-02 21:07:32 -07:00
Kevin Hester
99d529be51 While connected to MQTT server, veto light-sleep (to keep wifi working) 2021-08-02 17:42:44 -07:00
Kevin Hester
39df7108a8 fix wifi hang when bad password used, cleanup wifi in general 2021-08-02 11:28:57 -07:00
Kevin Hester
72807f0fa0 CSE to cleanup mqtt addr setting 2021-08-02 10:50:55 -07:00
Kevin Hester
2fe11d4fe8 don't break strict-aliasing rules 2021-08-02 10:50:28 -07:00
Kevin Hester
596befff74 Fix invalid heap reference fixed by @flux242 2021-08-02 10:41:31 -07:00
Kevin Hester
b2524ceaff Merge pull request #830 from dmitryelj/master
USE_SH1106 compilation error fix
2021-08-01 14:06:42 -07:00
Kevin Hester
5f323e8bd1 fix leakage of wifi password reported by @vodkin 2021-08-01 12:58:23 -07:00
Kevin Hester
d40b66beac Allow plugins to write to the parsed protobuf (minimizes copies in some cases) 2021-08-01 12:58:23 -07:00
Dmitrii Eliuseev
afa12d6e87 USE_SH1106 error fix
Fix for USE_SH1106 compilation error
2021-08-01 20:15:02 +02:00
Kevin Hester
676a6f3bea Merge pull request #829 from audunf/mesh-packet-queue-priority
Drop lower priority packets when tx queue is full.
2021-08-01 10:40:13 -07:00
Audun Foyen
bf0b598908 Include <algorithm> - required for 'lower_bound' 2021-07-31 21:56:31 +02:00
Audun Foyen
8a79663fa0 Drop lower priority packets when tx queue is full.
Track packet pointers in vector. Priority maintained using: push_heap, pop_heap, make_heap, and sort_heap.
2021-07-31 21:42:48 +02:00
Kevin Hester
564262e75b Merge pull request #824 from geeksville/dev
1.2.43
2021-07-27 03:05:28 +08:00
Kevin Hester
a405d81c46 1.2.43 2021-07-26 10:26:53 -07:00
Kevin Hester
aac3143745 Merge remote-tracking branch 'mine/dev' into dev
# Conflicts:
#	version.properties
2021-07-26 10:14:46 -07:00
Kevin Hester
bb396508a4 Merge pull request #822 from audunf/issue-108
Track recent packets in unordered_set
2021-07-26 04:53:13 +08:00
Kevin Hester
810740b156 Merge branch 'master' into issue-108 2021-07-26 04:31:05 +08:00
Kevin Hester
19ffddb02e Merge pull request #819 from thebentern/patch-1
Convert MQTT server user preference to hostname:port
2021-07-26 04:30:52 +08:00
Kevin Hester
5826c52242 Merge branch 'master' into issue-108 2021-07-26 04:23:33 +08:00
Kevin Hester
a6904105f7 Merge branch 'master' into patch-1 2021-07-26 04:08:08 +08:00
Kevin Hester
da8ab82126 Merge pull request #823 from claesg/master
Fix for reading battery level on RAK-4631
2021-07-26 04:07:00 +08:00
claes
978bb7aa8b Fix for build error on T-Echo 2021-07-25 19:37:00 +02:00
claes
32fea4cbd7 Fix for reading battery level on RAK-4631
Build tested on RAK4631 with battery and their solar panel box.
This is from the log:
17:40:30 102 [Power] Battery: usbPower=0, isCharging=0, batMv=4164, batPct=96
Note that mV reading and Pct is ok.
It does not detect being connected to USB and charging.

Also tested on TBEAM where it seems to be ok.

There still seems to be a problem with the FW for this board that it goes to
sleep for ever after running for a few hours.
2021-07-25 18:25:11 +02:00
claes
6e136b9796 Fix for reading battery level on RAK-4631
Build tested on RAK4631 with battery and their solar panel box.
This is from the log:
17:40:30 102 [Power] Battery: usbPower=0, isCharging=0, batMv=4164, batPct=96
Note that mV reading and Pct is ok.
It does not detect being connected to USB and charging.

Also tested on TBEAM where it seems to be ok.

There still seems to be a problem with the FW for this board that it goes to
sleep for ever after running for a few hours.
2021-07-24 19:47:57 +02:00
Audun Foyen
986d44873a Issue-108. Track recent packets in unordered_set
Check individual packets seen recently for expiry - and purge.
Otherwise - only scan all of recentPackets for expired once
fill > 75% (of MAX_NUM_NODES).
2021-07-20 21:19:35 +02:00
Sacha Weatherstone
2e1746ca0f Merge pull request #820 from meshtastic/sachaw-patch-1
Update README.md
2021-07-09 13:56:15 +10:00
Sacha Weatherstone
863b60277b Update README.md 2021-07-09 13:36:37 +10:00
Ben Meadors
035f25190b Handle MQTT host string with port omitted 2021-07-02 07:47:12 -05:00
Ben Meadors
3ea03dadb5 Convert MQTT server to hostname:port 2021-07-01 16:57:50 -05:00
Kevin Hester
753ae00ddb Merge pull request #818 from geeksville/master
Master
2021-07-01 23:50:57 +08:00
Kevin Hester
eb9e976fab 1.2.39 2021-05-29 13:19:05 +08:00
Kevin Hester
451b085c13 update protos 2021-05-28 11:01:01 +08:00
51 changed files with 608 additions and 599 deletions

214
README.md
View File

@@ -1,213 +1,5 @@
# Meshtastic-device
[![Open in Visual Studio Code](https://open.vscode.dev/badges/open-in-vscode.svg)](https://open.vscode.dev/meshtastic/Meshtastic-device)
## This repository contains the device firmware used in the [Meshtastic](https://meshtastic.org) project.
This is the device side code for the [meshtastic.org](https://www.meshtastic.org) project.
![Continuous Integration](https://github.com/meshtastic/Meshtastic-esp32/workflows/Continuous%20Integration/badge.svg)
Meshtastic® is a project that lets you use
inexpensive GPS mesh radios as an extensible, super long battery life mesh GPS communicator. These radios are great for hiking, skiing, paragliding -
essentially any hobby where you don't have reliable internet access. Each member of your private mesh can always see the location and distance of all other
members and any text messages sent to your group chat.
The radios automatically create a mesh to forward packets as needed, so everyone in the group can receive messages from even the furthest member. The radios
will optionally work with your phone, but no phone is required.
Typical time between recharging the radios should be about eight days.
This project is is currently in beta-testing - if you have questions please [join our discussion forum](https://meshtastic.discourse.group/).
This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the chat.
## Supported hardware
We currently support three models of radios.
- TTGO T-Beam (usually the recommended choice)
- [T-Beam V1.1 w/ NEO-6M - special Meshtastic version](https://www.aliexpress.com/item/4001178678568.html) (Includes built-in OLED display and they have **preinstalled** the meshtastic software)
- [T-Beam V1.1 w/ NEO-M8N](https://www.aliexpress.com/item/33047631119.html) (slightly better GPS)
- [T-Beam V1.1 w/ NEO-M8N /w SX1262](https://www.aliexpress.com/item/4001287221970.html) (slightly better GPS + LoRa)
- board labels "TTGO T22_V1.1 20191212"
- [T-Beam V0.7 w/ NEO-6M](https://www.aliexpress.com/item/4000574335430.html) (will work but **you must use the tbeam0.7 firmware ** - but the T-Beam V1.0 or later are better!)
- board labels "TTGO T22_V07 20180711"
- 3D printable cases
- [T-Beam V0](https://www.thingiverse.com/thing:3773717) (GPS and LoRa antenna misaligned if GPS placed as pictured)
- [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:3830711)
- [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:4677388) (Mounting option for larger GPS antenna but LoRa antenna enclosed)
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4587297) (GPS and LoRa antenna misaligned if GPS placed as pictured)
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4589651)
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4619981) (GPS and LoRa antenna misaligned if GPS placed as pictured)
- Laser-cut cases
- [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:4552771)
- [TTGO LORA32](https://www.aliexpress.com/item/4000211331316.html) - No GPS
- version 2.1
- board labels "TTGO T3_V1.6 20180606"
- 3D printable case
- [TTGO LORA32 v1](https://www.thingiverse.com/thing:3385109)
- [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/) - No GPS
- [Official Heltec case](https://www.aliexpress.com/item/4001050707951.html)
- [3D Printable case](https://www.thingiverse.com/thing:3125854)
Note: The GPS and LoRa stock antennas should be placed in a way, that the GPS antenna faces the sky and the LoRa antenna radiates 360 degrees horizontally. For better GPS reception you might want to [upgrade the GPS antenna](https://meshtastic.discourse.group/t/the-importance-of-gps-antennas-and-request-to-3d-case-documentation-people/1505) and to properly align the antennas you might want to upgrade to a LoRa antenna that can be adjusted to radiate into the right directions.
**Make sure to get the frequency for your country**
- US/JP/AU/NZ/CA - 915MHz
- CN - 470MHz
- EU - 868MHz, 433MHz
- full list of LoRa frequencies per region is available [here](https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html)
Getting a version that includes a screen is optional, but highly recommended.
## Firmware Installation
Prebuilt binaries for the supported radios are available in our [releases](https://github.com/meshtastic/Meshtastic-esp32/releases). Your initial installation has to happen over USB from your Mac, Windows or Linux PC. Once our software is installed, all future software updates happen over bluetooth from your phone.
Be **very careful** to install the correct load for your board. In particular the popular 'T-BEAM' radio from TTGO is not called 'TTGO-Lora' (that is a different board). So don't install the 'TTGO-Lora' build on a TBEAM, it won't work correctly.
Please post comments on our [group chat](https://meshtastic.discourse.group/) if you have problems or successes.
### Installing from a GUI - Windows and Mac
1. Download and unzip the latest Meshtastic firmware [release](https://github.com/meshtastic/Meshtastic-esp32/releases).
2. Download [ESPHome Flasher](https://github.com/esphome/esphome-flasher/releases) (either x86-32bit Windows or x64-64 bit Windows).
3. Connect your radio to your USB port and open ESPHome Flasher.
4. If your board is not showing under Serial Port then you likely need to install the drivers for the CP210X serial chip. In Windows you can check by searching “Device Manager” and ensuring the device is shown under “Ports”.
5. If there is an error, download the drivers [here](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers), then unzip and run the Installer application.
6. In ESPHome Flasher, refresh the serial ports and select your board.
7. Browse to the previously downloaded firmware and select the correct firmware based on the board type, country and frequency.
8. Select Flash ESP.
9. Once complete, “Done! Flashing is complete!” will be shown.
10. Debug messages sent from the Meshtastic device can be viewed with a terminal program such as [PuTTY](https://www.putty.org/) (Windows only). Within PuTTY, click “Serial”, enter the “Serial line” com port (can be found at step 4), enter “Speed” as 921600, then click “Open”.
### Installing from a commandline
These instructions currently require a few commmand lines, but it should be pretty straightforward.
1. Install "pip". Pip is the python package manager we use to get the esptool installer app. Instructions [here](https://www.makeuseof.com/tag/install-pip-for-python/). If you are using OS-X, see these [special instructions](docs/software/install-OSX.md).
2. Run "pip install --upgrade esptool" to get esptool installed on your machine.
3. Connect your radio to your USB port.
4. Confirm that your device is talking to your PC by running "esptool.py chip_id". The Heltec build also works on the TTGO LORA32 radio. You should see something like:
```
mydir$ esptool.py chip_id
esptool.py v2.6
Found 2 serial ports
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 24:6f:28:b5:36:71
Uploading stub...
Running stub...
Stub running...
Warning: ESP32 has no Chip ID. Reading MAC instead.
MAC: 24:6f:28:b5:36:71
Hard resetting via RTS pin...
```
5. cd into the directory where the release zip file was expanded.
6. Install the correct firmware for your board with `device-install.sh -f firmware-_board_-_country_.bin`.
- Example: `./device-install.sh -f firmware-HELTEC-US-0.0.3.bin`.
7. To update run `device-update.sh -f firmware-_board_-_country_.bin`
- Example: `./device-update.sh -f firmware-HELTEC-US-0.0.3.bin`.
Note: If you have previously installed meshtastic, you don't need to run this full script instead just run `esptool.py --baud 921600 write_flash 0x10000 firmware-_board_-_country_-_version_.bin`. This will be faster, also all of your current preferences will be preserved.
You should see something like this:
```
kevinh@kevin-server:~/development/meshtastic/meshtastic-esp32/release/latest$ ./device-install.sh firmware-TBEAM-US-0.1.8.bin
Trying to flash firmware-TBEAM-US-0.1.8.bin, but first erasing and writing system information
esptool.py v2.6
Found 2 serial ports
Serial port /dev/ttyUSB0
Connecting........____
Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 24:6f:28:b2:01:6c
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Erasing flash (this may take a while)...
Chip erase completed successfully in 6.1s
Hard resetting via RTS pin...
esptool.py v2.6
Found 2 serial ports
Serial port /dev/ttyUSB0
Connecting.......
Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 24:6f:28:b2:01:6c
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Flash params set to 0x0220
Compressed 61440 bytes to 11950...
Wrote 61440 bytes (11950 compressed) at 0x00001000 in 0.2 seconds (effective 3092.4 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
esptool.py v2.6
Found 2 serial ports
Serial port /dev/ttyUSB0
Connecting.....
Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 24:6f:28:b2:01:6c
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 1223568 bytes to 678412...
Wrote 1223568 bytes (678412 compressed) at 0x00010000 in 10.7 seconds (effective 912.0 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
```
7. The board will boot and show the Meshtastic logo.
8. Please post a comment on our chat so we know if these instructions worked for you ;-). If you find bugs/have-questions post there also - we will be rapidly iterating over the next few weeks.
# Meshtastic Android app
The companion (optional, free, open-source) Meshtastic Android app is available on various appstores [see this page for details](https://github.com/meshtastic/Meshtastic-Android/blob/master/README.md).
# Python API
We offer a [python API](https://github.com/meshtastic/Meshtastic-python) that makes it easy to use these devices to provide mesh networking for your custom projects.
# Development
We'd love to have you join us on this merry little project. Please see our [development documents](https://meshtastic.org/docs/software/other/sw-design) and [join us in our discussion forum](https://meshtastic.discourse.group/).
# Credits
This project is run by volunteers. We are a friendly group and welcome any contribution (code fixes, documentation, features, bug reports etc...). We try to be good about listing contributor names in release notes, but it has become unwieldy for the main-devs to keep updating the list below and we've neglected it too long. If you'd like your name included in this list please send a pull request to edit this README and simply add your line yourself. Thank you very much for your help!
- @astro-arphid: Added support for 433MHz radios in europe.
- @claesg: Various documentation fixes and 3D print enclosures
- @girtsf: Lots of improvements
- @spattinson: Fixed interrupt handling for the AXP192 part
# IMPORTANT DISCLAIMERS AND FAQ
For a listing of currently missing features and a FAQ click [here](docs/faq.md).
Copyright 2019 Geeksville Industries, LLC. GPL V3 Licensed.
For developer information and specific building instructions, please see the [developer doccumentation](https://meshtastic.org/docs/developers)

View File

@@ -72,6 +72,9 @@ platformio lib update
do_boards "$BOARDS_ESP32" "false"
do_boards "$BOARDS_NRF52" "true"
pio run --environment native
cp .pio/build/native/program $OUTDIR/bins/universal/meshtasticd_linux_amd64
echo "Building SPIFFS for ESP32 targets"
pio run --environment tbeam -t buildfs
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/spiffs-$VERSION.bin
@@ -99,7 +102,7 @@ XML
echo Generating $ARCHIVEDIR/firmware-$VERSION.zip
rm -f $ARCHIVEDIR/firmware-$VERSION.zip
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/spiffs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* images/system-info.bin bin/device-install.* bin/device-update.*
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/spiffs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* $OUTDIR/bins/universal/meshtasticd* images/system-info.bin bin/device-install.* bin/device-update.*
echo Generating $ARCHIVEDIR/elfs-$VERSION.zip
rm -f $ARCHIVEDIR/elfs-$VERSION.zip
zip --junk-paths $ARCHIVEDIR/elfs-$VERSION.zip $OUTDIR/elfs/universal/firmware-*-$VERSION.*

View File

@@ -2,20 +2,19 @@
You probably don't care about this section - skip to the next one.
* list portduino on platformio
* router mode dropping messages? https://meshtastic.discourse.group/t/router-mode-missing-messages/3329/3
* fix ttgo eink screen
* figure our wss for mqtt.meshtastic - use cloudflare? 2052 ws, 2053 crypt
* usb lora dongle from pine64, add end user instructions
* measure rak4630 power draw and turn off power for GPS most of the time. We should be able to run on the small solar panel.
* pine64 lora module
* @havealoha fixedposition not working
* turn on watchdog reset if app hangs on nrf52 or esp32
* pine64 solar boards
* for the matrix gateway? recommended by @sam-uk https://github.com/matrix-org/coap-proxy
* figure our wss for mqtt.meshtastic - use cloudflare? 2052 ws, 2053 crypt
* ask for vercel access
* finish plan for riot.im
* turn on setTx(timeout) and state = setDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT); in sx1262 code
* add rak4600 support (with rf95 radio and limited ram)
* NO add rak4600 support (with rf95 radio and limited ram)
* store esp32 crashes to flash (and 64KB coredump partition) - https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/core_dump.html
*
* Switch to use https://github.com/adafruit/Adafruit_nRF52_Arduino.git when available (see arduino code for examples)
* If more nodes appear than the nodedb can hold, delete oldest entries from DB
* send debug info 'in-band'
* DONE @luxonn reports that after a while the android app stops showing new messages
* DONE release android APK - fix recent 1.2.28 crash report
* DONE remote admin busted?
@@ -28,7 +27,6 @@ You probably don't care about this section - skip to the next one.
* DONE tcp stream problem in python+pordtuino, server thinks client dropped when client DID NOT DROP
* DONE TCP mode for android, localhost is at 10.0.2.2
* DONE make sure USB still works in android
* add portduino builds to zip
* add license to portduino and make announcement
* DONE naks are being dropped (though enqueuedLocal) sometimes before phone/PC gets them
* DONE have android fill in if local GPS has poor signal

View File

@@ -0,0 +1,23 @@
* nutcracker https://www.pine64.org/2020/10/28/nutcracker-challenge-blob-free-wifi-ble/
* https://github.com/pine64/bl_iot_sdk
* https://github.com/pine64/bl602-docs / https://pine64.github.io/bl602-docs/
* https://github.com/pine64/ArduinoCore-bouffalo
cd ~/packages
git clone --recursive https://github.com/pine64/bl_iot_sdk
https://github.com/spacemeowx2/blflash/releases
# FIXME or BL604
cd bl_iot_sdk
export BL60X_SDK_PATH=/home/kevinh/packages/bl_iot_sdk
export CONFIG_CHIP_NAME=BL602
cd customer_app/bl602_boot2
make
* todo run hello world on hardware (check for bl604 vs bl602 first)
* build/run in the crummy arduino environment
* build in platformio

View File

@@ -9,14 +9,14 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = tbeam
;default_envs = tbeam
;default_envs = tbeam0.7
;default_envs = heltec-v2.0
;default_envs = tlora-v1
;default_envs = tlora_v1_3
;default_envs = tlora-v2
;default_envs = lora-relay-v1 # nrf board
;default_envs = t-echo
default_envs = t-echo
;default_envs = nrf52840dk-geeksville
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
;default_envs = rak4631
@@ -70,7 +70,7 @@ lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
https://github.com/meshtastic/arduino-fsm.git#829e967b8a95c094f73c60ef8dacfe66eae38940
https://github.com/meshtastic/arduino-fsm.git
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
https://github.com/meshtastic/RadioLib.git#80ed10d689a0568782c5bd152906b0f97d2bce93
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
@@ -218,7 +218,7 @@ src_filter =
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<plugins/esp32> -<mqtt/>
lib_ignore =
BluetoothOTA
monitor_port = /dev/ttyACM1
; monitor_port = /dev/ttyACM1
# we pass in options to jlink so it can understand freertos (note: we don't use "jlink" as the tool)
;debug_tool = jlink
@@ -255,9 +255,12 @@ debug_init_break =
[nrf52840_base]
; Common base class for all nrf52840 based targets
extends = nrf52_base
; was -DTINY_USB
build_flags = ${nrf52_base.build_flags}
lib_deps =
${arduino_base.lib_deps}
Adafruit nRFCrypto
# Adafruit TinyUSB Arduino
# add Adafruit nRFCrypto platform IO automated scan is broken
[env:lora_isp4520]
@@ -315,7 +318,7 @@ extends = nrf52840_base
board = wiscore_rak4631
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52_base.build_flags} -Ivariants/WisCore_RAK4631_Board
build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board>
debug_tool = jlink
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
@@ -354,10 +357,13 @@ lib_deps =
[env:t-echo]
extends = nrf52840_base
board = t-echo
debug_tool = jlink
upload_protocol = jlink
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library - NOTE: WE NOT LONGER USE TFT_eSPI, it was for an earlier version of the TTGO eink screens
# -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
build_flags = ${nrf52_base.build_flags} -Ivariants/t-echo
# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling.
build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo
src_filter = ${nrf52_base.src_filter} +<../variants/t-echo>
lib_deps =
${nrf52840_base.lib_deps}
@@ -385,7 +391,7 @@ extends = nrf52840_base
board = lora-relay-v1
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_relay_v1
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v1
-DUSER_SETUP_LOADED
-DTFT_WIDTH=80
-DTFT_HEIGHT=160
@@ -407,7 +413,7 @@ extends = nrf52840_base
board = lora-relay-v2
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_relay_v2
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v2
-DUSER_SETUP_LOADED
-DTFT_WIDTH=80
-DTFT_HEIGHT=160

View File

@@ -43,6 +43,7 @@ Power *power;
using namespace meshtastic;
#ifndef AREF_VOLTAGE
#if defined(NRF52_SERIES)
/*
* Internal Reference is +/-0.6V, with an adjustable gain of 1/6, 1/5, 1/4,
@@ -57,6 +58,7 @@ using namespace meshtastic;
#else
#define AREF_VOLTAGE 3.3
#endif
#endif
/**
* If this board has a battery level sensor, set this to a valid implementation
@@ -80,10 +82,13 @@ class AnalogBatteryLevel : public HasBatteryLevel
if (v < noBatVolt)
return -1; // If voltage is super low assume no battery installed
#ifndef NRF52_SERIES
// This does not work on a RAK4631 with battery connected
if (v > chargingVolt)
return 0; // While charging we can't report % full on the battery
#endif
return 100 * (v - emptyVolt) / (fullVolt - emptyVolt);
return clamp((int)(100 * (v - emptyVolt) / (fullVolt - emptyVolt)), 0, 100);
}
/**
@@ -102,8 +107,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
if (millis() - last_read_time_ms > min_read_interval) {
last_read_time_ms = millis();
uint32_t raw = analogRead(BATTERY_PIN);
float scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw;
float scaled;
#ifndef VBAT_RAW_TO_SCALED
scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw;
#else
scaled = VBAT_RAW_TO_SCALED(raw); //defined in variant.h
#endif
// DEBUG_MSG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
last_read_value = scaled;
return scaled;
@@ -136,7 +145,9 @@ class AnalogBatteryLevel : public HasBatteryLevel
const float fullVolt = 4200, emptyVolt = 3270, chargingVolt = 4210, noBatVolt = 2230;
float last_read_value = 0.0;
uint32_t last_read_time_ms = 0;
} analogLevel;
};
AnalogBatteryLevel analogLevel;
Power::Power() : OSThread("Power") {}
@@ -153,11 +164,19 @@ bool Power::analogInit()
adcAttachPin(BATTERY_PIN);
#endif
#ifdef NRF52_SERIES
#ifdef VBAT_AR_INTERNAL
analogReference(VBAT_AR_INTERNAL);
#else
analogReference(AR_INTERNAL); // 3.6V
#endif
#endif
#ifndef BATTERY_SENSE_RESOLUTION_BITS
#define BATTERY_SENSE_RESOLUTION_BITS 10
#endif
// adcStart(BATTERY_PIN);
analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
batteryLevel = &analogLevel;
return true;
#else

View File

@@ -27,6 +27,7 @@ static bool isPowered()
static void sdsEnter()
{
DEBUG_MSG("Enter state: SDS\n");
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
doDeepSleep(getPref_sds_secs() * 1000LL);
}
@@ -41,7 +42,7 @@ static void lsEnter()
screen->setOn(false);
secsSlept = 0; // How long have we been sleeping this time
DEBUG_MSG("lsEnter end\n");
// DEBUG_MSG("lsEnter end\n");
}
static void lsIdle()
@@ -112,6 +113,7 @@ static void lsIdle()
static void lsExit()
{
DEBUG_MSG("Exit state: LS\n");
// setGPSPower(true); // restore GPS power
if (gps)
gps->forceWake(true);
@@ -119,6 +121,7 @@ static void lsExit()
static void nbEnter()
{
DEBUG_MSG("Enter state: NB\n");
screen->setOn(false);
setBluetoothEnable(false);
@@ -133,6 +136,7 @@ static void darkEnter()
static void serialEnter()
{
DEBUG_MSG("Enter state: SERIAL\n");
setBluetoothEnable(false);
screen->setOn(true);
screen->print("Serial connected\n");
@@ -145,6 +149,7 @@ static void serialExit()
static void powerEnter()
{
DEBUG_MSG("Enter state: POWER\n");
if (!isPowered()) {
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
DEBUG_MSG("Loss of power in Powered\n");
@@ -174,6 +179,7 @@ static void powerExit()
static void onEnter()
{
DEBUG_MSG("Enter state: ON\n");
screen->setOn(true);
setBluetoothEnable(true);
@@ -202,7 +208,9 @@ static void screenPress()
screen->onPress();
}
static void bootEnter() {}
static void bootEnter() {
DEBUG_MSG("Enter state: BOOT\n");
}
State stateSDS(sdsEnter, NULL, NULL, "SDS");
State stateLS(lsEnter, lsIdle, lsExit, "LS");
@@ -226,10 +234,9 @@ void PowerFSM_setup()
// if we are a router node, we go to NB (no need for bluetooth) otherwise we go to DARK (so we can send message to phone)
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
// Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB or dark and
// then it handles things powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet");
powerFSM.add_transition(&stateNB, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet, resetting win wake");
// We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from light sleep we _always_ transition to NB or dark and
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, exiting light sleep");
powerFSM.add_transition(&stateNB, &stateNB, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, resetting win wake");
// Handle press events - note: we ignore button presses when in API mode
powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press");
@@ -253,6 +260,9 @@ void PowerFSM_setup()
// if we are a router we don't turn the screen on for these things
if (!isRouter) {
// if any packet destined for phone arrives, turn on bluetooth at least
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
// show the latest node when we get a new node db update
powerFSM.add_transition(&stateNB, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
@@ -292,13 +302,13 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
powerFSM.add_transition(&stateON, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout");
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
State *lowPowerState = &stateLS;
uint32_t meshSds = 0;
#ifndef NRF52_SERIES
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
@@ -307,11 +317,12 @@ void PowerFSM_setup()
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
meshSds = getPref_mesh_sds_timeout_secs();
#else
lowPowerState = &stateDARK;
meshSds = UINT32_MAX; //Workaround for now: Don't go into deep sleep on the RAK4631
#endif
auto meshSds = getPref_mesh_sds_timeout_secs();
if (meshSds != UINT32_MAX)
powerFSM.add_timed_transition(lowPowerState, &stateSDS, meshSds * 1000, NULL, "mesh timeout");
// removing for now, because some users don't even have phones

View File

@@ -6,7 +6,7 @@
#define EVENT_PRESS 1
#define EVENT_WAKE_TIMER 2
#define EVENT_RECEIVED_PACKET 3
// #define EVENT_RECEIVED_PACKET 3
#define EVENT_PACKET_FOR_PHONE 4
#define EVENT_RECEIVED_TEXT_MSG 5
// #define EVENT_BOOT 6 // now done with a timed transition

View File

@@ -2,6 +2,7 @@
#include "RedirectablePrint.h"
#include "RTC.h"
#include "concurrency/OSThread.h"
// #include "wifi/WiFiServerAPI.h"
#include <assert.h>
#include <sys/time.h>
#include <time.h>
@@ -25,6 +26,10 @@ size_t RedirectablePrint::write(uint8_t c)
SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c);
#endif
// FIXME - clean this up, the whole relationship of this class to SerialConsole to TCP/bluetooth debug log output is kinda messed up. But for now, just have this hack to
// optionally send chars to TCP also
//WiFiServerPort::debugOut(c);
dest->write(c);
return 1; // We always claim one was written, rather than trusting what the
// serial port said (which could be zero)

View File

@@ -72,14 +72,21 @@ bool NotifiedWorkerThread::notifyLater(uint32_t delay, uint32_t v, bool overwrit
return didIt;
}
int32_t NotifiedWorkerThread::runOnce()
void NotifiedWorkerThread::checkNotification()
{
auto n = notification;
enabled = false; // Only run once per notification
notification = 0; // clear notification
if (n) {
onNotify(n);
}
}
int32_t NotifiedWorkerThread::runOnce()
{
enabled = false; // Only run once per notification
checkNotification();
return RUN_SAME;
}

View File

@@ -38,8 +38,14 @@ class NotifiedWorkerThread : public OSThread
protected:
virtual void onNotify(uint32_t notification) = 0;
/// just calls checkNotification()
virtual int32_t runOnce();
/// Sometimes we might want to check notifications independently of when our thread was getting woken up (i.e. if we are about to change
/// radio transmit/receive modes we want to handle any pending interrupts first). You can call this method and if any notifications are currently
/// pending they will be handled immediately.
void checkNotification();
private:
/**
* Notify this thread so it can run

View File

@@ -946,7 +946,9 @@ void Screen::setFrames()
normalFrames[numframes++] = drawTextMessageFrame;
// then all the nodes
for (size_t i = 0; i < numnodes; i++)
// We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens
size_t numToShow = min(numnodes, 4U);
for (size_t i = 0; i < numToShow; i++)
normalFrames[numframes++] = drawNodeInfo;
// then the debug info

View File

@@ -22,6 +22,8 @@ class Screen
#include <OLEDDisplayUi.h>
#include "../configuration.h"
#ifdef USE_SH1106
#include <SH1106Wire.h>
#elif defined(USE_ST7567)

View File

@@ -25,9 +25,10 @@
#include <Wire.h>
// #include <driver/rtc_io.h>
#include "mesh/http/WiFiAPClient.h"
#ifndef NO_ESP32
#include "mesh/http/WebServer.h"
#include "mesh/http/WiFiAPClient.h"
#include "nimble/BluetoothUtil.h"
#endif
@@ -337,9 +338,10 @@ void setup()
digitalWrite(RESET_OLED, 1);
#endif
bool forceSoftAP = 0;
#ifdef BUTTON_PIN
#ifndef NO_ESP32
bool forceSoftAP = 0;
// If the button is connected to GPIO 12, don't enable the ability to use
// meshtasticAdmin on the device.
@@ -536,10 +538,14 @@ void setup()
}
#endif
#ifndef NO_ESP32
#if defined(PORTDUINO) || defined(HAS_WIFI)
mqttInit();
#endif
// Initialize Wifi
initWifi(forceSoftAP);
#ifndef NO_ESP32
// Start web server thread.
webServerThread = new WebServerThread();
#endif
@@ -548,10 +554,6 @@ void setup()
initApiServer();
#endif
#if defined(PORTDUINO) || defined(HAS_WIFI)
mqttInit();
#endif
// Start airtime logger thread.
airTime = new AirTime();
@@ -646,7 +648,9 @@ void loop()
mainController.nextThread->tillRun(millis())); */
// We want to sleep as long as possible here - because it saves power
if (!runASAP && loopCanSleep())
if (!runASAP && loopCanSleep()) {
// if(delayMsec > 100) DEBUG_MSG("sleeping %ld\n", delayMsec);
mainDelay.delay(delayMsec);
}
// if (didWake) DEBUG_MSG("wake!\n");
}

View File

@@ -32,6 +32,10 @@ void CryptoEngine::decrypt(uint32_t fromNode, uint64_t packetNum, size_t numByte
void CryptoEngine::initNonce(uint32_t fromNode, uint64_t packetNum)
{
memset(nonce, 0, sizeof(nonce));
*((uint64_t *)&nonce[0]) = packetNum;
*((uint32_t *)&nonce[8]) = fromNode;
// use memcpy to avoid breaking strict-aliasing
memcpy(nonce, &packetNum, sizeof(uint64_t));
memcpy(nonce + sizeof(uint64_t), &fromNode, sizeof(uint32_t));
//*((uint64_t *)&nonce[0]) = packetNum;
//*((uint32_t *)&nonce[8]) = fromNode;
}

View File

@@ -4,14 +4,14 @@
#include <algorithm>
/// @return the priority of the specified packet
inline uint32_t getPriority(MeshPacket *p)
inline uint32_t getPriority(const MeshPacket *p)
{
auto pri = p->priority;
return pri;
}
/// @return "true" if "p1" is ordered before "p2"
bool CompareMeshPacket::operator()(MeshPacket *p1, MeshPacket *p2)
bool CompareMeshPacketFunc(const MeshPacket *p1, const MeshPacket *p2)
{
assert(p1 && p2);
auto p1p = getPriority(p1), p2p = getPriority(p2);
@@ -25,7 +25,12 @@ bool CompareMeshPacket::operator()(MeshPacket *p1, MeshPacket *p2)
MeshPacketQueue::MeshPacketQueue(size_t _maxLen) : maxLen(_maxLen) {}
/** Some clients might not properly set priority, therefore we fix it here.
bool MeshPacketQueue::empty() {
return queue.empty();
}
/**
* Some clients might not properly set priority, therefore we fix it here.
*/
void fixPriority(MeshPacket *p)
{
@@ -34,7 +39,7 @@ void fixPriority(MeshPacket *p)
if (p->priority == MeshPacket_Priority_UNSET) {
// if acks give high priority
// if a reliable message give a bit higher default priority
p->priority = (p->decoded.portnum == PortNum_ROUTING_APP) ? MeshPacket_Priority_ACK :
p->priority = (p->decoded.portnum == PortNum_ROUTING_APP) ? MeshPacket_Priority_ACK :
(p->want_ack ? MeshPacket_Priority_RELIABLE : MeshPacket_Priority_DEFAULT);
}
}
@@ -42,51 +47,70 @@ void fixPriority(MeshPacket *p)
/** enqueue a packet, return false if full */
bool MeshPacketQueue::enqueue(MeshPacket *p)
{
fixPriority(p);
// fixme if there is something lower priority in the queue that can be deleted to make space, delete that instead
if (size() >= maxLen)
return false;
else {
push(p);
return true;
// no space - try to replace a lower priority packet in the queue
if (queue.size() >= maxLen) {
return replaceLowerPriorityPacket(p);
}
queue.push_back(p);
std::push_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc);
return true;
}
MeshPacket *MeshPacketQueue::dequeue()
{
if (empty())
if (empty()) {
return NULL;
else {
auto p = top();
pop(); // remove the first item
return p;
}
auto *p = queue.front();
std::pop_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc);
queue.pop_back();
return p;
}
// this is kinda yucky, but I'm not sure if all arduino c++ compilers support closuers. And we only have one
// thread that can run at a time - so safe
static NodeNum findFrom;
static PacketId findId;
static bool isMyPacket(MeshPacket *p)
{
return p->id == findId && getFrom(p) == findFrom;
}
/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */
/** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */
MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id)
{
findFrom = from;
findId = id;
auto it = std::find_if(this->c.begin(), this->c.end(), isMyPacket);
if (it != this->c.end()) {
auto p = *it;
this->c.erase(it);
std::make_heap(this->c.begin(), this->c.end(), this->comp);
return p;
} else {
return NULL;
for (auto it = queue.begin(); it != queue.end(); it++) {
auto p = (*it);
if (getFrom(p) == from && p->id == id) {
queue.erase(it);
std::make_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc);
return p;
}
}
return NULL;
}
/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */
bool MeshPacketQueue::replaceLowerPriorityPacket(MeshPacket *p) {
std::sort_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc); // sort ascending based on priority (0 -> 127)
// find first packet which does not compare less (in priority) than parameter packet
auto low = std::lower_bound(queue.begin(), queue.end(), p, &CompareMeshPacketFunc);
if (low == queue.begin()) { // if already at start, there are no packets with lower priority
return false;
}
if (low == queue.end()) {
// all priorities in the vector are smaller than the incoming packet. Replace the lowest priority (first) element
low = queue.begin();
} else {
// 'low' iterator points to first packet which does not compare less than parameter
--low; // iterate to lower priority packet
}
if (getPriority(p) > getPriority(*low)) {
packetPool.release(*low); // deallocate and drop the packet we're replacing
*low = p; // replace low-pri packet at this position with incoming packet with higher priority
}
std::make_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc);
return true;
}

View File

@@ -5,29 +5,29 @@
#include <assert.h>
#include <queue>
// this is an strucure which implements the
// operator overloading
struct CompareMeshPacket {
bool operator()(MeshPacket *p1, MeshPacket *p2);
};
/**
* A priority queue of packets.
*
* A priority queue of packets
*/
class MeshPacketQueue : public std::priority_queue<MeshPacket *, std::vector<MeshPacket *>, CompareMeshPacket>
class MeshPacketQueue
{
size_t maxLen;
std::vector<MeshPacket *> queue;
/** Replace a lower priority package in the queue with 'mp' (provided there are lower pri packages). Return true if replaced. */
bool replaceLowerPriorityPacket(MeshPacket *mp);
public:
MeshPacketQueue(size_t _maxLen);
/** enqueue a packet, return false if full */
bool enqueue(MeshPacket *p);
// bool isEmpty();
/** return true if the queue is empty */
bool empty();
MeshPacket *dequeue();
/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */
/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */
MeshPacket *remove(NodeNum from, PacketId id);
};

View File

@@ -66,7 +66,7 @@ void MeshService::init()
int MeshService::handleFromRadio(const MeshPacket *mp)
{
powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping
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

View File

@@ -19,35 +19,57 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
}
uint32_t now = millis();
for (size_t i = 0; i < recentPackets.size();) {
PacketRecord &r = recentPackets[i];
if ((now - r.rxTimeMsec) >= FLOOD_EXPIRE_TIME) {
// DEBUG_MSG("Deleting old broadcast record %d\n", i);
recentPackets.erase(recentPackets.begin() + i); // delete old record
PacketRecord r;
r.id = p->id;
r.sender = getFrom(p);
r.rxTimeMsec = now;
auto found = recentPackets.find(r);
bool seenRecently = (found != recentPackets.end()); // found not equal to .end() means packet was seen recently
if (seenRecently && (now - found->rxTimeMsec) >= FLOOD_EXPIRE_TIME) { // Check whether found packet has already expired
recentPackets.erase(found); // Erase and pretend packet has not been seen recently
found = recentPackets.end();
seenRecently = false;
}
if (seenRecently) {
DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x\n", p->from, p->to, p->id);
}
if (withUpdate) {
if (found != recentPackets.end()) { // delete existing to updated timestamp (re-insert)
recentPackets.erase(found); // as unsorted_set::iterator is const (can't update timestamp - so re-insert..)
}
recentPackets.insert(r);
printPacket("Add packet record", p);
}
// Capacity is reerved, so only purge expired packets if recentPackets fills past 90% capacity
// Expiry is normally dealt with after having searched/found a packet (above)
if (recentPackets.size() > (MAX_NUM_NODES * 0.9)) {
clearExpiredRecentPackets();
}
return seenRecently;
}
/**
* Iterate through all recent packets, and remove all older than FLOOD_EXPIRE_TIME
*/
void PacketHistory::clearExpiredRecentPackets() {
uint32_t now = millis();
DEBUG_MSG("recentPackets size=%ld\n", recentPackets.size());
for (auto it = recentPackets.begin(); it != recentPackets.end(); ) {
if ((now - it->rxTimeMsec) >= FLOOD_EXPIRE_TIME) {
it = recentPackets.erase(it); // erase returns iterator pointing to element immediately following the one erased
} else {
if (r.id == p->id && r.sender == getFrom(p)) {
DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x\n", p->from, p->to, p->id);
// Update the time on this record to now
if (withUpdate)
r.rxTimeMsec = now;
return true;
}
i++;
++it;
}
}
// Didn't find an existing record, make one
if (withUpdate) {
PacketRecord r;
r.id = p->id;
r.sender = getFrom(p);
r.rxTimeMsec = now;
recentPackets.push_back(r);
printPacket("Adding packet record", p);
}
return false;
DEBUG_MSG("recentPackets size=%ld (after clearing expired packets)\n", recentPackets.size());
}

View File

@@ -1,7 +1,6 @@
#pragma once
#include "Router.h"
#include <queue>
#include <unordered_set>
/// We clear our old flood record five minute after we see the last of it
@@ -24,37 +23,15 @@ class PacketRecordHashFunction
size_t operator()(const PacketRecord &p) const { return (std::hash<NodeNum>()(p.sender)) ^ (std::hash<PacketId>()(p.id)); }
};
/// Order packet records by arrival time, we want the oldest packets to be in the front of our heap
class PacketRecordOrderFunction
{
public:
size_t operator()(const PacketRecord &p1, const PacketRecord &p2) const
{
// If the timer ticks have rolled over the difference between times will be _enormous_. Handle that case specially
uint32_t t1 = p1.rxTimeMsec, t2 = p2.rxTimeMsec;
if (t1 - t2 > UINT32_MAX / 2) {
// time must have rolled over, swap them because the new little number is 'bigger' than the old big number
t1 = t2;
t2 = p1.rxTimeMsec;
}
return t1 > t2;
}
};
/**
* This is a mixin that adds a record of past packets we have seen
*/
class PacketHistory
{
private:
/** FIXME: really should be a std::unordered_set with the key being sender,id.
* This would make checking packets in wasSeenRecently faster.
*/
std::vector<PacketRecord> recentPackets;
// priority_queue<PacketRecord, vector<PacketRecord>, PacketRecordOrderFunction> arrivalTimes;
// unordered_set<PacketRecord, PacketRecordHashFunction> recentPackets;
std::unordered_set<PacketRecord, PacketRecordHashFunction> recentPackets;
void clearExpiredRecentPackets(); // clear all recentPackets older than FLOOD_EXPIRE_TIME
public:
PacketHistory();

View File

@@ -81,6 +81,9 @@ class PhoneAPI
bool isConnected() { return state != STATE_SEND_NOTHING; }
/// emit a debugging log character, FIXME - implement
void debugOut(char c) { }
protected:
/// Our fromradio packet while it is being assembled
FromRadio fromRadioScratch;

View File

@@ -28,7 +28,7 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
* In general decoded will always be !NULL. But in some special applications (where you have handling packets
* for multiple port numbers, decoding will ONLY be attempted for packets where the portnum matches our expected ourPortNum.
*/
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const T *decoded) = 0;
virtual bool handleReceivedProtobuf(const MeshPacket &mp, T *decoded) = 0;
/**
* Return a mesh packet which has been preinited with a particular protobuf data payload and port number.

View File

@@ -146,6 +146,8 @@ void INTERRUPT_ATTR SX1262Interface::disableInterrupt()
void SX1262Interface::setStandby()
{
checkNotification(); // handle any pending interrupts before we force standby
int err = lora.standby();
assert(err == ERR_NONE);

View File

@@ -26,7 +26,11 @@ int32_t StreamAPI::readStream()
return recentRx ? 5 : 250;
} else {
while (stream->available()) { // Currently we never want to block
uint8_t c = stream->read();
int cInt = stream->read();
if(cInt < 0)
break; // We ran out of characters (even though available said otherwise) - this can happen on rf52 adafruit arduino
uint8_t c = (uint8_t) cInt;
// Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
size_t ptr = rxPtr;

View File

@@ -68,7 +68,7 @@ class StreamAPI : public PhoneAPI, protected concurrency::OSThread
void emitRebooted();
virtual void onConnectionChanged(bool connected);
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() = 0;

View File

@@ -5,7 +5,6 @@
#include <HTTPMultipartBodyParser.hpp>
#include <HTTPURLEncodedBodyParser.hpp>
#include <WebServer.h>
#include <WiFi.h>
@@ -13,7 +12,6 @@
#include "esp_task_wdt.h"
#endif
// Persistant Data Storage
#include <Preferences.h>
Preferences prefs;
@@ -42,46 +40,41 @@ Preferences prefs;
using namespace httpsserver;
#include "mesh/http/ContentHandler.h"
SSLCert *cert;
HTTPSServer *secureServer;
HTTPServer *insecureServer;
static SSLCert *cert;
static HTTPSServer *secureServer;
static HTTPServer *insecureServer;
volatile bool isWebServerReady;
volatile bool isCertReady;
bool isWebServerReady = 0;
bool isCertReady = 0;
void handleWebResponse()
static void handleWebResponse()
{
if (isWifiAvailable() == 0) {
return;
}
if (isWifiAvailable()) {
if (isWebServerReady) {
// We're going to handle the DNS responder here so it
// will be ignored by the NRF boards.
handleDNSResponse();
if (isWebServerReady) {
// We're going to handle the DNS responder here so it
// will be ignored by the NRF boards.
handleDNSResponse();
secureServer->loop();
insecureServer->loop();
}
if(secureServer)
secureServer->loop();
insecureServer->loop();
}
/*
Slow down the CPU if we have not received a request within the last few
seconds.
*/
if (millis() - getTimeSpeedUp() >= (25 * 1000)) {
setCpuFrequencyMhz(80);
setTimeSpeedUp();
/*
Slow down the CPU if we have not received a request within the last few
seconds.
*/
if (millis() - getTimeSpeedUp() >= (25 * 1000)) {
setCpuFrequencyMhz(80);
setTimeSpeedUp();
}
}
}
void taskCreateCert(void *parameter)
static void taskCreateCert(void *parameter)
{
prefs.begin("MeshtasticHTTPS", false);
// Delete the saved certs
@@ -92,13 +85,32 @@ void taskCreateCert(void *parameter)
prefs.remove("cert");
}
DEBUG_MSG("Checking if we have a previously saved SSL Certificate.\n");
size_t pkLen = prefs.getBytesLength("PK");
size_t certLen = prefs.getBytesLength("cert");
DEBUG_MSG("Checking if we have a previously saved SSL Certificate.\n");
if (pkLen && certLen) {
DEBUG_MSG("Existing SSL Certificate found!\n");
uint8_t *pkBuffer = new uint8_t[pkLen];
prefs.getBytes("PK", pkBuffer, pkLen);
uint8_t *certBuffer = new uint8_t[certLen];
prefs.getBytes("cert", certBuffer, certLen);
cert = new SSLCert(certBuffer, certLen, pkBuffer, pkLen);
DEBUG_MSG("Retrieved Private Key: %d Bytes\n", cert->getPKLength());
// DEBUG_MSG("Retrieved Private Key: " + String(cert->getPKLength()) + " Bytes");
// for (int i = 0; i < cert->getPKLength(); i++)
// Serial.print(cert->getPKData()[i], HEX);
// Serial.println();
DEBUG_MSG("Retrieved Certificate: %d Bytes\n", cert->getCertLength());
// for (int i = 0; i < cert->getCertLength(); i++)
// Serial.print(cert->getCertData()[i], HEX);
// Serial.println();
} else {
DEBUG_MSG("Creating the certificate. This may take a while. Please wait...\n");
yield();
@@ -133,35 +145,35 @@ void taskCreateCert(void *parameter)
}
}
isCertReady = 1;
isCertReady = true;
// Must delete self, can't just fall out
vTaskDelete(NULL);
}
void createSSLCert()
{
if (isWifiAvailable() && !isCertReady) {
if (isWifiAvailable() == 0) {
return;
// Create a new process just to handle creating the cert.
// This is a workaround for Bug: https://github.com/fhessel/esp32_https_server/issues/48
// jm@casler.org (Oct 2020)
xTaskCreate(taskCreateCert, /* Task function. */
"createCert", /* String with name of task. */
16384, /* Stack size in bytes. */
NULL, /* Parameter passed as input of the task */
16, /* Priority of the task. */
NULL); /* Task handle. */
DEBUG_MSG("Waiting for SSL Cert to be generated.\n");
while (!isCertReady) {
DEBUG_MSG(".");
delay(1000);
yield();
esp_task_wdt_reset();
}
DEBUG_MSG("SSL Cert Ready!\n");
}
// Create a new process just to handle creating the cert.
// This is a workaround for Bug: https://github.com/fhessel/esp32_https_server/issues/48
// jm@casler.org (Oct 2020)
xTaskCreate(taskCreateCert, /* Task function. */
"createCert", /* String with name of task. */
16384, /* Stack size in bytes. */
NULL, /* Parameter passed as input of the task */
16, /* Priority of the task. */
NULL); /* Task handle. */
DEBUG_MSG("Waiting for SSL Cert to be generated.\n");
while (!isCertReady) {
DEBUG_MSG(".");
delay(1000);
yield();
esp_task_wdt_reset();
}
DEBUG_MSG("SSL Cert Ready!\n");
}
WebServerThread *webServerThread;
@@ -181,6 +193,8 @@ void initWebServer()
{
DEBUG_MSG("Initializing Web Server ...\n");
#if 0
// this seems to be a copypaste dup of taskCreateCert
prefs.begin("MeshtasticHTTPS", false);
size_t pkLen = prefs.getBytesLength("PK");
@@ -211,6 +225,7 @@ void initWebServer()
} else {
DEBUG_MSG("Web Server started without SSL keys! How did this happen?\n");
}
#endif
// We can now use the new certificate to setup our server as usual.
secureServer = new HTTPSServer(cert);
@@ -218,14 +233,16 @@ void initWebServer()
registerHandlers(insecureServer, secureServer);
DEBUG_MSG("Starting Web Servers...\n");
secureServer->start();
if(secureServer) {
DEBUG_MSG("Starting Secure Web Server...\n");
secureServer->start();
}
DEBUG_MSG("Starting Insecure Web Server...\n");
insecureServer->start();
if (secureServer->isRunning() && insecureServer->isRunning()) {
DEBUG_MSG("HTTP and HTTPS Web Servers Ready! :-) \n");
isWebServerReady = 1;
if (insecureServer->isRunning()) {
DEBUG_MSG("Web Servers Ready! :-) \n");
isWebServerReady = true;
} else {
DEBUG_MSG("HTTP and HTTPS Web Servers Failed! ;-( \n");
DEBUG_MSG("Web Servers Failed! ;-( \n");
}
}

View File

@@ -8,10 +8,6 @@
void initWebServer();
void createSSLCert();
void handleWebResponse();
class WebServerThread : private concurrency::OSThread
{

View File

@@ -1,7 +1,9 @@
#include "mesh/http/WiFiAPClient.h"
#include "NodeDB.h"
#include "concurrency/Periodic.h"
#include "configuration.h"
#include "main.h"
#include "mqtt/MQTT.h"
#include "mesh/http/WebServer.h"
#include "mesh/wifi/WiFiServerAPI.h"
#include "target_specific.h"
@@ -9,6 +11,8 @@
#include <ESPmDNS.h>
#include <WiFi.h>
using namespace concurrency;
static void WiFiEvent(WiFiEvent_t event);
// DNS Server for the Captive Portal
@@ -23,6 +27,47 @@ bool forcedSoftAP = 0;
bool APStartupComplete = 0;
static bool needReconnect = true; // If we create our reconnector, run it once at the beginning
// FIXME, veto light sleep if we have a TCP server running
#if 0
class WifiSleepObserver : public Observer<uint32_t> {
protected:
/// Return 0 if sleep is okay
virtual int onNotify(uint32_t newValue) {
}
};
static WifiSleepObserver wifiSleepObserver;
//preflightSleepObserver.observe(&preflightSleep);
#endif
static int32_t reconnectWiFi()
{
if (radioConfig.has_preferences && needReconnect) {
const char *wifiName = radioConfig.preferences.wifi_ssid;
const char *wifiPsw = radioConfig.preferences.wifi_password;
if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL;
if (*wifiName) {
needReconnect = false;
DEBUG_MSG("... Reconnecting to WiFi access point");
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw);
}
}
return 30 * 1000; // every 30 seconds
}
static Periodic *wifiReconnect;
bool isSoftAPForced()
{
return forcedSoftAP;
@@ -37,15 +82,6 @@ bool isWifiAvailable()
const char *wifiName = radioConfig.preferences.wifi_ssid;
// strcpy(radioConfig.preferences.wifi_ssid, "meshtastic");
// strcpy(radioConfig.preferences.wifi_password, "meshtastic!");
// strcpy(radioConfig.preferences.wifi_ssid, "meshtasticAdmin");
// strcpy(radioConfig.preferences.wifi_password, "12345678");
// radioConfig.preferences.wifi_ap_mode = true;
// radioConfig.preferences.wifi_ap_mode = false;
if (*wifiName) {
return true;
} else {
@@ -74,27 +110,44 @@ void deinitWifi()
}
}
// Startup WiFi
void initWifi(bool forceSoftAP)
static void onNetworkConnected()
{
if (!APStartupComplete) {
// Start web server
DEBUG_MSG("... Starting network services\n");
if (forceSoftAP) {
// do nothing
// DEBUG_MSG("----- Forcing SoftAP\n");
} else {
if (isWifiAvailable() == 0) {
return;
// start mdns
if (!MDNS.begin("Meshtastic")) {
DEBUG_MSG("Error setting up MDNS responder!\n");
} else {
DEBUG_MSG("mDNS responder started\n");
DEBUG_MSG("mDNS Host: Meshtastic.local\n");
MDNS.addService("http", "tcp", 80);
MDNS.addService("https", "tcp", 443);
}
}
initWebServer();
initApiServer();
APStartupComplete = true;
}
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
if(mqtt)
mqtt->reconnect();
}
// Startup WiFi
bool initWifi(bool forceSoftAP)
{
forcedSoftAP = forceSoftAP;
createSSLCert();
if (radioConfig.has_preferences || forceSoftAP) {
if ((radioConfig.has_preferences && radioConfig.preferences.wifi_ssid[0]) || forceSoftAP) {
const char *wifiName = radioConfig.preferences.wifi_ssid;
const char *wifiPsw = radioConfig.preferences.wifi_password;
createSSLCert();
if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL;
@@ -155,29 +208,15 @@ void initWifi(bool forceSoftAP)
},
WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);
DEBUG_MSG("JOINING WIFI: ssid=%s\n", wifiName);
if (WiFi.begin(wifiName, wifiPsw) == WL_CONNECTED) {
DEBUG_MSG("MY IP ADDRESS: %s\n", WiFi.localIP().toString().c_str());
} else {
DEBUG_MSG("Started Joining WIFI\n");
}
DEBUG_MSG("JOINING WIFI soon: ssid=%s\n", wifiName);
wifiReconnect = new Periodic("WifiConnect", reconnectWiFi);
}
}
if (!MDNS.begin("Meshtastic")) {
DEBUG_MSG("Error setting up MDNS responder!\n");
while (1) {
delay(1000);
}
}
DEBUG_MSG("mDNS responder started\n");
DEBUG_MSG("mDNS Host: Meshtastic.local\n");
MDNS.addService("http", "tcp", 80);
MDNS.addService("https", "tcp", 443);
} else
return true;
} else {
DEBUG_MSG("Not using WIFI\n");
return false;
}
}
// Called by the Espressif SDK to
@@ -193,10 +232,10 @@ static void WiFiEvent(WiFiEvent_t event)
DEBUG_MSG("Completed scan for access points\n");
break;
case SYSTEM_EVENT_STA_START:
DEBUG_MSG("WiFi client started\n");
DEBUG_MSG("WiFi station started\n");
break;
case SYSTEM_EVENT_STA_STOP:
DEBUG_MSG("WiFi clients stopped\n");
DEBUG_MSG("WiFi station stopped\n");
break;
case SYSTEM_EVENT_STA_CONNECTED:
DEBUG_MSG("Connected to access point\n");
@@ -205,7 +244,7 @@ static void WiFiEvent(WiFiEvent_t event)
DEBUG_MSG("Disconnected from WiFi access point\n");
// Event 5
reconnectWiFi();
needReconnect = true;
break;
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
DEBUG_MSG("Authentication mode of access point has changed\n");
@@ -213,18 +252,7 @@ static void WiFiEvent(WiFiEvent_t event)
case SYSTEM_EVENT_STA_GOT_IP:
DEBUG_MSG("Obtained IP address: \n");
Serial.println(WiFi.localIP());
if (!APStartupComplete) {
// Start web server
DEBUG_MSG("... Starting network services\n");
initWebServer();
initApiServer();
APStartupComplete = true;
} else {
DEBUG_MSG("... Not starting network services (They're already running)\n");
}
onNetworkConnected();
break;
case SYSTEM_EVENT_STA_LOST_IP:
DEBUG_MSG("Lost IP address and IP address is reset to 0\n");
@@ -244,18 +272,7 @@ static void WiFiEvent(WiFiEvent_t event)
case SYSTEM_EVENT_AP_START:
DEBUG_MSG("WiFi access point started\n");
Serial.println(WiFi.softAPIP());
if (!APStartupComplete) {
// Start web server
DEBUG_MSG("... Starting network services\n");
initWebServer();
initApiServer();
APStartupComplete = true;
} else {
DEBUG_MSG("... Not starting network services (They're already running)\n");
}
onNetworkConnected();
break;
case SYSTEM_EVENT_AP_STOP:
DEBUG_MSG("WiFi access point stopped\n");
@@ -302,26 +319,6 @@ void handleDNSResponse()
}
}
void reconnectWiFi()
{
if (radioConfig.has_preferences) {
const char *wifiName = radioConfig.preferences.wifi_ssid;
const char *wifiPsw = radioConfig.preferences.wifi_password;
if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL;
if (*wifiName) {
DEBUG_MSG("... Reconnecting to WiFi access point");
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw);
}
}
}
uint8_t getWifiDisconnectReason()
{
return wifiDisconnectReason;

View File

@@ -9,15 +9,15 @@
#include <WiFi.h>
#endif
void initWifi(bool forceSoftAP);
/// @return true if wifi is now in use
bool initWifi(bool forceSoftAP);
void deinitWifi();
bool isWifiAvailable();
void handleDNSResponse();
void reconnectWiFi();
bool isSoftAPForced();
uint8_t getWifiDisconnectReason();

View File

@@ -25,8 +25,6 @@ WiFiServerAPI::~WiFiServerAPI()
// FIXME - delete this if the client dropps the connection!
}
/// override close to also shutdown the TCP link
void WiFiServerAPI::close()
{
@@ -51,6 +49,13 @@ int32_t WiFiServerAPI::runOnce()
}
}
/// If an api server is running, we try to spit out debug 'serial' characters there
void WiFiServerPort::debugOut(char c)
{
if (apiPort && apiPort->openAPI)
apiPort->openAPI->debugOut(c);
}
#define MESHTASTIC_PORTNUM 4403
WiFiServerPort::WiFiServerPort() : WiFiServer(MESHTASTIC_PORTNUM), concurrency::OSThread("ApiServer") {}

View File

@@ -21,8 +21,8 @@ class WiFiServerAPI : public StreamAPI
virtual void close();
protected:
/// We override this method to prevent publishing EVENT_SERIAL_CONNECTED/DISCONNECTED for wifi links (we want the board to stay in the POWERED state to prevent disabling wifi)
/// We override this method to prevent publishing EVENT_SERIAL_CONNECTED/DISCONNECTED for wifi links (we want the board to
/// stay in the POWERED state to prevent disabling wifi)
virtual void onConnectionChanged(bool connected) {}
virtual int32_t runOnce(); // Check for dropped client connections
@@ -48,6 +48,10 @@ class WiFiServerPort : public WiFiServer, private concurrency::OSThread
void init();
/// If an api server is running, we try to spit out debug 'serial' characters there
static void debugOut(char c);
protected:
int32_t runOnce();
};

View File

@@ -1,9 +1,11 @@
#include "MQTT.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "main.h"
#include "mesh/Channels.h"
#include "mesh/Router.h"
#include "mesh/generated/mqtt.pb.h"
#include "sleep.h"
#include <WiFi.h>
#include <assert.h>
@@ -57,33 +59,45 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient)
mqtt = this;
pubSub.setCallback(mqttCallback);
// preflightSleepObserver.observe(&preflightSleep);
}
void MQTT::reconnect()
{
// pubSub.setServer("devsrv.ezdevice.net", 1883); or 192.168.10.188
const char *serverAddr = "mqtt.meshtastic.org"; // default hostname
if (wantsLink()) {
const char *serverAddr = "mqtt.meshtastic.org"; // default hostname
int serverPort = 1883; // default server port
if (*radioConfig.preferences.mqtt_server)
serverAddr = radioConfig.preferences.mqtt_server; // Override the default
if (*radioConfig.preferences.mqtt_server)
serverAddr = radioConfig.preferences.mqtt_server; // Override the default
pubSub.setServer(serverAddr, 1883);
String server = String(serverAddr);
int delimIndex = server.indexOf(':');
if (delimIndex > 0) {
String port = server.substring(delimIndex + 1, server.length());
server[delimIndex] = 0;
serverPort = port.toInt();
serverAddr = server.c_str();
}
pubSub.setServer(serverAddr, serverPort);
DEBUG_MSG("Connecting to MQTT server\n", serverAddr);
auto myStatus = (statusTopic + owner.id);
bool connected = pubSub.connect(owner.id, "meshdev", "large4cats", myStatus.c_str(), 1, true, "offline");
if (connected) {
DEBUG_MSG("MQTT connected\n");
enabled = true; // Start running background process again
runASAP = true;
DEBUG_MSG("Connecting to MQTT server %s, port: %d\n", serverAddr, serverPort);
auto myStatus = (statusTopic + owner.id);
bool connected = pubSub.connect(owner.id, "meshdev", "large4cats", myStatus.c_str(), 1, true, "offline");
if (connected) {
DEBUG_MSG("MQTT connected\n");
enabled = true; // Start running background process again
runASAP = true;
/// FIXME, include more information in the status text
bool ok = pubSub.publish(myStatus.c_str(), "online", true);
DEBUG_MSG("published %d\n", ok);
/// FIXME, include more information in the status text
bool ok = pubSub.publish(myStatus.c_str(), "online", true);
DEBUG_MSG("published %d\n", ok);
sendSubscriptions();
} else
DEBUG_MSG("Failed to contact MQTT server...\n");
sendSubscriptions();
} else
DEBUG_MSG("Failed to contact MQTT server...\n");
}
}
void MQTT::sendSubscriptions()
@@ -140,6 +154,7 @@ int32_t MQTT::runOnce()
pubSub.disconnect();
}
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); // Suppress entering light sleep (because that would turn off bluetooth)
return 20;
}
}

View File

@@ -19,6 +19,9 @@ class MQTT : private concurrency::OSThread
WiFiClient mqttClient;
PubSubClient pubSub;
// instead we supress sleep from our runOnce() callback
// CallbackObserver<MQTT, void *> preflightSleepObserver = CallbackObserver<MQTT, void *>(this, &MQTT::preflightSleepCb);
public:
MQTT();
@@ -32,6 +35,10 @@ class MQTT : private concurrency::OSThread
*/
void onSend(const MeshPacket &mp, ChannelIndex chIndex);
/** Attempt to connect to server if necessary
*/
void reconnect();
protected:
virtual int32_t runOnce();
@@ -40,10 +47,6 @@ class MQTT : private concurrency::OSThread
*/
bool wantsLink() const;
/** Attempt to connect to server if necessary
*/
void reconnect();
/** Tell the server what subscriptions we want (based on channels.downlink_enabled)
*/
void sendSubscriptions();
@@ -53,6 +56,9 @@ class MQTT : private concurrency::OSThread
/// Called when a new publish arrives from the MQTT server
void onPublish(char *topic, byte *payload, unsigned int length);
/// Return 0 if sleep is okay, veto sleep if we are connected to pubsub server
// int preflightSleepCb(void *unused = NULL) { return pubSub.connected() ? 1 : 0; }
};
void mqttInit();

View File

@@ -21,6 +21,8 @@
static bool pinShowing;
static uint32_t doublepressed;
static bool bluetoothActive;
static void startCb(uint32_t pin)
{
pinShowing = true;
@@ -52,23 +54,27 @@ void updateBatteryLevel(uint8_t level)
void deinitBLE()
{
// DEBUG_MSG("Shutting down bluetooth\n");
// ble_gatts_show_local();
if (bluetoothActive) {
bluetoothActive = false;
// FIXME - do we need to dealloc things? - what needs to stay alive across light sleep?
auto ret = nimble_port_stop();
assert(ret == ESP_OK);
// DEBUG_MSG("Shutting down bluetooth\n");
// ble_gatts_show_local();
nimble_port_deinit(); // teardown nimble datastructures
// FIXME - do we need to dealloc things? - what needs to stay alive across light sleep?
auto ret = nimble_port_stop();
assert(ret == ESP_OK);
// DEBUG_MSG("BLE port_deinit done\n");
nimble_port_deinit(); // teardown nimble datastructures
ret = esp_nimble_hci_and_controller_deinit();
assert(ret == ESP_OK);
// DEBUG_MSG("BLE port_deinit done\n");
// DEBUG_MSG("BLE task exiting\n");
ret = esp_nimble_hci_and_controller_deinit();
assert(ret == ESP_OK);
DEBUG_MSG("Done shutting down bluetooth\n");
// DEBUG_MSG("BLE task exiting\n");
DEBUG_MSG("Done shutting down bluetooth\n");
}
}
void loopBLE()
@@ -479,6 +485,8 @@ void disablePin()
doublepressed = millis();
}
// This routine is called multiple times, once each time we come back from sleep
void reinitBluetooth()
{
@@ -536,10 +544,10 @@ void reinitBluetooth()
ble_store_config_init();
nimble_port_freertos_init(ble_host_task);
bluetoothActive = true;
}
bool bluetoothOn;
bool firstTime = 1;
// Enable/disable bluetooth.
void setBluetoothEnable(bool on)
@@ -549,32 +557,15 @@ void setBluetoothEnable(bool on)
bluetoothOn = on;
if (on) {
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
reinitBluetooth();
// Don't try to reconnect wifi before bluetooth is configured.
// WiFi is initialized from main.cpp in setup() .
if (firstTime) {
firstTime = 0;
} else {
#ifndef NO_ESP32
initWifi(0);
#endif
if (!initWifi(0)) // if we are using wifi, don't turn on bluetooth also
{
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
reinitBluetooth();
}
} else {
/*
// If WiFi is in use, disable shutting down the radio.
if (isWifiAvailable()) {
return;
}
*/
// shutdown wifi
#ifndef NO_ESP32
deinitWifi();
#endif
// We have to totally teardown our bluetooth objects to prevent leaks
deinitBLE();

View File

@@ -5,6 +5,7 @@
#include <ble_gap.h>
#include <memory.h>
#include <stdio.h>
// #include <Adafruit_USBD_Device.h>
#include "NRF52Bluetooth.h"
#include "error.h"
@@ -20,7 +21,10 @@ static inline void debugger_break(void)
}
bool loopCanSleep() {
return !tud_cdc_connected();
// turn off sleep only while connected via USB
// return true;
return !Serial; // the bool operator on the nrf52 serial class returns true if connected to a PC currently
// return !(TinyUSBDevice.mounted() && !TinyUSBDevice.suspended());
}
// handle standard gcc assert failures
@@ -37,7 +41,7 @@ void getMacAddr(uint8_t *dmac)
ble_gap_addr_t addr;
if (sd_ble_gap_addr_get(&addr) == NRF_SUCCESS) {
memcpy(dmac, addr.addr, 6);
} else {
} else {
const uint8_t *src = (const uint8_t *)NRF_FICR->DEVICEADDR;
dmac[5] = src[0];
dmac[4] = src[1];
@@ -90,7 +94,7 @@ void setBluetoothEnable(bool on)
}
/**
* Override printf to use the SEGGER output library
* Override printf to use the SEGGER output library (note - this does not effect the printf method on the debug console)
*/
int printf(const char *fmt, ...)
{

View File

@@ -12,6 +12,24 @@
AdminPlugin *adminPlugin;
/// A special reserved string to indicate strings we can not share with external nodes. We will use this 'reserved' word instead.
/// Also, to make setting work correctly, if someone tries to set a string to this reserved value we assume they don't really want a change.
static const char *secretReserved = "sekrit";
/// If buf is !empty, change it to secret
static void hideSecret(char *buf) {
if(*buf) {
strcpy(buf, secretReserved);
}
}
/// If buf is the reserved secret word, replace the buffer with currentVal
static void writeSecret(char *buf, const char *currentVal) {
if(strcmp(buf, secretReserved) == 0) {
strcpy(buf, currentVal);
}
}
void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
{
if (req.decoded.want_response) {
@@ -35,13 +53,15 @@ void AdminPlugin::handleGetRadio(const MeshPacket &req)
// using to the app (so that even old phone apps work with new device loads).
r.get_radio_response.preferences.ls_secs = getPref_ls_secs();
r.get_radio_response.preferences.phone_timeout_secs = getPref_phone_timeout_secs();
// hideSecret(r.get_radio_response.preferences.wifi_ssid); // hmm - leave public for now, because only minimally private and useful for users to know current provisioning)
hideSecret(r.get_radio_response.preferences.wifi_password);
r.which_variant = AdminMessage_get_radio_response_tag;
myReply = allocDataProtobuf(r);
}
}
bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessage *r)
bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
{
assert(r);
switch (r->which_variant) {
@@ -139,8 +159,9 @@ void AdminPlugin::handleSetChannel(const Channel &cc)
}
}
void AdminPlugin::handleSetRadio(const RadioConfig &r)
void AdminPlugin::handleSetRadio(RadioConfig &r)
{
writeSecret(r.preferences.wifi_password, radioConfig.preferences.wifi_password);
radioConfig = r;
service.reloadConfig();

View File

@@ -17,12 +17,12 @@ class AdminPlugin : public ProtobufPlugin<AdminMessage>
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const AdminMessage *p);
virtual bool handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *p);
private:
void handleSetOwner(const User &o);
void handleSetChannel(const Channel &cc);
void handleSetRadio(const RadioConfig &r);
void handleSetRadio(RadioConfig &r);
void handleGetChannel(const MeshPacket &req, uint32_t channelIndex);
void handleGetRadio(const MeshPacket &req);

View File

@@ -8,7 +8,7 @@
NodeInfoPlugin *nodeInfoPlugin;
bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User *pptr)
bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, User *pptr)
{
auto p = *pptr;

View File

@@ -26,7 +26,7 @@ class NodeInfoPlugin : public ProtobufPlugin<User>, private concurrency::OSThrea
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const User *p);
virtual bool handleReceivedProtobuf(const MeshPacket &mp, User *p);
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. */

View File

@@ -14,7 +14,7 @@ PositionPlugin::PositionPlugin()
setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
}
bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position *pptr)
bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, Position *pptr)
{
auto p = *pptr;

View File

@@ -33,7 +33,7 @@ class PositionPlugin : public ProtobufPlugin<Position>, private concurrency::OST
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const Position *p);
virtual bool handleReceivedProtobuf(const MeshPacket &mp, Position *p);
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. */

View File

@@ -48,7 +48,7 @@ RemoteHardwarePlugin::RemoteHardwarePlugin()
{
}
bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, const HardwareMessage *pptr)
bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, HardwareMessage *pptr)
{
auto p = *pptr;
DEBUG_MSG("Received RemoteHardware typ=%d\n", p.typ);

View File

@@ -27,7 +27,7 @@ class RemoteHardwarePlugin : public ProtobufPlugin<HardwareMessage>, private con
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const HardwareMessage *p);
virtual bool handleReceivedProtobuf(const MeshPacket &mp, HardwareMessage *p);
/**
* Periodically read the gpios we have been asked to WATCH, if they have changed,

View File

@@ -7,7 +7,7 @@
RoutingPlugin *routingPlugin;
bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *r)
bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, Routing *r)
{
printPacket("Routing sniffing", &mp);
router->sniffReceived(&mp, r);

View File

@@ -22,7 +22,7 @@ class RoutingPlugin : public ProtobufPlugin<Routing>
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const Routing *p);
virtual bool handleReceivedProtobuf(const MeshPacket &mp, Routing *p);
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. */

View File

@@ -204,7 +204,7 @@ void EnvironmentalMeasurementPlugin::drawFrame(OLEDDisplay *display, OLEDDisplay
}
bool EnvironmentalMeasurementPlugin::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p)
bool EnvironmentalMeasurementPlugin::handleReceivedProtobuf(const MeshPacket &mp, EnvironmentalMeasurement *p)
{
if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){
// If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume

View File

@@ -18,7 +18,7 @@ class EnvironmentalMeasurementPlugin : private concurrency::OSThread, public Pro
/** Called to handle a particular incoming message
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p);
virtual bool handleReceivedProtobuf(const MeshPacket &mp, EnvironmentalMeasurement *p);
virtual int32_t runOnce();
/**
* Send our EnvironmentalMeasurement into the mesh

View File

@@ -5,7 +5,9 @@
//#include "mesh/wifi/WiFiAPClient.h"
void initWifi(bool forceSoftAP) {}
bool initWifi(bool forceSoftAP) {
return false;
}
void deinitWifi() {}

View File

@@ -171,8 +171,25 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define GPS_RX_PIN PIN_SERIAL1_RX
#define GPS_TX_PIN PIN_SERIAL1_TX
// The battery sense is hooked to pin A0
// Battery
// The battery sense is hooked to pin A0 (5)
#define BATTERY_PIN PIN_A0
// and has 12 bit resolution
#define BATTERY_SENSE_RESOLUTION_BITS 12
#define BATTERY_SENSE_RESOLUTION 4096.0
// Definition of milliVolt per LSB => 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
#define VBAT_MV_PER_LSB (0.73242188F)
// Voltage divider value => 1.5M + 1M voltage divider on VBAT = (1.5M / (1M + 1.5M))
#define VBAT_DIVIDER (0.4F)
// Compensation factor for the VBAT divider
#define VBAT_DIVIDER_COMP (1.73)
// Fixed calculation of milliVolt from compensation value
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER VBAT_DIVIDER_COMP //REAL_VBAT_MV_PER_LSB
#define VBAT_RAW_TO_SCALED(x) (REAL_VBAT_MV_PER_LSB * x)
#ifdef __cplusplus
}

View File

@@ -251,6 +251,26 @@ External serial flash WP25R1635FZUIL0
// To debug via the segger JLINK console rather than the CDC-ACM serial device
// #define USE_SEGGER
// Battery
// The battery sense is hooked to pin A0 (4)
// it is defined in the anlaolgue pin section of this file
// and has 12 bit resolution
#define BATTERY_SENSE_RESOLUTION_BITS 12
#define BATTERY_SENSE_RESOLUTION 4096.0
// Definition of milliVolt per LSB => 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
#define VBAT_MV_PER_LSB (0.73242188F)
// Voltage divider value => 100K + 100K voltage divider on VBAT = (100K / (100K + 100K))
#define VBAT_DIVIDER (0.5F)
// Compensation factor for the VBAT divider
#define VBAT_DIVIDER_COMP (2.0)
// Fixed calculation of milliVolt from compensation value
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER VBAT_DIVIDER_COMP
#define VBAT_RAW_TO_SCALED(x) (REAL_VBAT_MV_PER_LSB * x)
#ifdef __cplusplus
}
#endif

View File

@@ -1,4 +1,4 @@
[VERSION]
major = 1
minor = 2
build = 42
build = 45