Compare commits

...

44 Commits

Author SHA1 Message Date
Kevin Hester
e32b41938a Merge pull request #78 from geeksville/master
Fix #77: bluetooth is supposed to be on in DARK state
2020-04-05 14:41:52 -07:00
geeksville
ef395a1596 0.2.3 2020-04-05 14:39:42 -07:00
geeksville
af35f3006c force other devs to update for
fix https://github.com/meshtastic/Meshtastic-esp32/issues/76
2020-04-05 14:13:04 -07:00
geeksville
13ac686c96 minor doc cleanups 2020-04-05 13:58:38 -07:00
geeksville
05a0266fc4 Fix #77: bluetooth is supposed to be on in DARK state 2020-04-05 13:09:46 -07:00
Kevin Hester
3acbf31198 Merge pull request #75 from geeksville/master
fix bugs I noticed while testing a virgin tbeam
2020-04-04 20:55:06 -07:00
geeksville
2e82bf3ca1 Merge remote-tracking branch 'root/master' 2020-04-04 20:51:31 -07:00
geeksville
63e1a3f47e always set time from GPS if we can 2020-04-04 19:16:30 -07:00
geeksville
07a8972aea NEO-6M gps with empty backup batteries give super invalid times 2020-04-04 18:47:41 -07:00
geeksville
d1cb45aa5d string typo 2020-04-04 18:46:19 -07:00
Kevin Hester
1b3610d0fa Merge pull request #74 from geeksville/master
begin cleanup on radio abstraction - so we can support different radio chips and libraries
2020-04-02 08:10:12 -07:00
geeksville
2fcdc2c09f Merge remote-tracking branch 'root/master' 2020-04-01 11:51:15 -07:00
geeksville
da74803ffb begin cleanup on radio abstraction, details below:
* to allow changing to new mesh transport
* to allow a different chipset for the radio
* to allow testing on hardware with a SimRadio
* new "bare" build env for a devboard with virtually no hardware
* make buttons optional
2020-03-31 21:56:35 -07:00
Kevin Hester
890511615f Merge pull request #72 from geeksville/master
kevin's monday bug queue ;-)
2020-03-31 10:40:13 -07:00
geeksville
17de6f9532 fix #73: allow hw-model to be longer (16 bytes including terminator) 2020-03-30 19:58:06 -07:00
Kevin Hester
2a15195c32 Merge branch 'master' into master 2020-03-30 18:52:29 -07:00
geeksville
1b050a6c3d stop distributing the (enormous) elf files in the zip file 2020-03-30 18:51:15 -07:00
geeksville
1da62e5ba1 oops - we were previously not marking these protobuf structs as valid 2020-03-30 17:02:41 -07:00
geeksville
feb6f2e59e extra debug output for radio config, and bump up bax handles for BLE 2020-03-30 17:02:09 -07:00
geeksville
7dabad1b70 don't let phones send down fatally invalid RadioConfig records
and if a phone did in the past, fixup the garbage we saved in flash
2020-03-30 16:10:11 -07:00
geeksville
a73f466473 Add GPL statement 2020-03-30 13:46:46 -07:00
geeksville
1fd92cf8eb fix build for Windows based on tip from @moinars 2020-03-29 12:33:14 -07:00
Kevin Hester
dd671ceca6 Merge pull request #71 from geeksville/master
add OS-X instructions from @android606
2020-03-29 11:50:13 -07:00
geeksville
8a76931b37 add OS-X instructions from @android606 2020-03-29 11:40:18 -07:00
Kevin Hester
b071eecce1 Merge pull request #70 from geeksville/fix68
Fix68
2020-03-29 11:16:15 -07:00
geeksville
81734f75c8 fix review comments (don't let commands queue up if we are missing a display) 2020-03-29 11:13:53 -07:00
geeksville
11d57e721a fix #68 (@girtsf, pls review - ps: no worries ;-) )
// We don't set useDisplay until setup() is called, because some boards have a declaration of this object but the device
// is never found when probing i2c and therefore we don't call setup and never want to do (invalid) accesses to this device.
2020-03-29 11:00:25 -07:00
geeksville
9b0e329bb9 update credits 2020-03-28 20:33:21 -07:00
Kevin Hester
450fb7bc35 Merge pull request #67 from geeksville/master
kevin's minor work items saturday queue
2020-03-28 20:22:36 -07:00
geeksville
c1f8c8cca4 0.2.0 2020-03-28 20:10:37 -07:00
geeksville
ea250d9cd3 add initial guess at TBEAM 0.7 hardware support 2020-03-28 15:31:22 -07:00
geeksville
be468a2183 add reasonable guesses for TTGO LORA V1 and V2 boards - thanks @sensorsiot
for the pinouts
2020-03-28 14:45:33 -07:00
Kevin Hester
a47d6c4d68 Merge pull request #65 from geeksville/master
kevin's friday minor bugfix queue
2020-03-28 13:26:30 -07:00
geeksville
5386a5b224 update build instructions 2020-03-28 13:17:07 -07:00
geeksville
a350b3795b remove unused file 2020-03-28 13:16:54 -07:00
geeksville
cf2aa37635 clean up configuration.h and add support for ttgo-lora-v1 boards 2020-03-27 16:55:19 -07:00
geeksville
d1387be015 Merge remote-tracking branch 'root/master'
# Conflicts:
#	src/main.cpp
#	src/screen.cpp
2020-03-27 14:18:07 -07:00
Kevin Hester
f8857ad45b Merge pull request #63 from girtsf/debug-screen-b49
fix #49: make debug screen show real data
2020-03-27 14:11:56 -07:00
geeksville
d831beab3d moving build selection into platformio.ini rather than nasty #defines. thanks to @sensorslot
for the pointer to https://github.com/arendst/Tasmota - where I just borrowed heavily ;-)
2020-03-27 14:03:58 -07:00
geeksville
5c4ae6c042 now that axp192 interrups work, no need to poll over i2c. #48 2020-03-27 14:03:58 -07:00
geeksville
a0c97825e8 always use gps.isConnected to check for GPS, it is the only thing
guaranteed to be fresh and accurate
2020-03-27 12:32:18 -07:00
geeksville
cc3bac7ea0 Fix AXP192 handling by @spattinson. yay! fix #48
Also - now that he fixed that, we can leave PMU interrupts on across sleep

Hopefully the following line will properly credit him in the magic github
universe...

Co-authored-by: spattinson <spattinson@users.noreply.github.com>
2020-03-27 12:29:51 -07:00
geeksville
ce21859ada toto updates 2020-03-27 12:08:05 -07:00
Girts Folkmanis
54cd082bfe fix #49: make debug screen show real data
* Break out debug screen to a separate class and make it thread-safe.
* Break out power state to a separate class.
* Show battery voltage, charging & USB status on debug screen.
* Show GPS lock / no lock
* Fix an off-by-one that I introduced earlier in `drawRows`.
2020-03-26 22:17:47 -07:00
31 changed files with 711 additions and 260 deletions

4
.vscode/launch.json vendored
View File

@@ -12,7 +12,7 @@
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug",
"executable": "/home/kevinh/development/meshtastic/meshtastic-esp32/.pio/build/esp32/firmware.elf",
"executable": "/home/kevinh/development/meshtastic/meshtastic-esp32/.pio/build/tbeam/firmware.elf",
"toolchainBinDir": "/home/kevinh/.platformio/packages/toolchain-xtensa32/bin",
"preLaunchTask": {
"type": "PlatformIO",
@@ -24,7 +24,7 @@
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug (skip Pre-Debug)",
"executable": "/home/kevinh/development/meshtastic/meshtastic-esp32/.pio/build/esp32/firmware.elf",
"executable": "/home/kevinh/development/meshtastic/meshtastic-esp32/.pio/build/tbeam/firmware.elf",
"toolchainBinDir": "/home/kevinh/.platformio/packages/toolchain-xtensa32/bin",
"internalConsoleOptions": "openOnSessionStart"
}

View File

@@ -1,39 +1,43 @@
# Meshtastic-esp32
This is the device side code for the [meshtastic.org](https://www.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
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
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 currently early-alpha, but 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.
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. The [TTGO T-Beam](https://www.aliexpress.com/item/4000119152086.html), [TTGO LORA32](https://www.banggood.com/LILYGO-TTGO-LORA32-868Mhz-SX1276-ESP32-Oled-Display-bluetooth-WIFI-Lora-Development-Module-Board-p-1248652.html?cur_warehouse=UK) and the [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/). Most users should buy the T-Beam and a 18650 battery (total cost less than $35). Make
sure to buy the frequency range which is legal for your country. For the USA, you should buy the 915MHz version. Getting a version that include a screen
We currently support three models of radios. The [TTGO T-Beam](https://www.aliexpress.com/item/4000119152086.html), [TTGO LORA32](https://www.banggood.com/LILYGO-TTGO-LORA32-868Mhz-SX1276-ESP32-Oled-Display-bluetooth-WIFI-Lora-Development-Module-Board-p-1248652.html?cur_warehouse=UK) and the [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/). Most users should buy the T-Beam and a 18650 battery (total cost less than \$35). Make
sure to buy the frequency range which is legal for your country. For the USA, you should buy the 915MHz version. Getting a version that include a screen
is optional, but highly recommended.
See (meshtastic.org) for 3D printable cases.
## Installing the firmware
Prebuilt binaries for the supported radios is 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.
The instructions currently require a few commmand lines, but it should be pretty straightforward. Please post comments on our group chat if you have problems or successes. Steps to install:
Prebuilt binaries for the supported radios is 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.
The instructions currently require a few commmand lines, but it should be pretty straightforward. Please post comments on our group chat if you have problems or successes. Steps to install:
1. Purchase a radio (see above) with the correct frequencies for your country (915MHz for US or JP, 470MHz for CN, 433MHz and 870MHz for EU).
2. 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/).
2. 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).
3. Run "pip install --upgrade esptool" to get esptool installed on your machine
4. Connect your radio to your USB port
5. 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:
5. 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
@@ -51,14 +55,16 @@ Warning: ESP32 has no Chip ID. Reading MAC instead.
MAC: 24:6f:28:b5:36:71
Hard resetting via RTS pin...
```
6. cd into the directory where the release zip file was expanded.
7. Install the correct firmware for your board with "device-install.sh firmware-_board_-_country_.bin". For instance "./device-install.sh 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_.bin". This will be faster, also all of your current preferences will be preserved.
6. cd into the directory where the release zip file was expanded.
7. Install the correct firmware for your board with "device-install.sh firmware-_board_-_country_.bin". For instance "./device-install.sh 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_.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
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
@@ -120,29 +126,34 @@ Hash of data verified.
Leaving...
Hard resetting via RTS pin...
```
8. The board will boot and show the Meshtastic logo.
9. 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.
9. 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 source code for the (optional) Meshtastic Android app is [here](https://github.com/meshtastic/Meshtastic-Android).
Alpha test builds are current available by opting into our alpha test group. See (www.meshtastic.org) for instructions.
The source code for the (optional) Meshtastic Android app is [here](https://github.com/meshtastic/Meshtastic-Android).
Alpha test builds are current available by opting into our alpha test group. See (www.meshtastic.org) for instructions.
After our rate of change slows a bit, we will make beta builds available here (without needing to join the alphatest group):
[![Download at https://play.google.com/store/apps/details?id=com.geeksville.mesh](https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png)](https://play.google.com/store/apps/details?id=com.geeksville.mesh&referrer=utm_source%3Dgithub%26utm_medium%3Desp32-readme%26utm_campaign%3Dmeshtastic-esp32%2520readme%26anid%3Dadmob&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1)
# Development
We'd love to have you join us on this merry little project. Please see our [development documents](./docs/software/sw-design.md) and [join us in our discussion forum](https://meshtastic.discourse.group/).
We'd love to have you join us on this merry little project. Please see our [development documents](./docs/software/sw-design.md) and [join us in our discussion forum](https://meshtastic.discourse.group/).
# Credits
This project is run by volunteers. Past contributors include:
This project is run by volunteers. Past contributors include:
* @astro-arphid: Added support for 433MHz radios in europe.
* @claesg: Various documentation fixes and 3D print enclosures
* @girtsf: So far our CI system, but soon lots of device improvements
- @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).
For a listing of currently missing features and a FAQ click [here](docs/faq.md).
Copyright 2019 Geeksville Industries, LLC. GPL V3 Licensed.

View File

@@ -7,9 +7,6 @@ source bin/version.sh
COUNTRIES="US EU433 EU865 CN JP"
#COUNTRIES=US
SRCMAP=.pio/build/esp32/output.map
SRCBIN=.pio/build/esp32/firmware.bin
SRCELF=.pio/build/esp32/firmware.elf
OUTDIR=release/latest
# We keep all old builds (and their map files in the archive dir)
@@ -17,29 +14,37 @@ ARCHIVEDIR=release/archive
rm -f $OUTDIR/firmware*
mkdir -p $OUTDIR/bins $OUTDIR/elfs
rm -f $OUTDIR/bins/*
# build the named environment and copy the bins to the release directory
function do_build {
ENV_NAME=$1
echo "Building for $ENV_NAME with $PLATFORMIO_BUILD_FLAGS"
SRCBIN=.pio/build/$ENV_NAME/firmware.bin
SRCELF=.pio/build/$ENV_NAME/firmware.elf
rm -f $SRCBIN
pio run --environment $ENV_NAME # -v
cp $SRCBIN $OUTDIR/bins/firmware-$ENV_NAME-$COUNTRY-$VERSION.bin
cp $SRCELF $OUTDIR/elfs/firmware-$ENV_NAME-$COUNTRY-$VERSION.elf
}
for COUNTRY in $COUNTRIES; do
HWVERSTR="1.0-$COUNTRY"
COMMONOPTS="-DAPP_VERSION=$VERSION -DHW_VERSION_$COUNTRY -DHW_VERSION=$HWVERSTR -Wall -Wextra -Wno-missing-field-initializers -Isrc -Os -Wl,-Map,.pio/build/esp32/output.map -DAXP_DEBUG_PORT=Serial"
COMMONOPTS="-DAPP_VERSION=$VERSION -DHW_VERSION_$COUNTRY -DHW_VERSION=$HWVERSTR -Wall -Wextra -Wno-missing-field-initializers -Isrc -Os -DAXP_DEBUG_PORT=Serial"
export PLATFORMIO_BUILD_FLAGS="-DT_BEAM_V10 $COMMONOPTS"
echo "Building with $PLATFORMIO_BUILD_FLAGS"
rm -f $SRCBIN $SRCMAP
pio run # -v
cp $SRCBIN $OUTDIR/firmware-TBEAM-$COUNTRY-$VERSION.bin
cp $SRCELF $OUTDIR/firmware-TBEAM-$COUNTRY-$VERSION.elf
#cp $SRCMAP $ARCHIVEDIR/firmware-TBEAM-$COUNTRY-$VERSION.map
export PLATFORMIO_BUILD_FLAGS="$COMMONOPTS"
export PLATFORMIO_BUILD_FLAGS="-DHELTEC_LORA32 $COMMONOPTS"
rm -f $SRCBIN $SRCMAP
pio run # -v
cp $SRCBIN $OUTDIR/firmware-HELTEC-$COUNTRY-$VERSION.bin
cp $SRCELF $OUTDIR/firmware-HELTEC-$COUNTRY-$VERSION.elf
#cp $SRCMAP $ARCHIVEDIR/firmware-HELTEC-$COUNTRY-$VERSION.map
do_build "tbeam0.7"
do_build "ttgo-lora32-v2"
do_build "ttgo-lora32-v1"
do_build "tbeam"
do_build "heltec"
done
# keep the bins in archive also
cp $OUTDIR/firmware* $ARCHIVEDIR
cp $OUTDIR/bins/firmware* $OUTDIR/elfs/firmware* $ARCHIVEDIR
cat >$OUTDIR/curfirmwareversion.xml <<XML
<?xml version="1.0" encoding="utf-8"?>
@@ -54,6 +59,6 @@ Generated by bin/buildall.sh -->
XML
rm -f $ARCHIVEDIR/firmware-$VERSION.zip
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $OUTDIR/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $OUTDIR/bins/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh
echo BUILT ALL

View File

@@ -1,3 +1,3 @@
export VERSION=0.1.10
export VERSION=0.2.3

View File

@@ -17,6 +17,7 @@ Items to complete soon (next couple of alpha releases).
Items to complete before the first beta release.
- possibly switch to https://github.com/SlashDevin/NeoGPS for gps comms
- good source of battery/signal/gps icons https://materialdesignicons.com/
- research and implement better mesh algorithm - investigate changing routing to https://github.com/sudomesh/LoRaLayer2 ?
- check fcc rules on duty cycle. we might not need to freq hop. https://www.sunfiretesting.com/LoRa-FCC-Certification-Guide/

View File

@@ -6,19 +6,15 @@ in these instructions I describe use of their command line tool.
1. Purchase a suitable radio (see above)
2. Install [PlatformIO](https://platformio.org/platformio-ide)
3. Download this git repo and cd into it
4. Edit configuration.h and comment out *one* of the following two lines (depending on which board you are using):
```
// #define T_BEAM_V10
#define HELTEC_LORA32
```
4. If you are outside the USA, edit [platformio.ini](/platformio.ini) to set the correct frequency range for your country. The line you need to change starts with "hw_version" and instructions are provided above that line. Options are provided for EU433, EU835, CN, JP and US. Pull-requests eagerly accepted for other countries.
5. Plug the radio into your USB port
6. Type "pio run -t upload" (This command will fetch dependencies, build the project and install it on the board via USB)
7. Platform IO also installs a very nice VisualStudio Code based IDE, see their [tutorial](https://docs.platformio.org/en/latest/tutorials/espressif32/arduino_debugging_unit_testing.html) if you'd like to use it
6. Type "pio run --environment XXX -t upload" (This command will fetch dependencies, build the project and install it on the board via USB). For XXX, use the board type you have (either tbeam, heltec, ttgo-lora32-v1, ttgo-lora32-v2).
7. Platform IO also installs a very nice VisualStudio Code based IDE, see their [tutorial](https://docs.platformio.org/en/latest/tutorials/espressif32/arduino_debugging_unit_testing.html) if you'd like to use it.
## Decoding stack traces
If you get a crash, you can decode the addresses from the `Backtrace:` line:
1. Save the `Backtrace: 0x....` line to a file, e.g., `backtrace.txt`.
2. Run `bin/exception_decoder.py backtrace.txt` (this uses symbols from the
last `firmware.elf`, so you must be running the same binary that's still in

View File

@@ -0,0 +1,27 @@
(Here's some quick tips on installing the device code from OS-X, thanks to @android606)
First time using LoRa for anything, just checking it out.
I bought a T-Beam on eBay, followed the instructions to install the firmware here:
[https://github.com/meshtastic/Meshtastic-esp32](https://github.com/meshtastic/Meshtastic-esp32)
I'm using a Mac for this, so that might account for differences in the steps to get it working. I just swapped out my SSD last month, I'm using a pretty fresh install of OS X 10.15.3/Catalina.
I got it working fairly smoothly, but there were two hang-ups I thought I'd mention:
1. I am about 0% familiar with Python, so there were some issues getting esptool.py working. Basically, this OS X comes with Python 2.7 and no pip. Pip installed okay, so I used it to install esptool. Esptool appeared to install correctly, but I couldn't get it to work to save my life. Simply typing "esptool.py" doesn't work, and I just don't know enough python to figure out why. For some reason, it installs but isn't in the \$PATH anywhere, and I don't know where it went. Python 2.7 kept giving me warning messages about being old and unsupported, so I figured that might be a hint that I should upgrade.
I ended up doing this:
- brew install pyenv (to install pyenv)
- pyenv install 3.7.7 (to install and select python 3.7.7)
- pyenv global 3.7.7 (to select the new version of python)
- brew install pip (to install pip3)
- pip3 install --upgrade esptool (note I specifically had to use "pip3", not "pip")
...then I was able to execute esptool.py
2. esptool.py didn't work though, because the virtual com port wasn't showing up as a device. I had to install a driver from Silicon Labs, which I got here:
[driver for the CP210X USB to UART bridge from Silicon Labs](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers)
After I installed that, esptool.py was completely happy and the firmware loaded right up.

View File

@@ -10,7 +10,7 @@ TODO:
* DONE read about mesh routing solutions (DSR and AODV)
* DONE read about general mesh flooding solutions (naive, MPR, geo assisted)
* DONE reread the disaster radio protocol docs - seems based on Babel (which is AODVish)
* possibly dash7? https://www.slideshare.net/MaartenWeyn1/dash7-alliance-protocol-technical-presentation https://github.com/MOSAIC-LoPoW/dash7-ap-open-source-stack
* possibly dash7? https://www.slideshare.net/MaartenWeyn1/dash7-alliance-protocol-technical-presentation https://github.com/MOSAIC-LoPoW/dash7-ap-open-source-stack - does the opensource stack implement multihop routing? flooding? their discussion mailing list looks dead-dead
* update duty cycle spreadsheet for our typical usecase
* generalize naive flooding on top of radiohead or disaster.radio? (and fix radiohead to use my new driver)

View File

@@ -9,11 +9,14 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = tbeam
[env:esp32]
[common]
; default to a US frequency range, change it as needed for your region and hardware (CN, JP, EU433, EU865)
hw_version = US
[env]
platform = espressif32
board = ttgo-t-beam
; board = heltec_wifi_lora_32_V2
framework = arduino
; customize the partition table
@@ -22,23 +25,24 @@ board_build.partitions = partition-table.csv
; note: we add src to our include search path so that lmic_project_config can override
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
build_flags = -Wall -Wextra -Wno-missing-field-initializers -Isrc -Os -Wl,-Map,.pio/build/esp32/output.map -DAXP_DEBUG_PORT=Serial
build_flags = -Wall -Wextra -Wno-missing-field-initializers -Isrc -Os -Wl,-Map,.pio/build/output.map -DAXP_DEBUG_PORT=Serial -DHW_VERSION_${common.hw_version}
; not needed included in ttgo-t-beam board file
; also to use PSRAM https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram
; -DBOARD_HAS_PSRAM
; -mfix-esp32-psram-cache-issue
; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
; leave this commented out to avoid breaking Windows
;upload_port = /dev/ttyUSB0
;monitor_port = /dev/ttyUSB0
upload_speed = 921600
upload_port = /dev/ttyUSB0
; the default is esptool
; upload_protocol = esp-prog
monitor_port = /dev/ttyUSB0
monitor_speed = 115200
# debug_tool = esp-prog
@@ -55,10 +59,8 @@ debug_tool = jlink
debug_init_break = tbreak setup
; Note: some libraries are specified by #ID where there are conflicting library
; names.
lib_deps =
https://github.com/meshtastic/RadioHead.git
https://github.com/meshtastic/RadioHead.git#a87518beacfff53bc2eec5ae33c607713e9596e6
https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306
AXP202X_Library
SPI
@@ -68,9 +70,39 @@ lib_deps =
https://github.com/meshtastic/arduino-fsm.git
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
;[env:tbeam]
;board = ttgo-t-beam
; The 1.0 release of the TBEAM board
[env:tbeam]
board = ttgo-t-beam
lib_deps =
${env.lib_deps}
AXP202X_Library
build_flags =
${env.build_flags} -D TBEAM_V10
;[env:heltec]
; The original TBEAM board without the AXP power chip and a few other changes
[env:tbeam0.7]
board = ttgo-t-beam
build_flags =
${env.build_flags} -D TBEAM_V07
[env:heltec]
;build_type = debug ; to make it possible to step through our jtag debugger
;board = heltec_wifi_lora_32_V2
board = heltec_wifi_lora_32_V2
[env:ttgo-lora32-v1]
board = ttgo-lora32-v1
build_flags =
${env.build_flags} -D TTGO_LORA_V1
; note: the platformio definition for lora32-v2 seems stale, it is missing a pins_arduino.h file, therefore I don't think it works
[env:ttgo-lora32-v2]
board = ttgo-lora32-v1
build_flags =
${env.build_flags} -D TTGO_LORA_V2
; This is a temporary build target to test turning off particular hardare bits in the build (to improve modularity)
[env:bare]
board = ttgo-lora32-v1
build_flags =
${env.build_flags} -D BARE_BOARD

2
proto

Submodule proto updated: 1b2449b50d...d13d741a98

View File

@@ -5,12 +5,14 @@
#include <pb_decode.h>
#include <pb_encode.h>
#ifdef RF95_IRQ_GPIO
/// A temporary buffer used for sending/receving packets, sized to hold the biggest buffer we might need
#define MAX_RHPACKETLEN 251
static uint8_t radiobuf[MAX_RHPACKETLEN];
CustomRF95::CustomRF95(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
: RH_RF95(NSS_GPIO, DIO0_GPIO), pool(_pool), rxDest(_rxDest), txQueue(MAX_TX_QUEUE), sendingPacket(NULL)
: RH_RF95(NSS_GPIO, RF95_IRQ_GPIO), RadioInterface(_pool, _rxDest), txQueue(MAX_TX_QUEUE)
{
}
@@ -173,3 +175,5 @@ void CustomRF95::startSend(MeshPacket *txp)
int res = RH_RF95::send(radiobuf, numbytes);
assert(res);
}
#endif

View File

@@ -1,8 +1,6 @@
#pragma once
#include "MemoryPool.h"
#include "MeshTypes.h"
#include "PointerQueue.h"
#include "RadioInterface.h"
#include "mesh.pb.h"
#include <RHMesh.h>
#include <RH_RF95.h>
@@ -12,15 +10,12 @@
/**
* A version of the RF95 driver which is smart enough to manage packets via queues (no polling or blocking in user threads!)
*/
class CustomRF95 : public RH_RF95
class CustomRF95 : public RH_RF95, public RadioInterface
{
friend class MeshRadio; // for debugging we let that class touch pool
MemoryPool<MeshPacket> &pool;
PointerQueue<MeshPacket> &rxDest;
PointerQueue<MeshPacket> txQueue;
MeshPacket *sendingPacket; // The packet we are currently sending
public:
/** pool is the pool we will alloc our rx packets from
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool

View File

@@ -6,8 +6,7 @@
HardwareSerial _serial_gps(GPS_SERIAL_NUM);
RTC_DATA_ATTR bool timeSetFromGPS; // We only reset our time once per _boot_ after that point just run from the internal clock
// (even across sleeps)
bool timeSetFromGPS; // We try to set our time from GPS each time we wake from sleep
GPS gps;
@@ -16,7 +15,6 @@ static uint32_t
timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time
static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock
static bool hasValidLocation; // default to false, until we complete our first read
static bool wantNewLocation = true;
GPS::GPS() : PeriodicTask() {}
@@ -177,8 +175,10 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
DEBUG_MSG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
perhapsSetRTC(&tv);
if (t.tm_year < 0 || t.tm_year >= 300)
DEBUG_MSG("Ignoring invalid GPS time\n");
else
perhapsSetRTC(&tv);
}
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP()) // rd fixes only

View File

@@ -45,8 +45,13 @@ class GPS : public PeriodicTask, public Observable
/// Restart our lock attempt - try to get and broadcast a GPS reading ASAP
void startLock();
/// Returns ture if we have acquired GPS lock.
bool hasLock() const { return hasValidLocation; }
private:
void readFromRTC();
bool hasValidLocation = false; // default to false, until we complete our first read
};
extern GPS gps;

View File

@@ -106,12 +106,13 @@ class RadioCharacteristic : public ProtobufCharacteristic
void onRead(BLECharacteristic *c)
{
DEBUG_MSG("Reading radio config\n");
DEBUG_MSG("Reading radio config, sdsecs %u\n", radioConfig.preferences.sds_secs);
ProtobufCharacteristic::onRead(c);
}
void onWrite(BLECharacteristic *c)
{
DEBUG_MSG("Writing radio config\n");
ProtobufCharacteristic::onWrite(c);
service.reloadConfig();
}
@@ -263,7 +264,7 @@ See bluetooth-api.md for documentation.
BLEService *createMeshBluetoothService(BLEServer *server)
{
// Create the BLE Service, we need more than the default of 15 handles
BLEService *service = server->createService(BLEUUID("6ba1b218-15a8-461f-9fa8-5dcae273eafd"), 25, 0);
BLEService *service = server->createService(BLEUUID("6ba1b218-15a8-461f-9fa8-5dcae273eafd"), 30, 0);
assert(!meshFromNumCharacteristic);
meshFromNumCharacteristic = new FromNumCharacteristic;

View File

@@ -10,10 +10,6 @@
#include <pb_decode.h>
#include <pb_encode.h>
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
/**
* ## LoRaWAN for North America
@@ -28,18 +24,11 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts
/// Sometimes while debugging it is useful to set this false, to disable rf95 accesses
bool useHardware = true;
MeshRadio::MeshRadio(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest) : rf95(_pool, _rxDest), manager(rf95)
MeshRadio::MeshRadio(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
: radioIf(_pool, _rxDest) // , manager(radioIf)
{
myNodeInfo.num_channels = NUM_CHANNELS;
// radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast
// channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide bandwidth so
// incompatible radios can talk together
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
channelSettings.tx_power = 23;
memcpy(&channelSettings.psk, &defaultpsk, sizeof(channelSettings.psk));
strcpy(channelSettings.name, "Default");
// Can't print strings this early - serial not setup yet
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
}
@@ -62,10 +51,10 @@ bool MeshRadio::init()
delay(10);
#endif
manager.setThisAddress(
radioIf.setThisAddress(
nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor time.
if (!manager.init()) {
if (!radioIf.init()) {
DEBUG_MSG("LoRa radio init failed\n");
DEBUG_MSG("Uncomment '#define SERIAL_DEBUG' in RH_RF95.cpp for detailed debug info\n");
return false;
@@ -97,11 +86,11 @@ unsigned long hash(char *str)
void MeshRadio::reloadConfig()
{
rf95.setModeIdle(); // Need to be idle before doing init
radioIf.setModeIdle(); // Need to be idle before doing init
// Set up default configuration
// No Sync Words in LORA mode.
rf95.setModemConfig(
radioIf.setModemConfig(
(RH_RF95::ModemConfigChoice)channelSettings.modem_config); // Radio default
// setModemConfig(Bw125Cr48Sf4096); // slow and reliable?
// rf95.setPreambleLength(8); // Default is 8
@@ -109,7 +98,7 @@ void MeshRadio::reloadConfig()
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
int channel_num = hash(channelSettings.name) % NUM_CHANNELS;
float center_freq = CH0 + CH_SPACING * channel_num;
if (!rf95.setFrequency(center_freq)) {
if (!radioIf.setFrequency(center_freq)) {
DEBUG_MSG("setFrequency failed\n");
assert(0); // fixme panic
}
@@ -120,13 +109,13 @@ void MeshRadio::reloadConfig()
// If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then
// you can set transmitter powers from 5 to 23 dBm:
// FIXME - can we do this? It seems to be in the Heltec board.
rf95.setTxPower(channelSettings.tx_power, false);
radioIf.setTxPower(channelSettings.tx_power, false);
DEBUG_MSG("Set radio: name=%s. config=%u, ch=%d, txpower=%d\n", channelSettings.name, channelSettings.modem_config,
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, txpower=%d\n", channelSettings.name, channelSettings.modem_config,
channel_num, channelSettings.tx_power);
// Done with init tell radio to start receiving
rf95.setModeRx();
radioIf.setModeRx();
}
ErrorCode MeshRadio::send(MeshPacket *p)
@@ -134,9 +123,9 @@ ErrorCode MeshRadio::send(MeshPacket *p)
lastTxStart = millis();
if (useHardware)
return rf95.send(p);
return radioIf.send(p);
else {
rf95.pool.release(p);
radioIf.pool.release(p);
return ERRNO_OK;
}
}
@@ -148,12 +137,12 @@ void MeshRadio::loop()
// It should never take us more than 30 secs to send a packet, if it does, we have a bug, FIXME, move most of this
// into CustomRF95
uint32_t now = millis();
if (lastTxStart != 0 && (now - lastTxStart) > TX_WATCHDOG_TIMEOUT && rf95.mode() == RHGenericDriver::RHModeTx) {
DEBUG_MSG("ERROR! Bug! Tx packet took too long to send, forcing radio into rx mode");
rf95.setModeRx();
if (rf95.sendingPacket) { // There was probably a packet we were trying to send, free it
rf95.pool.release(rf95.sendingPacket);
rf95.sendingPacket = NULL;
if (lastTxStart != 0 && (now - lastTxStart) > TX_WATCHDOG_TIMEOUT && radioIf.mode() == RHGenericDriver::RHModeTx) {
DEBUG_MSG("ERROR! Bug! Tx packet took too long to send, forcing radio into rx mode\n");
radioIf.setModeRx();
if (radioIf.sendingPacket) { // There was probably a packet we were trying to send, free it
radioIf.pool.release(radioIf.sendingPacket);
radioIf.sendingPacket = NULL;
}
recordCriticalError(ErrTxWatchdog);
lastTxStart = 0; // Stop checking for now, because we just warned the developer

View File

@@ -64,8 +64,14 @@
class MeshRadio
{
public:
// Kinda ugly way of selecting different radio implementations, but soon this MeshRadio class will be going away
// entirely. At that point we can make things pretty.
#ifdef RF95_IRQ_GPIO
CustomRF95
rf95; // the raw radio interface - for now I'm leaving public - because this class is shrinking to be almost nothing
radioIf; // the raw radio interface - for now I'm leaving public - because this class is shrinking to be almost nothing
#else
SimRadio radioIf;
#endif
/** pool is the pool we will alloc our rx packets from
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
@@ -88,14 +94,8 @@ class MeshRadio
private:
// RHReliableDatagram manager; // don't use mesh yet
RHMesh manager;
// RHMesh manager;
/// Used for the tx timer watchdog, to check for bugs in our transmit code, msec of last time we did a send
uint32_t lastTxStart = 0;
/// low level send, might block for mutiple seconds
ErrorCode sendTo(NodeNum dest, const uint8_t *buf, size_t len);
/// enqueue a received packet in rxDest
void handleReceive(MeshPacket *p);
};

View File

@@ -97,7 +97,7 @@ MeshPacket *MeshService::handleFromRadioUser(MeshPacket *mp)
if (weWin) {
DEBUG_MSG("NOTE! Received a nodenum collision and we are vetoing\n");
packetPool.release(mp); // discard it
releaseToPool(mp); // discard it
mp = NULL;
sendOurOwner(); // send our owner as a _broadcast_ because that other guy is mistakenly using our nodenum
@@ -151,7 +151,7 @@ void MeshService::handleFromRadio(MeshPacket *mp)
mp->rx_time = gps.getValidTime(); // store the arrival timestamp for the phone
// If it is a position packet, perhaps set our clock (if we don't have a GPS of our own, otherwise wait for that to work)
if (!myNodeInfo.has_gps)
if (!gps.isConnected)
handleIncomingPosition(mp);
else {
DEBUG_MSG("Ignoring incoming time, because we have a GPS\n");
@@ -178,8 +178,9 @@ void MeshService::handleFromRadio(MeshPacket *mp)
if (mp->payload.want_response)
sendNetworkPing(mp->from);
} else
DEBUG_MSG("Dropping vetoed User message\n");
} else {
DEBUG_MSG("Not delivering vetoed User message\n");
}
}
void MeshService::handleFromRadio()
@@ -217,6 +218,7 @@ void MeshService::loop()
void MeshService::reloadConfig()
{
// If we can successfully set this radio to these settings, save them to disk
nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings
radio.reloadConfig();
nodeDB.saveToDisk();
}
@@ -263,7 +265,7 @@ void MeshService::sendToMesh(MeshPacket *p)
// nodes shouldn't trust it anyways) Note: for now, we allow a device with a local GPS to include the time, so that gpsless
// devices can get time.
if (p->has_payload && p->payload.which_variant == SubPacket_position_tag) {
if (!myNodeInfo.has_gps) {
if (!gps.isConnected) {
DEBUG_MSG("Stripping time %u from position send\n", p->payload.variant.position.time);
p->payload.variant.position.time = 0;
} else

View File

@@ -83,7 +83,7 @@ class MeshService : private Observer
/// handle all the packets that just arrived from the mesh radio
void handleFromRadio();
/// Handle a packet that just arrived from the radio
/// Handle a packet that just arrived from the radio. We will either eventually enqueue the message to the phone or return it to the free pool
void handleFromRadio(MeshPacket *p);
/// handle a user packet that just arrived on the radio, return NULL if we should not process this packet at all

View File

@@ -44,9 +44,39 @@ static uint8_t ourMacAddr[6];
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
void NodeDB::resetRadioConfig()
{
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
if (radioConfig.preferences.sds_secs == 0) {
DEBUG_MSG("RadioConfig reset!\n");
radioConfig.preferences.send_owner_interval = 4; // per sw-design.md
radioConfig.preferences.position_broadcast_secs = 15 * 60;
radioConfig.preferences.wait_bluetooth_secs = 120;
radioConfig.preferences.screen_on_secs = 30;
radioConfig.preferences.mesh_sds_timeout_secs = 2 * 60 * 60;
radioConfig.preferences.phone_sds_timeout_sec = 2 * 60 * 60;
radioConfig.preferences.sds_secs = 365 * 24 * 60 * 60; // one year
radioConfig.preferences.ls_secs = 60 * 60;
radioConfig.preferences.phone_timeout_secs = 15 * 60;
radioConfig.has_channel_settings = true;
radioConfig.has_preferences = true;
// radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast
// channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide bandwidth
// so incompatible radios can talk together
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
channelSettings.tx_power = 23;
memcpy(&channelSettings.psk, &defaultpsk, sizeof(channelSettings.psk));
strcpy(channelSettings.name, "Default");
}
}
void NodeDB::init()
{
// init our devicestate with valid flags so protobuf writing/reading will work
devicestate.has_my_node = true;
devicestate.has_radio = true;
@@ -57,15 +87,7 @@ void NodeDB::init()
devicestate.node_db_count = 0;
devicestate.receive_queue_count = 0;
radioConfig.preferences.send_owner_interval = 4; // per sw-design.md
radioConfig.preferences.position_broadcast_secs = 15 * 60;
radioConfig.preferences.wait_bluetooth_secs = 120;
radioConfig.preferences.screen_on_secs = 30;
radioConfig.preferences.mesh_sds_timeout_secs = 2 * 60 * 60;
radioConfig.preferences.phone_sds_timeout_sec = 2 * 60 * 60;
radioConfig.preferences.sds_secs = 365 * 24 * 60 * 60; // one year
radioConfig.preferences.ls_secs = 60 * 60;
radioConfig.preferences.phone_timeout_secs = 15 * 60;
resetRadioConfig();
// default to no GPS, until one has been found by probing
myNodeInfo.has_gps = false;
@@ -102,6 +124,7 @@ void NodeDB::init()
// saveToDisk();
loadFromDisk();
resetRadioConfig(); // If bogus settings got saved, then fix them
DEBUG_MSG("NODENUM=0x%x, dbsize=%d\n", myNodeInfo.my_node_num, *numNodes);
}

View File

@@ -43,6 +43,9 @@ class NodeDB
/// write to flash
void saveToDisk();
// Reinit radio config if needed, because sometimes a buggy android app might send us bogus settings
void resetRadioConfig();
/// given a subpacket sniffed from the network, update our DB state
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
void updateFrom(const MeshPacket &p);

View File

@@ -31,7 +31,7 @@ static void lsEnter()
screen.setOn(false);
uint32_t now = millis();
while (!service.radio.rf95.canSleep()) {
while (!service.radio.radioIf.canSleep()) {
delay(10); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives)
if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep
@@ -82,7 +82,12 @@ static void lsIdle()
} else {
DEBUG_MSG("wakeCause %d\n", wakeCause);
if (!digitalRead(BUTTON_PIN)) // If we woke because of press, instead generate a PRESS event.
#ifdef BUTTON_PIN
bool pressed = !digitalRead(BUTTON_PIN);
#else
bool pressed = false;
#endif
if (pressed) // If we woke because of press, instead generate a PRESS event.
{
powerFSM.trigger(EVENT_PRESS);
} else {
@@ -108,6 +113,7 @@ static void nbEnter()
static void darkEnter()
{
setBluetoothEnable(true);
screen.setOn(false);
}

15
src/RadioInterface.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include "CustomRF95.h"
#include "NodeDB.h"
#include "assert.h"
#include "configuration.h"
#include <pb_decode.h>
#include <pb_encode.h>
RadioInterface::RadioInterface(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest) : pool(_pool), rxDest(_rxDest) {}
ErrorCode SimRadio::send(MeshPacket *p)
{
DEBUG_MSG("SimRadio.send\n");
pool.release(p);
return ERRNO_OK;
}

123
src/RadioInterface.h Normal file
View File

@@ -0,0 +1,123 @@
#pragma once
#include "MemoryPool.h"
#include "MeshTypes.h"
#include "PointerQueue.h"
#include "mesh.pb.h"
#include <RH_RF95.h>
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
/**
* Basic operations all radio chipsets must implement.
*
* This defines the SOLE API for talking to radios (because soon we will have alternate radio implementations)
*/
class RadioInterface
{
friend class MeshRadio; // for debugging we let that class touch pool
protected:
MemoryPool<MeshPacket> &pool;
PointerQueue<MeshPacket> &rxDest;
MeshPacket *sendingPacket = NULL; // The packet we are currently sending
public:
/** pool is the pool we will alloc our rx packets from
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
*/
RadioInterface(MemoryPool<MeshPacket> &pool, PointerQueue<MeshPacket> &rxDest);
/**
* Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving)
*
* This method must be used before putting the CPU into deep or light sleep.
*/
virtual bool canSleep() { return true; }
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
/// return true for success
virtual bool sleep() { return true; }
/// Send a packet (possibly by enquing in a private fifo). This routine will
/// later free() the packet to pool. This routine is not allowed to stall because it is called from
/// bluetooth comms code. If the txmit queue is empty it might return an error
virtual ErrorCode send(MeshPacket *p) = 0;
};
class SimRadio : public RadioInterface
{
public:
/** pool is the pool we will alloc our rx packets from
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
*/
SimRadio(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest) : RadioInterface(_pool, _rxDest) {}
virtual ErrorCode send(MeshPacket *p);
// methods from radiohead
/// Sets the address of this node. Defaults to 0xFF. Subclasses or the user may want to change this.
/// This will be used to test the adddress in incoming messages. In non-promiscuous mode,
/// only messages with a TO header the same as thisAddress or the broadcast addess (0xFF) will be accepted.
/// In promiscuous mode, all messages will be accepted regardless of the TO header.
/// In a conventional multinode system, all nodes will have a unique address
/// (which you could store in EEPROM).
/// You would normally set the header FROM address to be the same as thisAddress (though you dont have to,
/// allowing the possibilty of address spoofing).
/// \param[in] thisAddress The address of this node.
virtual void setThisAddress(uint8_t thisAddress) {}
/// Initialise the Driver transport hardware and software.
/// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded.
virtual bool init() { return true; }
/// Sets the transmitter and receiver
/// centre frequency.
/// \param[in] centre Frequency in MHz. 137.0 to 1020.0. Caution: RFM95/96/97/98 comes in several
/// different frequency ranges, and setting a frequency outside that range of your radio will probably not work
/// \return true if the selected frquency centre is within range
bool setFrequency(float centre) { return true; }
/// Select one of the predefined modem configurations. If you need a modem configuration not provided
/// here, use setModemRegisters() with your own ModemConfig.
/// Caution: the slowest protocols may require a radio module with TCXO temperature controlled oscillator
/// for reliable operation.
/// \param[in] index The configuration choice.
/// \return true if index is a valid choice.
bool setModemConfig(RH_RF95::ModemConfigChoice index) { return true; }
/// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running,
/// disables them.
void setModeIdle() {}
/// If current mode is Tx or Idle, changes it to Rx.
/// Starts the receiver in the RF95/96/97/98.
void setModeRx() {}
/// Returns the operating mode of the library.
/// \return the current mode, one of RF69_MODE_*
virtual RHGenericDriver::RHMode mode() { return RHGenericDriver::RHModeIdle; }
/// Sets the transmitter power output level, and configures the transmitter pin.
/// Be a good neighbour and set the lowest power level you need.
/// Some SX1276/77/78/79 and compatible modules (such as RFM95/96/97/98)
/// use the PA_BOOST transmitter pin for high power output (and optionally the PA_DAC)
/// while some (such as the Modtronix inAir4 and inAir9)
/// use the RFO transmitter pin for lower power but higher efficiency.
/// You must set the appropriate power level and useRFO argument for your module.
/// Check with your module manufacturer which transmtter pin is used on your module
/// to ensure you are setting useRFO correctly.
/// Failure to do so will result in very low
/// transmitter power output.
/// Caution: legal power limits may apply in certain countries.
/// After init(), the power will be set to 13dBm, with useRFO false (ie PA_BOOST enabled).
/// \param[in] power Transmitter power level in dBm. For RFM95/96/97/98 LORA with useRFO false,
/// valid values are from +5 to +23.
/// For Modtronix inAir4 and inAir9 with useRFO true (ie RFO pins in use),
/// valid values are from -1 to 14.
/// \param[in] useRFO If true, enables the use of the RFO transmitter pins instead of
/// the PA_BOOST pin (false). Choose the correct setting for your module.
void setTxPower(int8_t power, bool useRFO = false) {}
};

View File

@@ -39,18 +39,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Configuration
// -----------------------------------------------------------------------------
// Select which board is being used. If the outside build environment has sent a choice, just use that
#if !defined(T_BEAM_V10) && !defined(HELTEC_LORA32)
#define T_BEAM_V10 // AKA Rev1 (second board released)
// #define HELTEC_LORA32
#define HW_VERSION_US // We encode the hardware freq range in the hw version string, so sw update can eventually install the
// correct build
#endif
// If we are using the JTAG port for debugging, some pins must be left free for that (and things like GPS have to be disabled)
// we don't support jtag on the ttgo - access to gpio 12 is a PITA
#ifdef HELTEC_LORA32
#ifdef ARDUINO_HELTEC_WIFI_LORA_32_V2
//#define USE_JTAG
#endif
@@ -105,9 +96,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MOSI_GPIO 27
#define NSS_GPIO 18
#if defined(T_BEAM_V10)
#if defined(TBEAM_V10)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "TBEAM"
#define HW_VENDOR "tbeam"
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
@@ -119,34 +110,98 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef USE_JTAG
#define RESET_GPIO 14
#endif
#define DIO0_GPIO 26
#define RF95_IRQ_GPIO 26
#define DIO1_GPIO 33 // Note: not really used on this board
#define DIO2_GPIO 32 // Note: not really used on this board
// Leave undefined to disable our PMU IRQ handler
#define PMU_IRQ 35
#elif defined(HELTEC_LORA32)
#elif defined(TBEAM_V07)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "HELTEC"
#define HW_VENDOR "tbeam0.7"
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
#define I2C_SDA 4
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
#define I2C_SDA 21
#define I2C_SCL 22
#define BUTTON_PIN 39
#ifndef USE_JTAG
#define RESET_GPIO 23
#endif
#define RF95_IRQ_GPIO 26
#define DIO1_GPIO 33 // Note: not really used on this board
#define DIO2_GPIO 32 // Note: not really used on this board
// This board has different GPS pins than all other boards
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 12
#define GPS_TX_PIN 15
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "heltec"
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#endif
#define RESET_OLED 16
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25
#define BUTTON_PIN 0
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#ifndef USE_JTAG
#define RESET_GPIO 14
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#endif
#define DIO0_GPIO 26
#define DIO1_GPIO 35
#define DIO2_GPIO 34
#define RF95_IRQ_GPIO 26
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#elif defined(TTGO_LORA_V1)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "ttgo-lora32-v1"
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
// #define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 2 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#elif defined(TTGO_LORA_V2)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "ttgo-lora32-v2"
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN \
0 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
// between this pin and ground
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#elif defined(BARE_BOARD)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "bare"
#endif
// -----------------------------------------------------------------------------

View File

@@ -32,13 +32,14 @@
#include "configuration.h"
#include "esp32/pm.h"
#include "esp_pm.h"
#include "power.h"
#include "rom/rtc.h"
#include "screen.h"
#include "sleep.h"
#include <Wire.h>
#include <driver/rtc_io.h>
#ifdef T_BEAM_V10
#ifdef TBEAM_V10
#include "axp20x.h"
AXP20X_Class axp;
bool pmu_irq = false;
@@ -52,9 +53,8 @@ meshtastic::Screen screen(SSD1306_ADDRESS, I2C_SDA, I2C_SCL);
meshtastic::Screen screen(SSD1306_ADDRESS, 0, 0);
#endif
// these flags are all in bss so they default false
bool isCharging;
bool isUSBPowered;
// Global power status singleton
static meshtastic::PowerStatus powerStatus;
bool ssd1306_found;
bool axp192_found;
@@ -81,7 +81,7 @@ void scanI2Cdevice(void)
ssd1306_found = true;
DEBUG_MSG("ssd1306 display found\n");
}
#ifdef T_BEAM_V10
#ifdef TBEAM_V10
if (addr == AXP192_SLAVE_ADDRESS) {
axp192_found = true;
DEBUG_MSG("axp192 PMU found\n");
@@ -97,6 +97,21 @@ void scanI2Cdevice(void)
DEBUG_MSG("done\n");
}
#ifdef TBEAM_V10
/// Reads power status to powerStatus singleton.
//
// TODO(girts): move this and other axp stuff to power.h/power.cpp.
void readPowerStatus()
{
powerStatus.haveBattery = axp.isBatteryConnect();
if (powerStatus.haveBattery) {
powerStatus.batteryVoltageMv = axp.getBattVoltage();
}
powerStatus.usb = axp.isVBUSPlug();
powerStatus.charging = axp.isChargeing();
}
#endif // TBEAM_V10
/**
* Init the power manager chip
*
@@ -108,7 +123,7 @@ void scanI2Cdevice(void)
*/
void axp192Init()
{
#ifdef T_BEAM_V10
#ifdef TBEAM_V10
if (axp192_found) {
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
DEBUG_MSG("AXP192 Begin PASS\n");
@@ -158,18 +173,18 @@ void axp192Init()
axp.debugCharging();
#ifdef PMU_IRQ
pinMode(PMU_IRQ, INPUT_PULLUP);
pinMode(PMU_IRQ, INPUT);
attachInterrupt(
PMU_IRQ, [] { pmu_irq = true; }, RISING);
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1);
axp.enableIRQ(AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ,
axp.enableIRQ(AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ | AXP202_CHARGING_FINISHED_IRQ | AXP202_CHARGING_IRQ |
AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_PEK_SHORTPRESS_IRQ,
1);
axp.clearIRQ();
#endif
isCharging = axp.isChargeing() ? 1 : 0;
isUSBPowered = axp.isVBUSPlug() ? 1 : 0;
readPowerStatus();
} else {
DEBUG_MSG("AXP192 Begin FAIL\n");
}
@@ -302,7 +317,7 @@ uint32_t ledBlinker()
setLed(ledOn);
// have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that
return isCharging ? 1000 : (ledOn ? 2 : 1000);
return powerStatus.charging ? 1000 : (ledOn ? 2 : 1000);
}
Periodic ledPeriodic(ledBlinker);
@@ -310,18 +325,21 @@ Periodic ledPeriodic(ledBlinker);
#if 0
// Turn off for now
uint32_t axpReads()
uint32_t axpDebugRead()
{
axp.debugCharging();
DEBUG_MSG("vbus current %f\n", axp.getVbusCurrent());
DEBUG_MSG("charge current %f\n", axp.getBattChargeCurrent());
DEBUG_MSG("bat voltage %f\n", axp.getBattVoltage());
DEBUG_MSG("batt pct %d\n", axp.getBattPercentage());
DEBUG_MSG("is battery connected %d\n", axp.isBatteryConnect());
DEBUG_MSG("is USB connected %d\n", axp.isVBUSPlug());
DEBUG_MSG("is charging %d\n", axp.isChargeing());
return 30 * 1000;
}
Periodic axpDebugOutput(axpReads);
Periodic axpDebugOutput(axpDebugRead);
#endif
void loop()
@@ -330,7 +348,6 @@ void loop()
powerFSM.run_machine();
gps.loop();
screen.loop();
service.loop();
ledPeriodic.loop();
@@ -340,27 +357,39 @@ void loop()
// for debug printing
// service.radio.rf95.canSleep();
#ifdef T_BEAM_V10
if (axp192_found) {
#ifdef PMU_IRQ
if (pmu_irq) {
pmu_irq = false;
axp.readIRQ();
if (pmu_irq) {
pmu_irq = false;
axp.readIRQ();
DEBUG_MSG("pmu irq!\n");
DEBUG_MSG("pmu irq!\n");
isCharging = axp.isChargeing() ? 1 : 0;
isUSBPowered = axp.isVBUSPlug() ? 1 : 0;
axp.clearIRQ();
if (axp.isChargingIRQ()) {
DEBUG_MSG("Battery start charging\n");
}
if (axp.isChargingDoneIRQ()) {
DEBUG_MSG("Battery fully charged\n");
}
if (axp.isVbusRemoveIRQ()) {
DEBUG_MSG("USB unplugged\n");
}
if (axp.isVbusPlugInIRQ()) {
DEBUG_MSG("USB plugged In\n");
}
if (axp.isBattPlugInIRQ()) {
DEBUG_MSG("Battery inserted\n");
}
if (axp.isBattRemoveIRQ()) {
DEBUG_MSG("Battery removed\n");
}
if (axp.isPEKShortPressIRQ()) {
DEBUG_MSG("PEK short button press\n");
}
// FIXME AXP192 interrupt is not firing, remove this temporary polling of battery state
isCharging = axp.isChargeing() ? 1 : 0;
isUSBPowered = axp.isVBUSPlug() ? 1 : 0;
#endif
readPowerStatus();
axp.clearIRQ();
}
#endif
#endif // T_BEAM_V10
#ifdef BUTTON_PIN
// if user presses button for more than 3 secs, discard our network prefs and reboot (FIXME, use a debounce lib instead of
@@ -390,6 +419,14 @@ void loop()
showingBootScreen = false;
}
// Update the screen last, after we've figured out what to show.
screen.debug()->setNodeNumbersStatus(nodeDB.getNumOnlineNodes(), nodeDB.getNumNodes());
screen.debug()->setChannelNameStatus(channelSettings.name);
screen.debug()->setPowerStatus(powerStatus);
// TODO(#4): use something based on hdop to show GPS "signal" strength.
screen.debug()->setGPSStatus(gps.hasLock() ? "ok" : ":(");
screen.loop();
// No GPS lock yet, let the OS put the main CPU in low power mode for 100ms (or until another interrupt comes in)
// i.e. don't just keep spinning in loop as fast as we can.
// DEBUG_MSG("msecs %d\n", msecstosleep);

View File

@@ -50,7 +50,7 @@ typedef struct _MyNodeInfo {
bool has_gps;
int32_t num_channels;
char region[12];
char hw_model[12];
char hw_model[16];
char firmware_version[12];
uint32_t error_code;
uint32_t error_address;
@@ -431,8 +431,8 @@ extern const pb_msgdesc_t ToRadio_msg;
#define RadioConfig_size 120
#define RadioConfig_UserPreferences_size 72
#define NodeInfo_size 155
#define MyNodeInfo_size 81
#define DeviceState_size 15076
#define MyNodeInfo_size 85
#define DeviceState_size 15080
#define FromRadio_size 301
#define ToRadio_size 295

18
src/power.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
namespace meshtastic
{
/// Describes the state of the power system.
struct PowerStatus {
/// Whether we have a battery connected
bool haveBattery;
/// Battery voltage in mV, valid if haveBattery is true
int batteryVoltageMv;
/// Whether USB is connected
bool usb;
/// Whether we are charging the battery
bool charging;
};
} // namespace meshtastic

View File

@@ -135,15 +135,17 @@ static uint32_t drawRows(OLEDDisplay *display, int16_t x, int16_t y, const char
display->drawString(xo, yo, *f);
xo += SCREEN_WIDTH / COLUMNS;
// Wrap to next row, if needed.
if (++col > COLUMNS) {
if (++col >= COLUMNS) {
xo = x;
yo += FONT_HEIGHT;
col = 0;
}
f++;
}
yo += FONT_HEIGHT; // include the last line in our total
if (col != 0) {
// Include last incomplete line in our total.
yo += FONT_HEIGHT;
}
return yo;
}
@@ -375,36 +377,6 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2);
}
static void drawDebugInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setFont(ArialMT_Plain_10);
// The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT);
static char usersStr[20];
snprintf(usersStr, sizeof(usersStr), "Users %d/%d", nodeDB.getNumOnlineNodes(), nodeDB.getNumNodes());
static char channelStr[20];
snprintf(channelStr, sizeof(channelStr), "%s", channelSettings.name);
// We don't show battery levels yet - for now just lie and show debug info
static char batStr[20];
snprintf(batStr, sizeof(batStr), "Batt %x%%", (isCharging << 1) + isUSBPowered);
static char gpsStr[20];
if (myNodeInfo.has_gps)
snprintf(gpsStr, sizeof(gpsStr), "GPS %d%%",
75); // FIXME, use something based on hdop
else
gpsStr[0] = '\0'; // Just show emptystring
const char *fields[] = {batStr, gpsStr, usersStr, channelStr, NULL};
uint32_t yo = drawRows(display, x, y, fields);
display->drawLogBuffer(x, yo);
}
#if 0
void _screen_header()
{
@@ -429,10 +401,7 @@ void _screen_header()
}
#endif
Screen::Screen(uint8_t address, uint8_t sda, uint8_t scl)
: cmdQueue(32), useDisplay(sda || scl), dispdev(address, sda, scl), ui(&dispdev)
{
}
Screen::Screen(uint8_t address, uint8_t sda, uint8_t scl) : cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev) {}
void Screen::handleSetOn(bool on)
{
@@ -453,8 +422,9 @@ void Screen::handleSetOn(bool on)
void Screen::setup()
{
if (!useDisplay)
return;
// We don't set useDisplay until setup() is called, because some boards have a declaration of this object but the device
// is never found when probing i2c and therefore we don't call setup and never want to do (invalid) accesses to this device.
useDisplay = true;
dispdev.resetOrientation();
@@ -467,6 +437,8 @@ void Screen::setup()
ui.setFrameAnimation(SLIDE_LEFT);
// Don't show the page swipe dots while in boot screen.
ui.disableAllIndicators();
// Store a pointer to Screen so we can get to it from static functions.
ui.getUiState()->userData = this;
// Add frames.
static FrameCallback bootFrames[] = {drawBootScreen};
@@ -573,6 +545,12 @@ void Screen::doTask()
setPeriod(1000 / targetFramerate);
}
void Screen::drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
Screen *screen = reinterpret_cast<Screen *>(state->userData);
screen->debugInfo.drawFrame(display, state, x, y);
}
// restore our regular frame list
void Screen::setFrames()
{
@@ -595,7 +573,10 @@ void Screen::setFrames()
normalFrames[numframes++] = drawNodeInfo;
// then the debug info
normalFrames[numframes++] = drawDebugInfo;
//
// Since frames are basic function pointers, we have to use a helper to
// call a method on debugInfo object.
normalFrames[numframes++] = &Screen::drawDebugInfoTrampoline;
ui.setFrames(normalFrames, numframes);
ui.enableAllIndicators();
@@ -642,4 +623,42 @@ void Screen::handleOnPress()
}
}
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setFont(ArialMT_Plain_10);
// The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT);
char usersStr[20];
char channelStr[20];
char batStr[20];
char gpsStr[20];
{
LockGuard guard(&lock);
snprintf(usersStr, sizeof(usersStr), "Users %d/%d", nodesOnline, nodesTotal);
snprintf(channelStr, sizeof(channelStr), "%s", channelName.c_str());
if (powerStatus.haveBattery) {
// TODO: draw a battery icon instead of letter "B".
int batV = powerStatus.batteryVoltageMv / 1000;
int batCv = (powerStatus.batteryVoltageMv % 1000) / 10;
snprintf(batStr, sizeof(batStr), "B %01d.%02dV%c%c", batV, batCv, powerStatus.charging ? '+' : ' ',
powerStatus.usb ? 'U' : ' ');
} else {
snprintf(batStr, sizeof(batStr), "%s", powerStatus.usb ? "USB" : "");
}
if (!gpsStatus.empty()) {
snprintf(gpsStr, sizeof(gpsStr), "GPS %s", gpsStatus.c_str());
} else {
gpsStr[0] = '\0'; // Just show empty string.
}
}
const char *fields[] = {batStr, gpsStr, usersStr, channelStr, nullptr};
uint32_t yo = drawRows(display, x, y, fields);
display->drawLogBuffer(x, yo);
}
} // namespace meshtastic

View File

@@ -7,14 +7,84 @@
#include "PeriodicTask.h"
#include "TypedQueue.h"
#include "lock.h"
#include "power.h"
namespace meshtastic
{
// Forward declarations
class Screen;
/// Handles gathering and displaying debug information.
class DebugInfo
{
public:
DebugInfo(const DebugInfo &) = delete;
DebugInfo &operator=(const DebugInfo &) = delete;
/// Sets user statistics.
void setNodeNumbersStatus(int online, int total)
{
LockGuard guard(&lock);
nodesOnline = online;
nodesTotal = total;
}
/// Sets the name of the channel.
void setChannelNameStatus(const char *name)
{
LockGuard guard(&lock);
channelName = name;
}
/// Sets battery/charging/etc status.
//
void setPowerStatus(const PowerStatus &status)
{
LockGuard guard(&lock);
powerStatus = status;
}
/// Sets GPS status.
//
// If this function never gets called, we assume GPS does not exist on this
// device.
// TODO(girts): figure out what the format should be.
void setGPSStatus(const char *status)
{
LockGuard guard(&lock);
gpsStatus = status;
}
private:
friend Screen;
DebugInfo() {}
/// Renders the debug screen.
void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
int nodesOnline = 0;
int nodesTotal = 0;
PowerStatus powerStatus;
std::string channelName;
std::string gpsStatus;
/// Protects all of internal state.
Lock lock;
};
/// Deals with showing things on the screen of the device.
//
// Other than setup(), this class is thread-safe. All state-changing calls are
// queued and executed when the main loop calls us.
//
// This class is thread-safe (as long as drawFrame is not called multiple times
// simultaneously).
class Screen : public PeriodicTask
{
public:
@@ -66,6 +136,11 @@ class Screen : public PeriodicTask
}
}
/// Returns a handle to the DebugInfo screen.
//
// Use this handle to set things like battery status, user count, GPS status, etc.
DebugInfo *debug() { return &debugInfo; }
protected:
/// Updates the UI.
//
@@ -94,9 +169,13 @@ class Screen : public PeriodicTask
/// Enques given command item to be processed by main loop().
bool enqueueCmd(const CmdItem &cmd)
{
bool success = cmdQueue.enqueue(cmd, 0);
setPeriod(1); // handle ASAP
return success;
if (!useDisplay)
return true; // claim success if our display is not in use
else {
bool success = cmdQueue.enqueue(cmd, 0);
setPeriod(1); // handle ASAP
return success;
}
}
// Implementations of various commands, called from doTask().
@@ -108,7 +187,9 @@ class Screen : public PeriodicTask
/// Rebuilds our list of frames (screens) to default ones.
void setFrames();
private:
/// Called when debug screen is to be drawn, calls through to debugInfo.drawFrame.
static void drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
/// Queue of commands to execute in doTask.
TypedQueue<CmdItem> cmdQueue;
/// Whether we are using a display
@@ -118,6 +199,9 @@ class Screen : public PeriodicTask
// Whether we are showing the regular screen (as opposed to booth screen or
// Bluetooth PIN screen)
bool showingNormalScreen = false;
/// Holds state for debug information
DebugInfo debugInfo;
/// Display device
SSD1306Wire dispdev;
/// UI helper for rendering to frames and switching between them

View File

@@ -14,7 +14,7 @@
#include <Wire.h>
#include <driver/rtc_io.h>
#ifdef T_BEAM_V10
#ifdef TBEAM_V10
#include "axp20x.h"
extern AXP20X_Class axp;
#endif
@@ -48,7 +48,7 @@ void setLed(bool ledOn)
digitalWrite(LED_PIN, ledOn);
#endif
#ifdef T_BEAM_V10
#ifdef TBEAM_V10
if (axp192_found) {
// blink the axp led
axp.setChgLEDMode(ledOn ? AXP20X_LED_LOW_LEVEL : AXP20X_LED_OFF);
@@ -60,7 +60,7 @@ void setGPSPower(bool on)
{
DEBUG_MSG("Setting GPS power=%d\n", on);
#ifdef T_BEAM_V10
#ifdef TBEAM_V10
if (axp192_found)
axp.setPowerOutPut(AXP192_LDO3, on ? AXP202_ON : AXP202_OFF); // GPS main power
#endif
@@ -110,7 +110,7 @@ void doDeepSleep(uint64_t msecToWake)
screen.setOn(false); // datasheet says this will draw only 10ua
// Put radio in sleep mode (will still draw power but only 0.2uA)
service.radio.rf95.sleep();
service.radio.radioIf.sleep();
nodeDB.saveToDisk();
@@ -124,7 +124,7 @@ void doDeepSleep(uint64_t msecToWake)
setLed(false);
#ifdef T_BEAM_V10
#ifdef TBEAM_V10
if (axp192_found) {
// No need to turn this off if the power draw in sleep mode really is just 0.2uA and turning it off would
// leave floating input for the IRQ line
@@ -155,18 +155,13 @@ void doDeepSleep(uint64_t msecToWake)
static const uint8_t rtcGpios[] = {/* 0, */ 2,
/* 4, */
#ifndef USE_JTAG
12,
13,
/* 14, */ /* 15, */
12, 13,
/* 14, */ /* 15, */
#endif
/* 25, */ 26, /* 27, */
32,
33,
34,
35,
36,
37,
/* 38, */ 39};
32, 33, 34, 35,
36, 37
/* 38, 39 */};
for (int i = 0; i < sizeof(rtcGpios); i++)
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
@@ -218,16 +213,21 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
#endif
#ifdef BUTTON_PIN
gpio_wakeup_enable((gpio_num_t)BUTTON_PIN, GPIO_INTR_LOW_LEVEL); // when user presses, this button goes low
gpio_wakeup_enable((gpio_num_t)DIO0_GPIO, GPIO_INTR_HIGH_LEVEL); // RF95 interrupt, active high
#endif
#ifdef RF95_IRQ_GPIO
gpio_wakeup_enable((gpio_num_t)RF95_IRQ_GPIO, GPIO_INTR_HIGH_LEVEL); // RF95 interrupt, active high
#endif
#ifdef PMU_IRQ
// FIXME, disable wake due to PMU because it seems to fire all the time?
// gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_HIGH_LEVEL); // pmu irq
if (axp192_found)
gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_LOW_LEVEL); // pmu irq
#endif
assert(esp_sleep_enable_gpio_wakeup() == ESP_OK);
assert(esp_sleep_enable_timer_wakeup(sleepUsec) == ESP_OK);
assert(esp_light_sleep_start() == ESP_OK);
// DEBUG_MSG("Exit light sleep b=%d, rf95=%d, pmu=%d\n", digitalRead(BUTTON_PIN), digitalRead(DIO0_GPIO),
// DEBUG_MSG("Exit light sleep b=%d, rf95=%d, pmu=%d\n", digitalRead(BUTTON_PIN), digitalRead(RF95_IRQ_GPIO),
// digitalRead(PMU_IRQ));
return esp_sleep_get_wakeup_cause();
}