Compare commits

...

16 Commits

Author SHA1 Message Date
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
16 changed files with 375 additions and 146 deletions

4
.vscode/launch.json vendored
View File

@@ -12,7 +12,7 @@
"type": "platformio-debug", "type": "platformio-debug",
"request": "launch", "request": "launch",
"name": "PIO Debug", "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", "toolchainBinDir": "/home/kevinh/.platformio/packages/toolchain-xtensa32/bin",
"preLaunchTask": { "preLaunchTask": {
"type": "PlatformIO", "type": "PlatformIO",
@@ -24,7 +24,7 @@
"type": "platformio-debug", "type": "platformio-debug",
"request": "launch", "request": "launch",
"name": "PIO Debug (skip Pre-Debug)", "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", "toolchainBinDir": "/home/kevinh/.platformio/packages/toolchain-xtensa32/bin",
"internalConsoleOptions": "openOnSessionStart" "internalConsoleOptions": "openOnSessionStart"
} }

View File

@@ -7,9 +7,6 @@ source bin/version.sh
COUNTRIES="US EU433 EU865 CN JP" COUNTRIES="US EU433 EU865 CN JP"
#COUNTRIES=US #COUNTRIES=US
SRCMAP=.pio/build/esp32/output.map
SRCBIN=.pio/build/esp32/firmware.bin
SRCELF=.pio/build/esp32/firmware.elf
OUTDIR=release/latest OUTDIR=release/latest
# We keep all old builds (and their map files in the archive dir) # We keep all old builds (and their map files in the archive dir)
@@ -17,25 +14,30 @@ ARCHIVEDIR=release/archive
rm -f $OUTDIR/firmware* rm -f $OUTDIR/firmware*
# 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/firmware-$ENV_NAME-$COUNTRY-$VERSION.bin
cp $SRCELF $OUTDIR/firmware-$ENV_NAME-$COUNTRY-$VERSION.elf
}
for COUNTRY in $COUNTRIES; do for COUNTRY in $COUNTRIES; do
HWVERSTR="1.0-$COUNTRY" 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" export PLATFORMIO_BUILD_FLAGS="$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="-DHELTEC_LORA32 $COMMONOPTS" do_build "tbeam0.7"
rm -f $SRCBIN $SRCMAP do_build "ttgo-lora32-v2"
pio run # -v do_build "ttgo-lora32-v1"
cp $SRCBIN $OUTDIR/firmware-HELTEC-$COUNTRY-$VERSION.bin do_build "tbeam"
cp $SRCELF $OUTDIR/firmware-HELTEC-$COUNTRY-$VERSION.elf do_build "heltec"
#cp $SRCMAP $ARCHIVEDIR/firmware-HELTEC-$COUNTRY-$VERSION.map
done done
# keep the bins in archive also # keep the bins in archive also

View File

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

View File

@@ -17,6 +17,7 @@ Items to complete soon (next couple of alpha releases).
Items to complete before the first beta release. 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/ - 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 ? - 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/ - 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) 1. Purchase a suitable radio (see above)
2. Install [PlatformIO](https://platformio.org/platformio-ide) 2. Install [PlatformIO](https://platformio.org/platformio-ide)
3. Download this git repo and cd into it 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): 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.
```
// #define T_BEAM_V10
#define HELTEC_LORA32
```
5. Plug the radio into your USB port 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) 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 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 ## Decoding stack traces
If you get a crash, you can decode the addresses from the `Backtrace:` line: 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`. 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 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 last `firmware.elf`, so you must be running the same binary that's still in

View File

@@ -10,7 +10,7 @@ TODO:
* DONE read about mesh routing solutions (DSR and AODV) * DONE read about mesh routing solutions (DSR and AODV)
* DONE read about general mesh flooding solutions (naive, MPR, geo assisted) * 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) * 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 * 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) * 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 ; https://docs.platformio.org/page/projectconf.html
[platformio] [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 platform = espressif32
board = ttgo-t-beam
; board = heltec_wifi_lora_32_V2
framework = arduino framework = arduino
; customize the partition table ; customize the partition table
@@ -22,14 +25,13 @@ board_build.partitions = partition-table.csv
; note: we add src to our include search path so that lmic_project_config can override ; 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 ; 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 ; 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 ; also to use PSRAM https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram
; -DBOARD_HAS_PSRAM ; -DBOARD_HAS_PSRAM
; -mfix-esp32-psram-cache-issue ; -mfix-esp32-psram-cache-issue
; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG ; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
upload_speed = 921600 upload_speed = 921600
@@ -55,8 +57,6 @@ debug_tool = jlink
debug_init_break = tbreak setup debug_init_break = tbreak setup
; Note: some libraries are specified by #ID where there are conflicting library
; names.
lib_deps = lib_deps =
https://github.com/meshtastic/RadioHead.git https://github.com/meshtastic/RadioHead.git
https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306 https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306
@@ -68,9 +68,32 @@ lib_deps =
https://github.com/meshtastic/arduino-fsm.git https://github.com/meshtastic/arduino-fsm.git
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
;[env:tbeam] ; The 1.0 release of the TBEAM board
;board = ttgo-t-beam [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 ;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

View File

@@ -16,7 +16,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 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 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; static bool wantNewLocation = true;
GPS::GPS() : PeriodicTask() {} GPS::GPS() : PeriodicTask() {}

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 /// Restart our lock attempt - try to get and broadcast a GPS reading ASAP
void startLock(); void startLock();
/// Returns ture if we have acquired GPS lock.
bool hasLock() const { return hasValidLocation; }
private: private:
void readFromRTC(); void readFromRTC();
bool hasValidLocation = false; // default to false, until we complete our first read
}; };
extern GPS gps; extern GPS gps;

View File

@@ -151,7 +151,7 @@ void MeshService::handleFromRadio(MeshPacket *mp)
mp->rx_time = gps.getValidTime(); // store the arrival timestamp for the phone 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 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); handleIncomingPosition(mp);
else { else {
DEBUG_MSG("Ignoring incoming time, because we have a GPS\n"); DEBUG_MSG("Ignoring incoming time, because we have a GPS\n");
@@ -263,7 +263,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 // 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. // devices can get time.
if (p->has_payload && p->payload.which_variant == SubPacket_position_tag) { 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); DEBUG_MSG("Stripping time %u from position send\n", p->payload.variant.position.time);
p->payload.variant.position.time = 0; p->payload.variant.position.time = 0;
} else } else

View File

@@ -39,18 +39,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Configuration // 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) // 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 // 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 //#define USE_JTAG
#endif #endif
@@ -105,9 +96,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MOSI_GPIO 27 #define MOSI_GPIO 27
#define NSS_GPIO 18 #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 // 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 // #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
@@ -126,27 +117,87 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Leave undefined to disable our PMU IRQ handler // Leave undefined to disable our PMU IRQ handler
#define PMU_IRQ 35 #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 // 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 BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
#define I2C_SDA 4
#define I2C_SDA 21
#define I2C_SCL 22
#define BUTTON_PIN 39
#ifndef USE_JTAG
#define RESET_GPIO 23
#endif
#define DIO0_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 #define I2C_SCL 15
#endif #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 VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 #define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 0 #define BUTTON_PIN 0 // If defined, this will be used for user button presses
#ifndef USE_JTAG #ifndef USE_JTAG
#define RESET_GPIO 14 #define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#endif #endif
#define DIO0_GPIO 26 #define DIO0_GPIO 26
#define DIO1_GPIO 35 #define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 #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 DIO0_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 DIO0_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
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -32,13 +32,14 @@
#include "configuration.h" #include "configuration.h"
#include "esp32/pm.h" #include "esp32/pm.h"
#include "esp_pm.h" #include "esp_pm.h"
#include "power.h"
#include "rom/rtc.h" #include "rom/rtc.h"
#include "screen.h" #include "screen.h"
#include "sleep.h" #include "sleep.h"
#include <Wire.h> #include <Wire.h>
#include <driver/rtc_io.h> #include <driver/rtc_io.h>
#ifdef T_BEAM_V10 #ifdef TBEAM_V10
#include "axp20x.h" #include "axp20x.h"
AXP20X_Class axp; AXP20X_Class axp;
bool pmu_irq = false; bool pmu_irq = false;
@@ -52,9 +53,8 @@ meshtastic::Screen screen(SSD1306_ADDRESS, I2C_SDA, I2C_SCL);
meshtastic::Screen screen(SSD1306_ADDRESS, 0, 0); meshtastic::Screen screen(SSD1306_ADDRESS, 0, 0);
#endif #endif
// these flags are all in bss so they default false // Global power status singleton
bool isCharging; static meshtastic::PowerStatus powerStatus;
bool isUSBPowered;
bool ssd1306_found; bool ssd1306_found;
bool axp192_found; bool axp192_found;
@@ -81,7 +81,7 @@ void scanI2Cdevice(void)
ssd1306_found = true; ssd1306_found = true;
DEBUG_MSG("ssd1306 display found\n"); DEBUG_MSG("ssd1306 display found\n");
} }
#ifdef T_BEAM_V10 #ifdef TBEAM_V10
if (addr == AXP192_SLAVE_ADDRESS) { if (addr == AXP192_SLAVE_ADDRESS) {
axp192_found = true; axp192_found = true;
DEBUG_MSG("axp192 PMU found\n"); DEBUG_MSG("axp192 PMU found\n");
@@ -97,6 +97,21 @@ void scanI2Cdevice(void)
DEBUG_MSG("done\n"); 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 * Init the power manager chip
* *
@@ -108,7 +123,7 @@ void scanI2Cdevice(void)
*/ */
void axp192Init() void axp192Init()
{ {
#ifdef T_BEAM_V10 #ifdef TBEAM_V10
if (axp192_found) { if (axp192_found) {
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) { if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
DEBUG_MSG("AXP192 Begin PASS\n"); DEBUG_MSG("AXP192 Begin PASS\n");
@@ -158,18 +173,18 @@ void axp192Init()
axp.debugCharging(); axp.debugCharging();
#ifdef PMU_IRQ #ifdef PMU_IRQ
pinMode(PMU_IRQ, INPUT_PULLUP); pinMode(PMU_IRQ, INPUT);
attachInterrupt( attachInterrupt(
PMU_IRQ, [] { pmu_irq = true; }, RISING); PMU_IRQ, [] { pmu_irq = true; }, FALLING);
axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1); 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); 1);
axp.clearIRQ(); axp.clearIRQ();
#endif #endif
readPowerStatus();
isCharging = axp.isChargeing() ? 1 : 0;
isUSBPowered = axp.isVBUSPlug() ? 1 : 0;
} else { } else {
DEBUG_MSG("AXP192 Begin FAIL\n"); DEBUG_MSG("AXP192 Begin FAIL\n");
} }
@@ -302,7 +317,7 @@ uint32_t ledBlinker()
setLed(ledOn); setLed(ledOn);
// have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that // 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); Periodic ledPeriodic(ledBlinker);
@@ -310,18 +325,21 @@ Periodic ledPeriodic(ledBlinker);
#if 0 #if 0
// Turn off for now // Turn off for now
uint32_t axpReads() uint32_t axpDebugRead()
{ {
axp.debugCharging(); axp.debugCharging();
DEBUG_MSG("vbus current %f\n", axp.getVbusCurrent()); DEBUG_MSG("vbus current %f\n", axp.getVbusCurrent());
DEBUG_MSG("charge current %f\n", axp.getBattChargeCurrent()); DEBUG_MSG("charge current %f\n", axp.getBattChargeCurrent());
DEBUG_MSG("bat voltage %f\n", axp.getBattVoltage()); DEBUG_MSG("bat voltage %f\n", axp.getBattVoltage());
DEBUG_MSG("batt pct %d\n", axp.getBattPercentage()); 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; return 30 * 1000;
} }
Periodic axpDebugOutput(axpReads); Periodic axpDebugOutput(axpDebugRead);
#endif #endif
void loop() void loop()
@@ -330,7 +348,6 @@ void loop()
powerFSM.run_machine(); powerFSM.run_machine();
gps.loop(); gps.loop();
screen.loop();
service.loop(); service.loop();
ledPeriodic.loop(); ledPeriodic.loop();
@@ -340,27 +357,39 @@ void loop()
// for debug printing // for debug printing
// service.radio.rf95.canSleep(); // service.radio.rf95.canSleep();
#ifdef T_BEAM_V10
if (axp192_found) {
#ifdef PMU_IRQ #ifdef PMU_IRQ
if (pmu_irq) { if (pmu_irq) {
pmu_irq = false; pmu_irq = false;
axp.readIRQ(); axp.readIRQ();
DEBUG_MSG("pmu irq!\n"); DEBUG_MSG("pmu irq!\n");
isCharging = axp.isChargeing() ? 1 : 0; if (axp.isChargingIRQ()) {
isUSBPowered = axp.isVBUSPlug() ? 1 : 0; DEBUG_MSG("Battery start charging\n");
}
axp.clearIRQ(); 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 readPowerStatus();
isCharging = axp.isChargeing() ? 1 : 0; axp.clearIRQ();
isUSBPowered = axp.isVBUSPlug() ? 1 : 0;
#endif
} }
#endif #endif // T_BEAM_V10
#ifdef BUTTON_PIN #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 // 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; 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) // 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. // i.e. don't just keep spinning in loop as fast as we can.
// DEBUG_MSG("msecs %d\n", msecstosleep); // DEBUG_MSG("msecs %d\n", msecstosleep);

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); display->drawString(xo, yo, *f);
xo += SCREEN_WIDTH / COLUMNS; xo += SCREEN_WIDTH / COLUMNS;
// Wrap to next row, if needed. // Wrap to next row, if needed.
if (++col > COLUMNS) { if (++col >= COLUMNS) {
xo = x; xo = x;
yo += FONT_HEIGHT; yo += FONT_HEIGHT;
col = 0; col = 0;
} }
f++; f++;
} }
if (col != 0) {
yo += FONT_HEIGHT; // include the last line in our total // Include last incomplete line in our total.
yo += FONT_HEIGHT;
}
return yo; return yo;
} }
@@ -375,36 +377,6 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2); 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 #if 0
void _screen_header() void _screen_header()
{ {
@@ -467,6 +439,8 @@ void Screen::setup()
ui.setFrameAnimation(SLIDE_LEFT); ui.setFrameAnimation(SLIDE_LEFT);
// Don't show the page swipe dots while in boot screen. // Don't show the page swipe dots while in boot screen.
ui.disableAllIndicators(); ui.disableAllIndicators();
// Store a pointer to Screen so we can get to it from static functions.
ui.getUiState()->userData = this;
// Add frames. // Add frames.
static FrameCallback bootFrames[] = {drawBootScreen}; static FrameCallback bootFrames[] = {drawBootScreen};
@@ -573,6 +547,12 @@ void Screen::doTask()
setPeriod(1000 / targetFramerate); 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 // restore our regular frame list
void Screen::setFrames() void Screen::setFrames()
{ {
@@ -595,7 +575,10 @@ void Screen::setFrames()
normalFrames[numframes++] = drawNodeInfo; normalFrames[numframes++] = drawNodeInfo;
// then the debug info // 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.setFrames(normalFrames, numframes);
ui.enableAllIndicators(); ui.enableAllIndicators();
@@ -642,4 +625,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 } // namespace meshtastic

View File

@@ -7,14 +7,84 @@
#include "PeriodicTask.h" #include "PeriodicTask.h"
#include "TypedQueue.h" #include "TypedQueue.h"
#include "lock.h"
#include "power.h"
namespace meshtastic 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. /// Deals with showing things on the screen of the device.
// //
// Other than setup(), this class is thread-safe. All state-changing calls are // Other than setup(), this class is thread-safe. All state-changing calls are
// queued and executed when the main loop calls us. // 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 class Screen : public PeriodicTask
{ {
public: 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: protected:
/// Updates the UI. /// Updates the UI.
// //
@@ -108,7 +183,9 @@ class Screen : public PeriodicTask
/// Rebuilds our list of frames (screens) to default ones. /// Rebuilds our list of frames (screens) to default ones.
void setFrames(); 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. /// Queue of commands to execute in doTask.
TypedQueue<CmdItem> cmdQueue; TypedQueue<CmdItem> cmdQueue;
/// Whether we are using a display /// Whether we are using a display
@@ -118,6 +195,9 @@ class Screen : public PeriodicTask
// Whether we are showing the regular screen (as opposed to booth screen or // Whether we are showing the regular screen (as opposed to booth screen or
// Bluetooth PIN screen) // Bluetooth PIN screen)
bool showingNormalScreen = false; bool showingNormalScreen = false;
/// Holds state for debug information
DebugInfo debugInfo;
/// Display device /// Display device
SSD1306Wire dispdev; SSD1306Wire dispdev;
/// UI helper for rendering to frames and switching between them /// UI helper for rendering to frames and switching between them

View File

@@ -14,7 +14,7 @@
#include <Wire.h> #include <Wire.h>
#include <driver/rtc_io.h> #include <driver/rtc_io.h>
#ifdef T_BEAM_V10 #ifdef TBEAM_V10
#include "axp20x.h" #include "axp20x.h"
extern AXP20X_Class axp; extern AXP20X_Class axp;
#endif #endif
@@ -48,7 +48,7 @@ void setLed(bool ledOn)
digitalWrite(LED_PIN, ledOn); digitalWrite(LED_PIN, ledOn);
#endif #endif
#ifdef T_BEAM_V10 #ifdef TBEAM_V10
if (axp192_found) { if (axp192_found) {
// blink the axp led // blink the axp led
axp.setChgLEDMode(ledOn ? AXP20X_LED_LOW_LEVEL : AXP20X_LED_OFF); 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); DEBUG_MSG("Setting GPS power=%d\n", on);
#ifdef T_BEAM_V10 #ifdef TBEAM_V10
if (axp192_found) if (axp192_found)
axp.setPowerOutPut(AXP192_LDO3, on ? AXP202_ON : AXP202_OFF); // GPS main power axp.setPowerOutPut(AXP192_LDO3, on ? AXP202_ON : AXP202_OFF); // GPS main power
#endif #endif
@@ -124,7 +124,7 @@ void doDeepSleep(uint64_t msecToWake)
setLed(false); setLed(false);
#ifdef T_BEAM_V10 #ifdef TBEAM_V10
if (axp192_found) { 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 // 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 // leave floating input for the IRQ line
@@ -155,18 +155,13 @@ void doDeepSleep(uint64_t msecToWake)
static const uint8_t rtcGpios[] = {/* 0, */ 2, static const uint8_t rtcGpios[] = {/* 0, */ 2,
/* 4, */ /* 4, */
#ifndef USE_JTAG #ifndef USE_JTAG
12, 12, 13,
13, /* 14, */ /* 15, */
/* 14, */ /* 15, */
#endif #endif
/* 25, */ 26, /* 27, */ /* 25, */ 26, /* 27, */
32, 32, 33, 34, 35,
33, 36, 37
34, /* 38, 39 */};
35,
36,
37,
/* 38, */ 39};
for (int i = 0; i < sizeof(rtcGpios); i++) for (int i = 0; i < sizeof(rtcGpios); i++)
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]); rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
@@ -222,7 +217,8 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
gpio_wakeup_enable((gpio_num_t)DIO0_GPIO, GPIO_INTR_HIGH_LEVEL); // RF95 interrupt, active high gpio_wakeup_enable((gpio_num_t)DIO0_GPIO, GPIO_INTR_HIGH_LEVEL); // RF95 interrupt, active high
#ifdef PMU_IRQ #ifdef PMU_IRQ
// FIXME, disable wake due to PMU because it seems to fire all the time? // 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 #endif
assert(esp_sleep_enable_gpio_wakeup() == ESP_OK); assert(esp_sleep_enable_gpio_wakeup() == ESP_OK);
assert(esp_sleep_enable_timer_wakeup(sleepUsec) == ESP_OK); assert(esp_sleep_enable_timer_wakeup(sleepUsec) == ESP_OK);