Compare commits

..

94 Commits
1.1.3 ... 1.1.6

Author SHA1 Message Date
Kevin Hester
4dd50df810 Merge pull request #498 from geeksville/dev
1.1.6
2020-10-21 04:28:55 -07:00
Kevin Hester
14c4022c18 1.1.6 (and screen layout tweaks) 2020-10-21 19:18:03 +08:00
Kevin Hester
a5d7bacdbf Show current region on the boot screen 2020-10-21 17:27:13 +08:00
Kevin Hester
0b3c25f6d9 use correct code for "talking to phone" fixes OTA update while a router 2020-10-21 16:50:09 +08:00
Kevin Hester
ad7a474a52 update buildscript to generate universal/regionless roms 2020-10-21 12:48:04 +08:00
Kevin Hester
430186ec53 Merge remote-tracking branch 'root/master' into dev 2020-10-21 10:44:56 +08:00
Jm Casler
227c6fc27e Merge pull request #494 from meshtastic/dev-https
Added the x-protobuf-schema, initial integration of javascript library, tuning of the CPU throttle timer.
2020-10-18 22:03:46 -07:00
Jm Casler
a37844d7e5 Merge pull request #493 from mc-hamster/master
update case of meshhttpStatic.h
2020-10-18 21:55:25 -07:00
Jm Casler
ff20b29c3c update case of meshhttpStatic.h 2020-10-18 21:44:55 -07:00
Jm Casler
64c29c4a35 Merge pull request #490 from mc-hamster/master
Update filename, cpu clock timer, add more debug info on the web server startup
2020-10-18 21:41:34 -07:00
Jm Casler
d4df3f8a7e mDNS server http://meshtastic.local 2020-10-18 21:39:02 -07:00
Jm Casler
a16c3af30a Clarified debug message regardding the Web Server startup status. 2020-10-18 18:44:08 -07:00
Jm Casler
3061860dab Update sleep timer for the CPU clock 2020-10-18 18:30:19 -07:00
Jm Casler
2450d98b59 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-18 18:08:03 -07:00
Jm Casler
a371592ad9 Added instructions for David 2020-10-18 18:07:44 -07:00
Jm Casler
f7aaf48ae9 Merge pull request #20 from meshtastic/dev-https
Update my branch from dev-https
2020-10-18 18:04:49 -07:00
Jm Casler
1fb604ebc8 Merge pull request #488 from mc-hamster/master
Update dev-https from my fork.
2020-10-18 16:44:01 -07:00
Jm Casler
df2733a3b5 readded nodeScriptScriptsJS. it got lost in the transition to the new webserver 2020-10-17 20:28:19 -07:00
Kevin Hester
8fd3cb1aac add crude charging detection for 'dumb' voltage based battery sensors 2020-10-18 09:44:29 +08:00
Kevin Hester
485c476f17 cleaner battery debug messages 2020-10-18 09:32:12 +08:00
Jm Casler
7dd4ce32d2 Moved style.css into meshhttpStatic.h
Also created /data to store static files before they go into meshhttpStatic.h
2020-10-17 17:33:29 -07:00
Jm Casler
7f12af73d4 Updated to be host and protocol agnostic 2020-10-17 12:00:21 -07:00
Jm Casler
63113d57b3 Initial integration of meshtastic.js and sample code 2020-10-17 11:30:59 -07:00
Jm Casler
32850ff39d Merge pull request #487 from mc-hamster/master
Some cleanup and implement the X-Protobuf-Schema header
2020-10-16 23:40:48 -07:00
Jm Casler
2901f773a4 Some cleanup and implement the X-Protobuf-Schema header 2020-10-16 23:33:50 -07:00
Kevin Hester
a7c54e4ad7 Merge remote-tracking branch 'root/master' into dev 2020-10-17 13:41:51 +08:00
Jm Casler
c2a1141dfa Merge pull request #485 from mc-hamster/master
update class case of HttpAPI
2020-10-16 19:40:32 -07:00
Jm Casler
5b4472ab56 fix case of HttpAPI class 2020-10-16 19:38:59 -07:00
Jm Casler
3262f732d8 Merge pull request #19 from meshtastic/master
update my branch from master
2020-10-16 19:31:59 -07:00
Jm Casler
cff21ca130 Merge pull request #484 from meshtastic/dev-https
Functional protobuf/rest interface.
2020-10-16 19:28:40 -07:00
Jm Casler
81ce04d3da Merge branch 'master' into dev-https 2020-10-16 19:21:06 -07:00
Jm Casler
f4d2b10840 Merge pull request #483 from mc-hamster/master
Update for interface with the JS client.
2020-10-16 19:18:31 -07:00
Jm Casler
2370cb8aac Merge pull request #482 from meshtastic/dev-https
Merge from dev-https to master.
2020-10-16 19:10:04 -07:00
Kevin Hester
59ec87f5b0 oops tbeam was inheriting from arduino, it should inherit from esp32 2020-10-17 09:58:34 +08:00
Jm Casler
0d9481b6ea add allow-headers 2020-10-16 18:00:28 -07:00
Jm Casler
8f0105ccd9 don't send content-type when options is set 2020-10-16 17:46:22 -07:00
Kevin Hester
05ca3c3d56 Update to work with my font size change 2020-10-17 08:44:04 +08:00
Jm Casler
ba549d8fcd Return OPTIONS when requested for toradio 2020-10-16 17:41:08 -07:00
Jm Casler
b9df2c00fa fromradio all option
requesting fromradio will return one protobuf
4:56
requesting fromradio?all=true will give you all of them.
2020-10-16 17:07:35 -07:00
Kevin Hester
d9dcb33576 Merge branch 'master' into dev-https 2020-10-16 17:05:06 -07:00
Jm Casler
f698231be7 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-16 16:36:55 -07:00
Jm Casler
8414f4a6a3 Added access-control-allow headers 2020-10-16 16:36:52 -07:00
Kevin Hester
f3b93d55fb oops fix for esp32 2020-10-16 17:03:04 +08:00
Kevin Hester
2b373048c6 fix battery voltage sensing on NRF52 boards 2020-10-16 17:00:27 +08:00
Kevin Hester
b32e3f1269 Merge pull request #479 from geeksville/dev
minor eink things
2020-10-15 23:44:15 -07:00
Kevin Hester
68ddb712f5 properly keep nrf52s from sleeping 2020-10-16 14:00:56 +08:00
Kevin Hester
2fb5cd8c1c work with more NMEA gps sentences 2020-10-16 14:00:17 +08:00
Kevin Hester
79aea8231f make screen positions less hardwired wrt font size 2020-10-16 11:22:07 +08:00
Kevin Hester
b0837c10c6 eink display improvements 2020-10-16 10:53:55 +08:00
Jm Casler
cd811951b1 Merge pull request #481 from mc-hamster/master
Update from mchamster to dev-https
2020-10-15 19:53:03 -07:00
Jm Casler
df2976dad0 Merge pull request #18 from meshtastic/dev-https
From Dev https to mc-hamster master
2020-10-15 19:40:49 -07:00
Jm Casler
4ccbe6ff71 Merge pull request #480 from meshtastic/master
Updating dev-https from master
2020-10-15 19:40:01 -07:00
Jm Casler
038ddb887f Be a little smarter with setting the CPU frequency
in the event we have HTTPS and HTTP requests within close periods, let the speed set by the HTTPS request take presidence.
2020-10-15 19:28:20 -07:00
Kevin Hester
9134faaed1 turn off segger debug in ttgo eink build 2020-10-15 16:11:40 +08:00
Kevin Hester
649a120fe0 make eink screen look nicer 2020-10-15 15:56:38 +08:00
Kevin Hester
4db0c4a563 Make screen code resolution agnostic. Look better on big TFT/eink screens 2020-10-15 15:12:27 +08:00
Jm Casler
3b2f5fa5e3 fromRadio now returns all the vailable protobufs. a request to http sets the cpu clock to 160mhz, https to 240mhz then will clock it back down after 2 minutes. 2020-10-14 20:24:19 -07:00
Jm Casler
97adb598b6 toRadio is functional 2020-10-14 16:17:12 -07:00
Kevin Hester
7ef2cc8623 Merge pull request #478 from geeksville/dev
1.1.5
2020-10-13 18:11:15 -07:00
Kevin Hester
b41a32c6b6 1.1.5 2020-10-14 09:04:20 +08:00
Kevin Hester
1ebd7b0c3e make lightsleep default time 5 minutes, with 1 minute in for BLE syncing 2020-10-14 08:53:12 +08:00
Kevin Hester
5457541244 fix #477: sleep behavior was broken in app due to device bug since 1.1.1
+        // NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
+        // So even if we internally use 0 to represent 'use default' we still need to send the value we are
+        // using to the app (so that even old phone apps work with new device loads).
2020-10-14 08:45:29 +08:00
Jm Casler
02e3438d5e Added a favicon.ico 2020-10-11 22:13:14 -07:00
Jm Casler
02b1ece6ac Update meshhttp.cpp 2020-10-11 21:30:14 -07:00
Jm Casler
9fdef366f7 Merge pull request #473 from mc-hamster/master
update dev-https from my fork
2020-10-11 21:20:50 -07:00
Jm Casler
284816229e Merge pull request #17 from meshtastic/master
update my fork from head
2020-10-11 21:19:39 -07:00
Jm Casler
10008d4eef fix merge conflict 2020-10-11 21:19:22 -07:00
Jm Casler
58cfd1317c Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-11 20:38:13 -07:00
Jm Casler
3d3f7869d4 Increase CPU frequency on HTTPS requests. Clock back down after a period of time. 2020-10-11 20:38:09 -07:00
Kevin Hester
ef325289eb fix a doc error 2020-10-12 11:09:53 +08:00
Kevin Hester
40c63c0615 Merge pull request #472 from geeksville/dev
1.1.4
2020-10-11 18:39:02 -07:00
Kevin Hester
a9de8b9bb3 oops - only read axp on boards that have it 2020-10-12 09:33:15 +08:00
Kevin Hester
66a7f896c8 1.1.4 2020-10-12 09:27:48 +08:00
Kevin Hester
45a36f5571 fix POWER state entry/exit based on loss of USB power (tx @mc-hamster) 2020-10-12 09:27:07 +08:00
Jm Casler
876d32c9ee Merge pull request #16 from geeksville/mc-master
fix build for linux (by moving esp32 specific lib to esp32 tree)
2020-10-11 18:17:20 -07:00
Kevin Hester
b9ce75b09c fix build for linux (by moving esp32 specific lib to esp32 tree) 2020-10-12 09:03:04 +08:00
Kevin Hester
62493efc40 Merge pull request #471 from geeksville/coroutine
fix my breakage
2020-10-11 17:42:26 -07:00
Kevin Hester
2848b76cc9 Merge branch 'master' into coroutine 2020-10-11 17:28:52 -07:00
Kevin Hester
ef8bea478d Merge branch 'coroutine' of https://github.com/geeksville/Meshtastic-esp32 into coroutine 2020-10-12 08:25:33 +08:00
Kevin Hester
a8e4bbbe65 fix my breaking of button press behavior 2020-10-12 08:25:17 +08:00
Kevin Hester
9a414d9c77 fix my breakage of screen waking 2020-10-12 08:13:32 +08:00
Jm Casler
48e6a60a07 Merge pull request #470 from mc-hamster/master
Merge pull request #15 from meshtastic/master
2020-10-10 22:30:34 -07:00
Jm Casler
ca48079545 Merge pull request #15 from meshtastic/master
updated my branch from head
2020-10-10 22:29:09 -07:00
Jm Casler
76b4be3b87 Merge pull request #469 from mc-hamster/master
Switched to esp32_https_server from the Espressif (Issue #452) and Enable RX LNA (#466)
2020-10-10 22:28:08 -07:00
Jm Casler
d39cc3d57b Checking if ESP32 for the frequency display 2020-10-10 22:06:56 -07:00
Jm Casler
b17a8d7a6a Removed powerExit -- it wasn't working 2020-10-10 21:54:27 -07:00
Jm Casler
c16acb904e Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-10 17:59:46 -07:00
Jm Casler
5b777219be Enable the RX LNA #466
Enabling the RX LNA
2020-10-10 17:59:32 -07:00
Jm Casler
32ea11d2af Merge pull request #14 from meshtastic/master
Update from head
2020-10-10 17:23:13 -07:00
Jm Casler
db8faa9faf added powerExit 2020-10-09 23:07:37 -07:00
Jm Casler
6d178ebc91 Added esp32_https_server to the meshtastic project 2020-10-07 22:18:46 -07:00
Jm Casler
f75a256631 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-07 22:02:59 -07:00
Jm Casler
4f659b7563 Initial check in of HTTPS server for #452
This switches from the espressif web server to esp32_https_server. Both HTTPS and HTTP have been migrated. On board SSL key generation.
2020-10-07 22:02:53 -07:00
Jm Casler
dffcea1f4d Merge pull request #13 from meshtastic/master
Update my fork from head with 1.1 changes
2020-10-07 08:32:54 -07:00
33 changed files with 2719 additions and 799 deletions

View File

@@ -9,11 +9,10 @@ COUNTRIES="US EU433 EU865 CN JP ANZ KR"
#COUNTRIES=CN #COUNTRIES=CN
BOARDS_ESP32="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7" BOARDS_ESP32="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
# BOARDS_ESP32=tbeam
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine # FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
BOARDS_NRF52="lora-relay-v1" BOARDS_NRF52="lora-relay-v1"
BOARDS="$BOARDS_ESP32 $BOARDS_NRF52"
#BOARDS=tbeam
OUTDIR=release/latest OUTDIR=release/latest
@@ -22,22 +21,61 @@ ARCHIVEDIR=release/archive
rm -f $OUTDIR/firmware* rm -f $OUTDIR/firmware*
mkdir -p $OUTDIR/bins $OUTDIR/elfs mkdir -p $OUTDIR/bins
rm -f $OUTDIR/bins/* rm -r $OUTDIR/bins/*
mkdir -p $OUTDIR/bins/universal $OUTDIR/elfs/universal
# build the named environment and copy the bins to the release directory # build the named environment and copy the bins to the release directory
function do_build { function do_build() {
echo "Building for $BOARD with $PLATFORMIO_BUILD_FLAGS" BOARD=$1
COUNTRY=$2
isNrf=$3
echo "Building $COUNTRY for $BOARD with $PLATFORMIO_BUILD_FLAGS"
rm -f .pio/build/$BOARD/firmware.* rm -f .pio/build/$BOARD/firmware.*
# The shell vars the build tool expects to find # The shell vars the build tool expects to find
export HW_VERSION="1.0-$COUNTRY"
export APP_VERSION=$VERSION export APP_VERSION=$VERSION
export COUNTRY
# Are we building a universal/regionless rom?
if [ "x$COUNTRY" != "x" ]
then
export HW_VERSION="1.0-$COUNTRY"
export COUNTRY
basename=firmware-$BOARD-$COUNTRY-$VERSION
else
export HW_VERSION="1.0"
unset COUNTRY
basename=universal/firmware-$BOARD-$VERSION
fi
pio run --jobs 4 --environment $BOARD # -v pio run --jobs 4 --environment $BOARD # -v
SRCELF=.pio/build/$BOARD/firmware.elf SRCELF=.pio/build/$BOARD/firmware.elf
cp $SRCELF $OUTDIR/elfs/firmware-$BOARD-$COUNTRY-$VERSION.elf cp $SRCELF $OUTDIR/elfs/$basename.elf
if [ "$isNrf" = "false" ]
then
echo "Copying ESP32 bin file"
SRCBIN=.pio/build/$BOARD/firmware.bin
cp $SRCBIN $OUTDIR/bins/$basename.bin
else
echo "Generating NRF52 uf2 file"
SRCHEX=.pio/build/$BOARD/firmware.hex
bin/uf2conv.py $SRCHEX -c -o $OUTDIR/bins/$basename.uf2 -f 0xADA52840
fi
}
function do_boards() {
declare boards=$1
declare isNrf=$2
for board in $boards; do
for country in $COUNTRIES; do
do_build $board $country "$isNrf"
done
# Build universal
do_build $board "" "$isNrf"
done
} }
# Make sure our submodules are current # Make sure our submodules are current
@@ -46,26 +84,16 @@ git submodule update
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio lib update platformio lib update
for COUNTRY in $COUNTRIES; do do_boards "$BOARDS_ESP32" "false"
for BOARD in $BOARDS; do do_boards "$BOARDS_NRF52" "true"
do_build $BOARD
done
echo "Copying ESP32 bin files"
for BOARD in $BOARDS_ESP32; do
SRCBIN=.pio/build/$BOARD/firmware.bin
cp $SRCBIN $OUTDIR/bins/firmware-$BOARD-$COUNTRY-$VERSION.bin
done
echo "Generating NRF52 uf2 files"
for BOARD in $BOARDS_NRF52; do
SRCHEX=.pio/build/$BOARD/firmware.hex
bin/uf2conv.py $SRCHEX -c -o $OUTDIR/bins/firmware-$BOARD-$COUNTRY-$VERSION.uf2 -f 0xADA52840
done
done
# keep the bins in archive also # keep the bins in archive also
cp $OUTDIR/bins/firmware* $OUTDIR/elfs/firmware* $ARCHIVEDIR cp $OUTDIR/bins/firmware* $OUTDIR/elfs/firmware* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
echo Updating android bins $OUTDIR/forandroid
rm -rf $OUTDIR/forandroid
mkdir -p $OUTDIR/forandroid
cp -a $OUTDIR/bins/universal/*.bin $OUTDIR/forandroid/
cat >$OUTDIR/curfirmwareversion.xml <<XML cat >$OUTDIR/curfirmwareversion.xml <<XML
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
@@ -79,6 +107,7 @@ Generated by bin/buildall.sh -->
</resources> </resources>
XML XML
echo Generating $ARCHIVEDIR/firmware-$VERSION.zip
rm -f $ARCHIVEDIR/firmware-$VERSION.zip rm -f $ARCHIVEDIR/firmware-$VERSION.zip
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $OUTDIR/bins/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh bin/device-update.sh zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $OUTDIR/bins/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh bin/device-update.sh

22
bin/install-eink.sh Executable file
View File

@@ -0,0 +1,22 @@
# You probably don't want to use this script, it programs a custom bootloader build onto a nrf52 board
set -e
BOOTDIR=/home/kevinh/development/meshtastic/Adafruit_nRF52_Bootloader
nrfjprog --eraseall -f nrf52
# this generates an intel hex file that can be programmed into a NRF52 to tell the adafruit bootloader that the current app image is valid
# Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000
# first 4 bytes should be 0x01 to indicate valid app image
# second 4 bytes should be 0x00 to indicate no CRC required for image
echo "01 00 00 00 00 00 00 00" | xxd -r -p - >/tmp/bootconf.bin
srec_cat /tmp/bootconf.bin -binary -offset 0xff000 -output /tmp/bootconf.hex -intel
echo Generating merged hex file
mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-125-gf38f8f4-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex
echo Telling bootloader app region is valid and telling CPU to run
nrfjprog --program ttgo_eink_full.hex -f nrf52 --reset
# nrfjprog --readuicr /tmp/uicr.hex; objdump -s /tmp/uicr.hex | less

View File

@@ -1,3 +1,3 @@
export VERSION=1.1.3 export VERSION=1.1.6

277
data/style.css Normal file
View File

@@ -0,0 +1,277 @@
/* latin-ext */
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url(./Google.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
*, *:before, *:after {
box-sizing: border-box;
}
body {
background: #C5DDEB;
font: 14px/20px "Lato", Arial, sans-serif;
padding: 40px 0;
color: white;
}
.grid {
display: grid;
grid-template-columns:
1fr 4fr;
grid-template-areas:
"header header"
"sidebar content";
margin: 0 auto;
width: 750px;
background: #444753;
border-radius: 5px;
}
.top {grid-area: header;}
.side {grid-area: sidebar;}
.main {grid-area: content;}
.top {
border-bottom: 2px solid white;
}
.top-text {
font-weight: bold;
font-size: 24px;
text-align: center;
padding: 20px;
}
.side {
width: 260px;
float: left;
}
.side .side-header {
padding: 20px;
border-bottom: 2px solid white;
}
.side .side-header .side-text {
padding-left: 10px;
margin-top: 6px;
font-size: 16px;
text-align: left;
font-weight: bold;
}
.channel-list ul {
padding: 20px;
height: 570px;
list-style-type: none;
}
.channel-list ul li {
padding-bottom: 20px;
}
.channel-list .channel-name {
font-size: 20px;
margin-top: 8px;
padding-left: 8px;
}
.channel-list .message-count {
padding-left: 16px;
color: #92959E;
}
.icon {
display: inline-block;
width: 1em;
height: 1em;
stroke-width: 0;
stroke: currentColor;
fill: currentColor;
}
.icon-map-marker {
width: 0.5714285714285714em;
}
.icon-circle {
width: 0.8571428571428571em;
}
.content {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
/* width: 490px; */
float: left;
background: #F2F5F8;
/* border-top-right-radius: 5px;
border-bottom-right-radius: 5px; */
color: #434651;
}
.content .content-header {
flex-grow: 0;
padding: 20px;
border-bottom: 2px solid white;
}
.content .content-header .content-from {
padding-left: 10px;
margin-top: 6px;
font-size: 20px;
text-align: center;
font-size: 16px;
}
.content .content-header .content-from .content-from-highlight {
font-weight: bold;
}
.content .content-header .content-num-messages {
color: #92959E;
}
.content .content-history {
flex-grow: 1;
padding: 20px 20px 20px;
border-bottom: 2px solid white;
overflow-y: scroll;
height: 375px;
}
.content .content-history ul {
list-style-type: none;
padding-inline-start: 10px;
}
.content .content-history .message-data {
margin-bottom: 10px;
}
.content .content-history .message-data-time {
color: #a8aab1;
padding-left: 6px;
}
.content .content-history .message {
color: white;
padding: 8px 10px;
line-height: 20px;
font-size: 14px;
border-radius: 7px;
margin-bottom: 30px;
width: 90%;
position: relative;
}
.content .content-history .message:after {
bottom: 100%;
left: 7%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-bottom-color: #86BB71;
border-width: 10px;
margin-left: -10px;
}
.content .content-history .my-message {
background: #86BB71;
}
.content .content-history .other-message {
background: #94C2ED;
}
.content .content-history .other-message:after {
border-bottom-color: #94C2ED;
left: 93%;
}
.content .content-message {
flex-grow: 0;
padding: 10px;
}
.content .content-message textarea {
width: 100%;
border: none;
padding: 10px 10px;
font: 14px/22px "Lato", Arial, sans-serif;
margin-bottom: 10px;
border-radius: 5px;
resize: none;
}
.content .content-message button {
float: right;
color: #94C2ED;
font-size: 16px;
text-transform: uppercase;
border: none;
cursor: pointer;
font-weight: bold;
background: #F2F5F8;
}
.content .content-message button:hover {
color: #75b1e8;
}
/* Tooltip container */
.tooltip {
color: #86BB71;
position: relative;
display: inline-block;
border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
}
/* Tooltip text */
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #444753;
color: #fff;
text-align: center;
padding: 5px 0;
border-radius: 6px;
/* Position the tooltip text - see examples below! */
position: absolute;
z-index: 1;
}
/* Show the tooltip text when you mouse over the tooltip container */
.tooltip:hover .tooltiptext {
visibility: visible;
}
.online, .offline, .me {
margin-right: 3px;
font-size: 10px;
}
.online {
color: #86BB71;
}
.offline {
color: #E38968;
}
.me {
color: #94C2ED;
}
.align-left {
text-align: left;
}
.align-right {
text-align: right;
}
.float-right {
float: right;
}
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}

BIN
data/style.css.gz Normal file

Binary file not shown.

View File

@@ -42,7 +42,6 @@ Expected sequence for initial download:
- Read a RadioConfig from "radio" - used to get the channel and radio settings - Read a RadioConfig from "radio" - used to get the channel and radio settings
- Read a User from "user" - to get the username for this node - Read a User from "user" - to get the username for this node
- Read a MyNodeInfo from "mynode" to get information about this local device - Read a MyNodeInfo from "mynode" to get information about this local device
- Write an empty record to "nodeinfo" to restart the nodeinfo reading state machine
- Read a series of NodeInfo packets to build the phone's copy of the current NodeDB for the mesh - Read a series of NodeInfo packets to build the phone's copy of the current NodeDB for the mesh
- Read a endConfig packet that indicates that the entire state you need has been sent. - Read a endConfig packet that indicates that the entire state you need has been sent.
- Read a series of MeshPackets until it returns empty to get any messages that arrived for this node while the phone was away - Read a series of MeshPackets until it returns empty to get any messages that arrived for this node while the phone was away

View File

@@ -7,6 +7,10 @@
TODO: TODO:
- enter SDS state at correct time (to protect battery or loss of phone contact)
- show screen on eink when we enter SDS state (with app info and say sleeping)
- require button press to pair
- shrink soft device RAM usage - shrink soft device RAM usage
- get nrf52832 working again (currently OOM) - get nrf52832 working again (currently OOM)
- i2c gps comms not quite right - i2c gps comms not quite right

View File

@@ -60,7 +60,7 @@ debug_tool = jlink
lib_deps = lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306 https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306
1260 ; OneButton library for non-blocking button debounce https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39 https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
@@ -95,6 +95,9 @@ build_flags =
${arduino_base.build_flags} -Wall -Wextra -Isrc/esp32 -Isrc/esp32-mfix-esp32-psram-cache-issue -lnimble -std=c++11 ${arduino_base.build_flags} -Wall -Wextra -Isrc/esp32 -Isrc/esp32-mfix-esp32-psram-cache-issue -lnimble -std=c++11
-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
-DAXP_DEBUG_PORT=Serial -DAXP_DEBUG_PORT=Serial
lib_deps =
${arduino_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git
# Hmm - this doesn't work yet # Hmm - this doesn't work yet
# board_build.ldscript = linker/esp32.extram.bss.ld # board_build.ldscript = linker/esp32.extram.bss.ld
lib_ignore = segger_rtt lib_ignore = segger_rtt
@@ -117,7 +120,7 @@ board_build.partitions = partition-table.csv
extends = esp32_base extends = esp32_base
board = ttgo-t-beam board = ttgo-t-beam
lib_deps = lib_deps =
${arduino_base.lib_deps} ${esp32_base.lib_deps}
build_flags = build_flags =
${esp32_base.build_flags} -D TBEAM_V10 ${esp32_base.build_flags} -D TBEAM_V10

View File

@@ -18,6 +18,21 @@ Power *power;
using namespace meshtastic; using namespace meshtastic;
#if defined(NRF52_SERIES)
/*
* Internal Reference is +/-0.6V, with an adjustable gain of 1/6, 1/5, 1/4,
* 1/3, 1/2 or 1, meaning 3.6, 3.0, 2.4, 1.8, 1.2 or 0.6V for the ADC levels.
*
* External Reference is VDD/4, with an adjustable gain of 1, 2 or 4, meaning
* VDD/4, VDD/2 or VDD for the ADC levels.
*
* Default settings are internal reference with 1/6 gain (GND..3.6V ADC range)
*/
#define AREF_VOLTAGE 3.6
#else
#define AREF_VOLTAGE 3.3
#endif
/** /**
* If this board has a battery level sensor, set this to a valid implementation * If this board has a battery level sensor, set this to a valid implementation
*/ */
@@ -37,10 +52,13 @@ class AnalogBatteryLevel : public HasBatteryLevel
{ {
float v = getBattVoltage() / 1000; float v = getBattVoltage() / 1000;
if (v < 2.1) if (v < noBatVolt)
return -1; // If voltage is super low assume no battery installed return -1; // If voltage is super low assume no battery installed
return 100 * (v - 3.27) / (4.2 - 3.27); if (v > chargingVolt)
return 0; // While charging we can't report % full on the battery
return 100 * (v - emptyVolt) / (fullVolt - emptyVolt);
} }
/** /**
@@ -48,9 +66,11 @@ class AnalogBatteryLevel : public HasBatteryLevel
*/ */
virtual float getBattVoltage() virtual float getBattVoltage()
{ {
// Tested ttgo eink nrf52 board and the reported value is perfect
// DEBUG_MSG("raw val %u", raw);
return return
#ifdef BATTERY_PIN #ifdef BATTERY_PIN
1000.0 * analogRead(BATTERY_PIN) * 2.0 * (3.3 / 1024.0); 1000.0 * 2.0 * (AREF_VOLTAGE / 1024.0) * analogRead(BATTERY_PIN);
#else #else
NAN; NAN;
#endif #endif
@@ -59,7 +79,20 @@ class AnalogBatteryLevel : public HasBatteryLevel
/** /**
* return true if there is a battery installed in this unit * return true if there is a battery installed in this unit
*/ */
virtual bool isBatteryConnect() { return getBattVoltage() != -1; } virtual bool isBatteryConnect() { return getBattPercentage() != -1; }
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
virtual bool isVBUSPlug() { return getBattVoltage() > chargingVolt; }
/// Assume charging if we have a battery and external power is connected.
/// we can't be smart enough to say 'full'?
virtual bool isChargeing() { return isBatteryConnect() && isVBUSPlug(); }
private:
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
const float fullVolt = 4.2, emptyVolt = 3.27, chargingVolt = 4.3, noBatVolt = 2.1;
} analogLevel; } analogLevel;
Power::Power() : OSThread("Power") {} Power::Power() : OSThread("Power") {}
@@ -68,10 +101,18 @@ bool Power::analogInit()
{ {
#ifdef BATTERY_PIN #ifdef BATTERY_PIN
DEBUG_MSG("Using analog input for battery level\n"); DEBUG_MSG("Using analog input for battery level\n");
// disable any internal pullups
pinMode(BATTERY_PIN, INPUT);
#ifndef NO_ESP32 #ifndef NO_ESP32
// ESP32 needs special analog stuff // ESP32 needs special analog stuff
adcAttachPin(BATTERY_PIN); adcAttachPin(BATTERY_PIN);
#endif #endif
#ifdef NRF52_SERIES
analogReference(AR_INTERNAL); // 3.6V
#endif
// adcStart(BATTERY_PIN); // adcStart(BATTERY_PIN);
analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution. analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
batteryLevel = &analogLevel; batteryLevel = &analogLevel;
@@ -121,7 +162,8 @@ void Power::readPowerStatus()
const PowerStatus powerStatus = const PowerStatus powerStatus =
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse, PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse,
batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent); batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
DEBUG_MSG("Read power stat %d\n", powerStatus.getHasUSB()); DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus.getHasUSB(),
powerStatus.getIsCharging(), powerStatus.getBatteryVoltageMv(), powerStatus.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus); newStatus.notifyObservers(&powerStatus);
// If we have a battery at all and it is less than 10% full, force deep sleep // If we have a battery at all and it is less than 10% full, force deep sleep
@@ -138,38 +180,39 @@ int32_t Power::runOnce()
{ {
readPowerStatus(); readPowerStatus();
#ifdef PMU_IRQ #ifdef TBEAM_V10
if (pmu_irq) { // WE no longer use the IRQ line to wake the CPU (due to false wakes from sleep), but we do poll
pmu_irq = false; // the IRQ status by reading the registers over I2C
axp.readIRQ(); axp.readIRQ();
DEBUG_MSG("pmu irq!\n"); if (axp.isVbusRemoveIRQ()) {
DEBUG_MSG("USB unplugged\n");
if (axp.isChargingIRQ()) { powerFSM.trigger(EVENT_POWER_DISCONNECTED);
DEBUG_MSG("Battery start charging\n");
}
if (axp.isChargingDoneIRQ()) {
DEBUG_MSG("Battery fully charged\n");
}
if (axp.isVbusRemoveIRQ()) {
DEBUG_MSG("USB unplugged\n");
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
}
if (axp.isVbusPlugInIRQ()) {
DEBUG_MSG("USB plugged In\n");
powerFSM.trigger(EVENT_POWER_CONNECTED);
}
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");
}
axp.clearIRQ();
} }
if (axp.isVbusPlugInIRQ()) {
DEBUG_MSG("USB plugged In\n");
powerFSM.trigger(EVENT_POWER_CONNECTED);
}
/*
Other things we could check if we cared...
if (axp.isChargingIRQ()) {
DEBUG_MSG("Battery start charging\n");
}
if (axp.isChargingDoneIRQ()) {
DEBUG_MSG("Battery fully charged\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");
}
*/
axp.clearIRQ();
#endif #endif
// Only read once every 20 seconds once the power status for the app has been initialized // Only read once every 20 seconds once the power status for the app has been initialized

View File

@@ -118,12 +118,21 @@ static void serialEnter()
{ {
setBluetoothEnable(false); setBluetoothEnable(false);
screen->setOn(true); screen->setOn(true);
screen->print("Using API...\n");
} }
static void powerEnter() static void powerEnter()
{ {
screen->setOn(true); screen->setOn(true);
setBluetoothEnable(true); setBluetoothEnable(true);
screen->print("Powered...\n");
}
static void powerExit()
{
screen->setOn(true);
setBluetoothEnable(true);
screen->print("Unpowered...\n");
} }
static void onEnter() static void onEnter()
@@ -140,6 +149,7 @@ static void onEnter()
service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node
lastPingMs = now; lastPingMs = now;
} }
} }
static void screenPress() static void screenPress()
@@ -156,7 +166,7 @@ State stateDARK(darkEnter, NULL, NULL, "DARK");
State stateSERIAL(serialEnter, NULL, NULL, "SERIAL"); State stateSERIAL(serialEnter, NULL, NULL, "SERIAL");
State stateBOOT(bootEnter, NULL, NULL, "BOOT"); State stateBOOT(bootEnter, NULL, NULL, "BOOT");
State stateON(onEnter, NULL, NULL, "ON"); State stateON(onEnter, NULL, NULL, "ON");
State statePOWER(powerEnter, NULL, NULL, "POWER"); State statePOWER(powerEnter, NULL, powerExit, "POWER");
Fsm powerFSM(&stateBOOT); Fsm powerFSM(&stateBOOT);
void PowerFSM_setup() void PowerFSM_setup()
@@ -235,10 +245,16 @@ void PowerFSM_setup()
powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout"); powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout");
powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout"); // On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
State *lowPowerState = &stateLS;
#ifndef NRF52_SERIES #ifndef NRF52_SERIES
// We never enter light-sleep state on NRF52 (because the CPU uses so little power normally) // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
lowPowerState = &stateDARK;
powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout"); powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout"); powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
@@ -246,9 +262,9 @@ void PowerFSM_setup()
auto meshSds = getPref_mesh_sds_timeout_secs(); auto meshSds = getPref_mesh_sds_timeout_secs();
if (meshSds != UINT32_MAX) if (meshSds != UINT32_MAX)
powerFSM.add_timed_transition(&stateLS, &stateSDS, meshSds * 1000, NULL, "mesh timeout"); powerFSM.add_timed_transition(lowPowerState, &stateSDS, meshSds * 1000, NULL, "mesh timeout");
// removing for now, because some users don't even have phones // removing for now, because some users don't even have phones
// powerFSM.add_timed_transition(&stateLS, &stateSDS, getPref_phone_sds_timeout_sec() * 1000, NULL, "phone // powerFSM.add_timed_transition(lowPowerState, &stateSDS, getPref_phone_sds_timeout_sec() * 1000, NULL, "phone
// timeout"); // timeout");
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state

View File

@@ -20,6 +20,6 @@
#define EVENT_POWER_DISCONNECTED 14 #define EVENT_POWER_DISCONNECTED 14
extern Fsm powerFSM; extern Fsm powerFSM;
extern State statePOWER; extern State statePOWER, stateSERIAL;
void PowerFSM_setup(); void PowerFSM_setup();

View File

@@ -82,7 +82,7 @@ class PowerStatus : public Status
isCharging = newStatus->isCharging; isCharging = newStatus->isCharging;
} }
if (isDirty) { if (isDirty) {
DEBUG_MSG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent); // DEBUG_MSG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent);
onNewStatus.notifyObservers(this); onNewStatus.notifyObservers(this);
} }
return 0; return 0;

View File

@@ -4,30 +4,22 @@
namespace concurrency namespace concurrency
{ {
InterruptableDelay::InterruptableDelay() InterruptableDelay::InterruptableDelay() {}
{
}
InterruptableDelay::~InterruptableDelay() InterruptableDelay::~InterruptableDelay() {}
{
}
/** /**
* Returns false if we were interrupted * Returns false if we were interrupted
*/ */
bool InterruptableDelay::delay(uint32_t msec) bool InterruptableDelay::delay(uint32_t msec)
{ {
if (msec) { // DEBUG_MSG("delay %u ", msec);
// DEBUG_MSG("delay %u ", msec);
// sem take will return false if we timed out (i.e. were not interrupted) // sem take will return false if we timed out (i.e. were not interrupted)
bool r = semaphore.take(msec); bool r = semaphore.take(msec);
// DEBUG_MSG("interrupt=%d\n", r); // DEBUG_MSG("interrupt=%d\n", r);
return !r; return !r;
} else {
return true;
}
} }
void InterruptableDelay::interrupt() void InterruptableDelay::interrupt()

View File

@@ -72,7 +72,7 @@ int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
crc.update(data, len); crc.update(data, len);
Update.write(data, len); Update.write(data, len);
updateActualSize += len; updateActualSize += len;
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG); // Not exactly correct, but we want to force the device to not sleep now powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
return 0; return 0;
} }

View File

@@ -1,6 +1,6 @@
#include "NMEAGPS.h" #include "NMEAGPS.h"
#include "configuration.h"
#include "RTC.h" #include "RTC.h"
#include "configuration.h"
static int32_t toDegInt(RawDegrees d) static int32_t toDegInt(RawDegrees d)
{ {
@@ -32,7 +32,7 @@ bool NMEAGPS::lookForTime()
{ {
auto ti = reader.time; auto ti = reader.time;
auto d = reader.date; auto d = reader.date;
if (ti.isUpdated() && ti.isValid() && d.isValid()) { if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
/* Convert to unix time /* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970
(midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z). (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
@@ -65,27 +65,27 @@ bool NMEAGPS::lookForLocation()
// uint8_t fixtype = reader.fixQuality(); // uint8_t fixtype = reader.fixQuality();
// hasValidLocation = ((fixtype >= 1) && (fixtype <= 5)); // hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
if (reader.satellites.isUpdated()) {
setNumSatellites(reader.satellites.value());
}
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
if (reader.hdop.isUpdated()) {
dop = reader.hdop.value();
}
if (reader.course.isUpdated()) {
heading = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
}
if (reader.altitude.isUpdated())
altitude = reader.altitude.meters();
if (reader.location.isUpdated()) { if (reader.location.isUpdated()) {
if (reader.altitude.isValid())
altitude = reader.altitude.meters();
if (reader.location.isValid()) { auto loc = reader.location.value();
auto loc = reader.location.value(); latitude = toDegInt(loc.lat);
latitude = toDegInt(loc.lat); longitude = toDegInt(loc.lng);
longitude = toDegInt(loc.lng); foundLocation = true;
foundLocation = true;
}
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
if (reader.hdop.isValid()) {
dop = reader.hdop.value();
}
if (reader.course.isValid()) {
heading = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
}
if (reader.satellites.isValid()) {
setNumSatellites(reader.satellites.value());
}
// expect gps pos lat=37.520825, lon=-122.309162, alt=158 // expect gps pos lat=37.520825, lon=-122.309162, alt=158
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude,
@@ -102,7 +102,7 @@ bool NMEAGPS::whileIdle()
// First consume any chars that have piled up at the receiver // First consume any chars that have piled up at the receiver
while (_serial_gps->available() > 0) { while (_serial_gps->available() > 0) {
int c = _serial_gps->read(); int c = _serial_gps->read();
// DEBUG_MSG("%c", c); //DEBUG_MSG("%c", c);
isValid |= reader.encode(c); isValid |= reader.encode(c);
} }

View File

@@ -46,15 +46,18 @@ void updateDisplay(uint8_t *blackFrame = framePtr)
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl) EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
{ {
setGeometry(GEOMETRY_128_64); // FIXME - currently we lie and claim 128x64 because I'm not yet sure other resolutions will setGeometry(GEOMETRY_RAWMODE, EPD_WIDTH, EPD_HEIGHT);
// work ie GEOMETRY_RAWMODE // setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
} }
// FIXME quick hack to limit drawing to a very slow rate // FIXME quick hack to limit drawing to a very slow rate
uint32_t lastDrawMsec; uint32_t lastDrawMsec;
// Write the buffer to the display memory /**
void EInkDisplay::display(void) * Force a display update if we haven't drawn within the specified msecLimit
*/
bool EInkDisplay::forceDisplay(uint32_t msecLimit)
{ {
// No need to grab this lock because we are on our own SPI bus // No need to grab this lock because we are on our own SPI bus
// concurrency::LockGuard g(spiLock); // concurrency::LockGuard g(spiLock);
@@ -62,16 +65,16 @@ void EInkDisplay::display(void)
uint32_t now = millis(); uint32_t now = millis();
uint32_t sinceLast = now - lastDrawMsec; uint32_t sinceLast = now - lastDrawMsec;
if (framePtr && (sinceLast > 60 * 1000 || lastDrawMsec == 0)) { if (framePtr && (sinceLast > msecLimit || lastDrawMsec == 0)) {
lastDrawMsec = now; lastDrawMsec = now;
// FIXME - only draw bits have changed (use backbuf similar to the other displays) // FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK); // tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) { for (uint8_t y = 0; y < displayHeight; y++) {
for (uint8_t x = 0; x < SCREEN_WIDTH; x++) { for (uint8_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent // get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto b = buffer[x + (y / 8) * SCREEN_WIDTH]; auto b = buffer[x + (y / 8) * displayWidth];
auto isset = b & (1 << (y & 7)); auto isset = b & (1 << (y & 7));
frame.drawPixel(x, y, isset ? INK : PAPER); frame.drawPixel(x, y, isset ? INK : PAPER);
} }
@@ -83,11 +86,25 @@ void EInkDisplay::display(void)
updateDisplay(); // Send image to display and refresh updateDisplay(); // Send image to display and refresh
DEBUG_MSG("done\n"); DEBUG_MSG("done\n");
// Put screen to sleep to save power // Put screen to sleep to save power
ePaper.Sleep(); ePaper.Sleep();
return true;
} else {
// DEBUG_MSG("Skipping eink display\n");
return false;
} }
} }
// Write the buffer to the display memory
void EInkDisplay::display(void)
{
// We don't allow regular 'dumb' display() calls to draw on eink until we've shown
// at least one forceDisplay() keyframe. This prevents flashing when we should the critical
// bootscreen (that we want to look nice)
if (lastDrawMsec)
forceDisplay(slowUpdateMsec); // Show the first screen a few seconds after boot, then slower
}
// Send a command to the display (low level function) // Send a command to the display (low level function)
void EInkDisplay::sendCommand(uint8_t com) void EInkDisplay::sendCommand(uint8_t com)
{ {

View File

@@ -14,15 +14,26 @@
*/ */
class EInkDisplay : public OLEDDisplay class EInkDisplay : public OLEDDisplay
{ {
/// How often should we update the display
/// thereafter we do once per 5 minutes
uint32_t slowUpdateMsec = 5 * 60 * 1000;
public: public:
/* constructor /* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/ */
EInkDisplay(uint8_t address, int sda, int scl); EInkDisplay(uint8_t address, int sda, int scl);
// Write the buffer to the display memory // Write the buffer to the display memory (for eink we only do this occasionally)
virtual void display(void); virtual void display(void);
/**
* Force a display update if we haven't drawn within the specified msecLimit
*
* @return true if we did draw the screen
*/
bool forceDisplay(uint32_t msecLimit = 1000);
protected: protected:
// the header size of the buffer used, e.g. for the SPI command header // the header size of the buffer used, e.g. for the SPI command header
virtual int getBufferOffset(void) { return 0; } virtual int getBufferOffset(void) { return 0; }
@@ -33,3 +44,5 @@ class EInkDisplay : public OLEDDisplay
// Connect to the display // Connect to the display
virtual bool connect(); virtual bool connect();
}; };

View File

@@ -58,39 +58,73 @@ static char ourId[5];
static bool heartbeat = false; static bool heartbeat = false;
#endif #endif
// We used to use constants for this - now we pull from the device at startup
//#define SCREEN_WIDTH 128
//#define SCREEN_HEIGHT 64
static uint16_t displayWidth, displayHeight;
#define SCREEN_WIDTH displayWidth
#define SCREEN_HEIGHT displayHeight
#ifdef HAS_EINK
// The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16
#define FONT_MEDIUM ArialMT_Plain_24
#define FONT_LARGE ArialMT_Plain_24
#else
#define FONT_SMALL ArialMT_Plain_10
#define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24
#endif
#define fontHeight(font) ((font)[1] + 1) // height is position 1
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
// draw an xbm image. // draw an xbm image.
// Please note that everything that should be transitioned // Please note that everything that should be transitioned
// needs to be drawn relative to x and y // needs to be drawn relative to x and y
display->drawXbm(x + 32, y, icon_width, icon_height, (const uint8_t *)icon_bits);
display->setFont(ArialMT_Plain_16); // draw centered left to right and centered above the one line of app text
display->setTextAlignment(TEXT_ALIGN_CENTER); display->drawXbm(x + (SCREEN_WIDTH - icon_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - icon_height) / 2 + 2,
display->drawString(64 + x, SCREEN_HEIGHT - FONT_HEIGHT_16, "meshtastic.org"); icon_width, icon_height, (const uint8_t *)icon_bits);
display->setFont(ArialMT_Plain_10);
const char *region = xstr(HW_VERSION); display->setFont(FONT_MEDIUM);
if (*region && region[3] == '-') // Skip past 1.0- in the 1.0-EU865 string display->setTextAlignment(TEXT_ALIGN_LEFT);
region += 4; const char *title = "meshtastic.org";
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
display->setFont(FONT_SMALL);
const char *region = myRegion ? myRegion->name : NULL;
if (region)
display->drawString(x + 0, y + 0, region);
char buf[16]; char buf[16];
snprintf(buf, sizeof(buf), "%s", snprintf(buf, sizeof(buf), "%s",
xstr(APP_VERSION)); // Note: we don't bother printing region or now, it makes the string too long xstr(APP_VERSION)); // Note: we don't bother printing region or now, it makes the string too long
display->drawString(SCREEN_WIDTH - 20, 0, buf); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
screen->forceDisplay();
} }
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
display->setTextAlignment(TEXT_ALIGN_CENTER); display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_16); display->setFont(FONT_MEDIUM);
display->drawString(64 + x, y, "Bluetooth"); display->drawString(64 + x, y, "Bluetooth");
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
display->drawString(64 + x, FONT_HEIGHT + y + 2, "Enter this code"); display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Enter this code");
display->setFont(ArialMT_Plain_24); display->setFont(FONT_LARGE);
display->drawString(64 + x, 26 + y, btPIN); display->drawString(64 + x, 26 + y, btPIN);
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
char buf[30]; char buf[30];
const char *name = "Name: "; const char *name = "Name: ";
strcpy(buf, name); strcpy(buf, name);
@@ -112,10 +146,10 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
// with the third parameter you can define the width after which words will // with the third parameter you can define the width after which words will
// be wrapped. Currently only spaces and "-" are allowed for wrapping // be wrapped. Currently only spaces and "-" are allowed for wrapping
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_16); display->setFont(FONT_MEDIUM);
String sender = (node && node->has_user) ? node->user.short_name : "???"; String sender = (node && node->has_user) ? node->user.short_name : "???";
display->drawString(0 + x, 0 + y, sender); display->drawString(0 + x, 0 + y, sender);
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
// the max length of this buffer is much longer than we can possibly print // the max length of this buffer is much longer than we can possibly print
static char tempBuf[96]; static char tempBuf[96];
@@ -135,8 +169,8 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
int xo = x, yo = y; int xo = x, yo = y;
while (*f) { while (*f) {
display->drawString(xo, yo, *f); display->drawString(xo, yo, *f);
yo += FONT_HEIGHT; yo += FONT_HEIGHT_SMALL;
if (yo > SCREEN_HEIGHT - FONT_HEIGHT) { if (yo > SCREEN_HEIGHT - FONT_HEIGHT_SMALL) {
xo += SCREEN_WIDTH / 2; xo += SCREEN_WIDTH / 2;
yo = 0; yo = 0;
} }
@@ -162,14 +196,14 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
// 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_SMALL;
col = 0; col = 0;
} }
f++; f++;
} }
if (col != 0) { if (col != 0) {
// Include last incomplete line in our total. // Include last incomplete line in our total.
yo += FONT_HEIGHT; yo += FONT_HEIGHT_SMALL;
} }
return yo; return yo;
@@ -236,7 +270,7 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
display->drawFastImage(x + 24, y, 8, 8, imgSatellite); display->drawFastImage(x + 24, y, 8, 8, imgSatellite);
// Draw the number of satellites // Draw the number of satellites
sprintf(satsString, "%d", gps->getNumSatellites()); sprintf(satsString, "%lu", gps->getNumSatellites());
display->drawString(x + 34, y - 2, satsString); display->drawString(x + 34, y - 2, satsString);
} }
} }
@@ -476,7 +510,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex); NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex);
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
@@ -489,11 +523,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
uint32_t agoSecs = sinceLastSeen(node); uint32_t agoSecs = sinceLastSeen(node);
static char lastStr[20]; static char lastStr[20];
if (agoSecs < 120) // last 2 mins? if (agoSecs < 120) // last 2 mins?
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs); snprintf(lastStr, sizeof(lastStr), "%lu seconds ago", agoSecs);
else if (agoSecs < 120 * 60) // last 2 hrs else if (agoSecs < 120 * 60) // last 2 hrs
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60); snprintf(lastStr, sizeof(lastStr), "%lu minutes ago", agoSecs / 60);
else else
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60); snprintf(lastStr, sizeof(lastStr), "%lu hours ago", agoSecs / 60 / 60);
static char distStr[20]; static char distStr[20];
strcpy(distStr, "? km"); // might not have location data strcpy(distStr, "? km"); // might not have location data
@@ -531,7 +565,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
// direction to node is unknown so display question mark // direction to node is unknown so display question mark
// Debug info for gps lock errors // Debug info for gps lock errors
// DEBUG_MSG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node)); // DEBUG_MSG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
display->drawString(compassX - FONT_HEIGHT / 4, compassY - FONT_HEIGHT / 2, "?"); display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2); display->drawCircle(compassX, compassY, COMPASS_DIAM / 2);
// Must be after distStr is populated // Must be after distStr is populated
@@ -561,7 +595,8 @@ void _screen_header()
} }
#endif #endif
Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev) { Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev)
{
cmdQueue.setReader(this); cmdQueue.setReader(this);
} }
@@ -596,6 +631,10 @@ void Screen::setup()
// Initialising the UI will init the display too. // Initialising the UI will init the display too.
ui.init(); ui.init();
displayWidth = dispdev.width();
displayHeight = dispdev.height();
ui.setTimePerTransition(300); // msecs ui.setTimePerTransition(300); // msecs
ui.setIndicatorPosition(BOTTOM); ui.setIndicatorPosition(BOTTOM);
// Defines where the first frame is located in the bar. // Defines where the first frame is located in the bar.
@@ -645,6 +684,14 @@ void Screen::setup()
nodeStatusObserver.observe(&nodeStatus->onNewStatus); nodeStatusObserver.observe(&nodeStatus->onNewStatus);
} }
void Screen::forceDisplay()
{
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
#ifdef HAS_EINK
dispdev.forceDisplay();
#endif
}
int32_t Screen::runOnce() int32_t Screen::runOnce()
{ {
// If we don't have a screen, don't ever spend any CPU for us. // If we don't have a screen, don't ever spend any CPU for us.
@@ -655,7 +702,8 @@ int32_t Screen::runOnce()
// Show boot screen for first 3 seconds, then switch to normal operation. // Show boot screen for first 3 seconds, then switch to normal operation.
static bool showingBootScreen = true; static bool showingBootScreen = true;
if (showingBootScreen && (millis() > 3000)) { if (showingBootScreen && (millis() > 5000)) {
DEBUG_MSG("Done with boot screen...\n");
stopBootScreen(); stopBootScreen();
showingBootScreen = false; showingBootScreen = false;
} }
@@ -701,6 +749,10 @@ int32_t Screen::runOnce()
return 0; return 0;
} }
// this must be before the frameState == FIXED check, because we always
// want to draw at least one FIXED frame before doing forceDisplay
ui.update();
// Switch to a low framerate (to save CPU) when we are not in transition // Switch to a low framerate (to save CPU) when we are not in transition
// but we should only call setTargetFPS when framestate changes, because // but we should only call setTargetFPS when framestate changes, because
// otherwise that breaks animations. // otherwise that breaks animations.
@@ -709,6 +761,7 @@ int32_t Screen::runOnce()
DEBUG_MSG("Setting idle framerate\n"); DEBUG_MSG("Setting idle framerate\n");
targetFramerate = IDLE_FRAMERATE; targetFramerate = IDLE_FRAMERATE;
ui.setTargetFPS(targetFramerate); ui.setTargetFPS(targetFramerate);
forceDisplay();
} }
// While showing the bootscreen or Bluetooth pair screen all of our // While showing the bootscreen or Bluetooth pair screen all of our
@@ -717,8 +770,6 @@ int32_t Screen::runOnce()
// standard screen loop handling here // standard screen loop handling here
} }
ui.update();
// DEBUG_MSG("want fps %d, fixed=%d\n", targetFramerate, // DEBUG_MSG("want fps %d, fixed=%d\n", targetFramerate,
// ui.getUiState()->frameState); If we are scrolling we need to be called // ui.getUiState()->frameState); If we are scrolling we need to be called
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice // soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
@@ -785,6 +836,8 @@ void Screen::setFrames()
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
// just changed) // just changed)
setFastFramerate(); // Draw ASAP
} }
void Screen::handleStartBluetoothPinScreen(uint32_t pin) void Screen::handleStartBluetoothPinScreen(uint32_t pin)
@@ -794,16 +847,17 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
static FrameCallback btFrames[] = {drawFrameBluetooth}; static FrameCallback btFrames[] = {drawFrameBluetooth};
snprintf(btPIN, sizeof(btPIN), "%06u", pin); snprintf(btPIN, sizeof(btPIN), "%06lu", pin);
ui.disableAllIndicators(); ui.disableAllIndicators();
ui.setFrames(btFrames, 1); ui.setFrames(btFrames, 1);
setFastFramerate();
} }
void Screen::handlePrint(const char *text) void Screen::handlePrint(const char *text)
{ {
DEBUG_MSG("Screen: %s", text); DEBUG_MSG("Screen: %s", text);
if (!useDisplay) if (!useDisplay || !showingNormalScreen)
return; return;
dispdev.print(text); dispdev.print(text);
@@ -814,22 +868,27 @@ void Screen::handleOnPress()
// If screen was off, just wake it, otherwise advance to next frame // If screen was off, just wake it, otherwise advance to next frame
// If we are in a transition, the press must have bounced, drop it. // If we are in a transition, the press must have bounced, drop it.
if (ui.getUiState()->frameState == FIXED) { if (ui.getUiState()->frameState == FIXED) {
setInterval(0); // redraw ASAP
ui.nextFrame(); ui.nextFrame();
DEBUG_MSG("Setting fast framerate\n"); setFastFramerate();
// We are about to start a transition so speed up fps
targetFramerate = TRANSITION_FRAMERATE;
ui.setTargetFPS(targetFramerate);
} }
} }
void Screen::setFastFramerate()
{
DEBUG_MSG("Setting fast framerate\n");
// We are about to start a transition so speed up fps
targetFramerate = TRANSITION_FRAMERATE;
ui.setTargetFPS(targetFramerate);
setInterval(0); // redraw ASAP
}
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
displayedNodeNum = 0; // Not currently showing a node pane displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
@@ -851,13 +910,13 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus); drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
// Draw the channel name // Draw the channel name
display->drawString(x, y + FONT_HEIGHT, channelStr); display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
// Draw our hardware ID to assist with bluetooth pairing // Draw our hardware ID to assist with bluetooth pairing
display->drawFastImage(x + SCREEN_WIDTH - (10) - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT, 8, 8, imgInfo); display->drawFastImage(x + SCREEN_WIDTH - (10) - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT, ourId); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId);
// Draw any log messages // Draw any log messages
display->drawLogBuffer(x, y + (FONT_HEIGHT * 2)); display->drawLogBuffer(x, y + (FONT_HEIGHT_SMALL * 2));
/* Display a heartbeat pixel that blinks every time the frame is redrawn */ /* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS #ifdef SHOW_REDRAWS
@@ -876,7 +935,7 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
displayedNodeNum = 0; // Not currently showing a node pane displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
@@ -907,86 +966,90 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
if (WiFi.status() == WL_CONNECTED) { if (WiFi.status() == WL_CONNECTED) {
if (radioConfig.preferences.wifi_ap_mode) { if (radioConfig.preferences.wifi_ap_mode) {
display->drawString(x, y + FONT_HEIGHT * 1, "IP: " + String(WiFi.softAPIP().toString().c_str())); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str()));
} else { } else {
display->drawString(x, y + FONT_HEIGHT * 1, "IP: " + String(WiFi.localIP().toString().c_str())); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str()));
} }
} else if (WiFi.status() == WL_NO_SSID_AVAIL) { } else if (WiFi.status() == WL_NO_SSID_AVAIL) {
display->drawString(x, y + FONT_HEIGHT * 1, "SSID Not Found"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found");
} else if (WiFi.status() == WL_CONNECTION_LOST) { } else if (WiFi.status() == WL_CONNECTION_LOST) {
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Lost"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Lost");
} else if (WiFi.status() == WL_CONNECT_FAILED) { } else if (WiFi.status() == WL_CONNECT_FAILED) {
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Failed"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
//} else if (WiFi.status() == WL_DISCONNECTED) { //} else if (WiFi.status() == WL_DISCONNECTED) {
// display->drawString(x, y + FONT_HEIGHT * 1, "Disconnected"); // display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disconnected");
} else if (WiFi.status() == WL_IDLE_STATUS) { } else if (WiFi.status() == WL_IDLE_STATUS) {
display->drawString(x, y + FONT_HEIGHT * 1, "Idle ... Reconnecting"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting");
} else { } else {
// Codes: // Codes:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code
if (getWifiDisconnectReason() == 2) { if (getWifiDisconnectReason() == 2) {
display->drawString(x, y + FONT_HEIGHT * 1, "Authentication Invalid"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Authentication Invalid");
} else if (getWifiDisconnectReason() == 3) { } else if (getWifiDisconnectReason() == 3) {
display->drawString(x, y + FONT_HEIGHT * 1, "De-authenticated"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "De-authenticated");
} else if (getWifiDisconnectReason() == 4) { } else if (getWifiDisconnectReason() == 4) {
display->drawString(x, y + FONT_HEIGHT * 1, "Disassociated Expired"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disassociated Expired");
} else if (getWifiDisconnectReason() == 5) { } else if (getWifiDisconnectReason() == 5) {
display->drawString(x, y + FONT_HEIGHT * 1, "AP - Too Many Clients"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP - Too Many Clients");
} else if (getWifiDisconnectReason() == 6) { } else if (getWifiDisconnectReason() == 6) {
display->drawString(x, y + FONT_HEIGHT * 1, "NOT_AUTHED"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "NOT_AUTHED");
} else if (getWifiDisconnectReason() == 7) { } else if (getWifiDisconnectReason() == 7) {
display->drawString(x, y + FONT_HEIGHT * 1, "NOT_ASSOCED"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "NOT_ASSOCED");
} else if (getWifiDisconnectReason() == 8) { } else if (getWifiDisconnectReason() == 8) {
display->drawString(x, y + FONT_HEIGHT * 1, "Disassociated"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disassociated");
} else if (getWifiDisconnectReason() == 9) { } else if (getWifiDisconnectReason() == 9) {
display->drawString(x, y + FONT_HEIGHT * 1, "ASSOC_NOT_AUTHED"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "ASSOC_NOT_AUTHED");
} else if (getWifiDisconnectReason() == 10) { } else if (getWifiDisconnectReason() == 10) {
display->drawString(x, y + FONT_HEIGHT * 1, "DISASSOC_PWRCAP_BAD"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "DISASSOC_PWRCAP_BAD");
} else if (getWifiDisconnectReason() == 11) { } else if (getWifiDisconnectReason() == 11) {
display->drawString(x, y + FONT_HEIGHT * 1, "DISASSOC_SUPCHAN_BAD"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "DISASSOC_SUPCHAN_BAD");
} else if (getWifiDisconnectReason() == 13) { } else if (getWifiDisconnectReason() == 13) {
display->drawString(x, y + FONT_HEIGHT * 1, "IE_INVALID"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IE_INVALID");
} else if (getWifiDisconnectReason() == 14) { } else if (getWifiDisconnectReason() == 14) {
display->drawString(x, y + FONT_HEIGHT * 1, "MIC_FAILURE"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "MIC_FAILURE");
} else if (getWifiDisconnectReason() == 15) { } else if (getWifiDisconnectReason() == 15) {
display->drawString(x, y + FONT_HEIGHT * 1, "AP Handshake Timeout"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP Handshake Timeout");
} else if (getWifiDisconnectReason() == 16) { } else if (getWifiDisconnectReason() == 16) {
display->drawString(x, y + FONT_HEIGHT * 1, "GROUP_KEY_UPDATE_TIMEOUT"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "GROUP_KEY_UPDATE_TIMEOUT");
} else if (getWifiDisconnectReason() == 17) { } else if (getWifiDisconnectReason() == 17) {
display->drawString(x, y + FONT_HEIGHT * 1, "IE_IN_4WAY_DIFFERS"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IE_IN_4WAY_DIFFERS");
} else if (getWifiDisconnectReason() == 18) { } else if (getWifiDisconnectReason() == 18) {
display->drawString(x, y + FONT_HEIGHT * 1, "Invalid Group Cipher"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Invalid Group Cipher");
} else if (getWifiDisconnectReason() == 19) { } else if (getWifiDisconnectReason() == 19) {
display->drawString(x, y + FONT_HEIGHT * 1, "Invalid Pairwise Cipher"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Invalid Pairwise Cipher");
} else if (getWifiDisconnectReason() == 20) { } else if (getWifiDisconnectReason() == 20) {
display->drawString(x, y + FONT_HEIGHT * 1, "AKMP_INVALID"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AKMP_INVALID");
} else if (getWifiDisconnectReason() == 21) { } else if (getWifiDisconnectReason() == 21) {
display->drawString(x, y + FONT_HEIGHT * 1, "UNSUPP_RSN_IE_VERSION"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "UNSUPP_RSN_IE_VERSION");
} else if (getWifiDisconnectReason() == 22) { } else if (getWifiDisconnectReason() == 22) {
display->drawString(x, y + FONT_HEIGHT * 1, "INVALID_RSN_IE_CAP"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "INVALID_RSN_IE_CAP");
} else if (getWifiDisconnectReason() == 23) { } else if (getWifiDisconnectReason() == 23) {
display->drawString(x, y + FONT_HEIGHT * 1, "802_1X_AUTH_FAILED"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "802_1X_AUTH_FAILED");
} else if (getWifiDisconnectReason() == 24) { } else if (getWifiDisconnectReason() == 24) {
display->drawString(x, y + FONT_HEIGHT * 1, "CIPHER_SUITE_REJECTED"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "CIPHER_SUITE_REJECTED");
} else if (getWifiDisconnectReason() == 200) { } else if (getWifiDisconnectReason() == 200) {
display->drawString(x, y + FONT_HEIGHT * 1, "BEACON_TIMEOUT"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "BEACON_TIMEOUT");
} else if (getWifiDisconnectReason() == 201) { } else if (getWifiDisconnectReason() == 201) {
display->drawString(x, y + FONT_HEIGHT * 1, "AP Not Found"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP Not Found");
} else if (getWifiDisconnectReason() == 202) { } else if (getWifiDisconnectReason() == 202) {
display->drawString(x, y + FONT_HEIGHT * 1, "AUTH_FAIL"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AUTH_FAIL");
} else if (getWifiDisconnectReason() == 203) { } else if (getWifiDisconnectReason() == 203) {
display->drawString(x, y + FONT_HEIGHT * 1, "ASSOC_FAIL"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "ASSOC_FAIL");
} else if (getWifiDisconnectReason() == 204) { } else if (getWifiDisconnectReason() == 204) {
display->drawString(x, y + FONT_HEIGHT * 1, "HANDSHAKE_TIMEOUT"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "HANDSHAKE_TIMEOUT");
} else if (getWifiDisconnectReason() == 205) { } else if (getWifiDisconnectReason() == 205) {
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Failed"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
} else { } else {
display->drawString(x, y + FONT_HEIGHT * 1, "Unknown Status"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Unknown Status");
} }
} }
display->drawString(x, y + FONT_HEIGHT * 2, "SSID: " + String(wifiName)); if ((millis() / 1000) % 2) {
display->drawString(x, y + FONT_HEIGHT * 3, "PWD: " + String(wifiPsw)); display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
} else {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "PWD: " + String(wifiPsw));
}
display->drawString(x, y + FONT_HEIGHT_SMALL * 3, "http://meshtastic.local");
/* Display a heartbeat pixel that blinks every time the frame is redrawn */ /* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS #ifdef SHOW_REDRAWS
@@ -1001,7 +1064,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
{ {
displayedNodeNum = 0; // Not currently showing a node pane displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(ArialMT_Plain_10); display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
@@ -1035,15 +1098,21 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
minutes %= 60; minutes %= 60;
hours %= 24; hours %= 24;
display->drawString(x, y + FONT_HEIGHT * 1, display->drawString(x, y + FONT_HEIGHT_SMALL * 1,
String(days) + "d " + (hours < 10 ? "0" : "") + String(hours) + ":" + (minutes < 10 ? "0" : "") + String(days) + "d " + (hours < 10 ? "0" : "") + String(hours) + ":" + (minutes < 10 ? "0" : "") +
String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds)); String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds));
#ifndef NO_ESP32
// Show CPU Frequency.
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("CPU " + String(getCpuFrequencyMhz()) + "MHz"),
y + FONT_HEIGHT_SMALL * 1, "CPU " + String(getCpuFrequencyMhz()) + "MHz");
#endif
// Line 3 // Line 3
drawGPSAltitude(display, x, y + FONT_HEIGHT * 2, gpsStatus); drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
// Line 4 // Line 4
drawGPScoordinates(display, x, y + FONT_HEIGHT * 3, gpsStatus); drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
/* Display a heartbeat pixel that blinks every time the frame is redrawn */ /* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS #ifdef SHOW_REDRAWS
@@ -1072,10 +1141,8 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
// DEBUG_MSG("Screen got status update %d\n", arg->getStatusType()); // DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
switch (arg->getStatusType()) { switch (arg->getStatusType()) {
case STATUS_TYPE_NODE: case STATUS_TYPE_NODE:
if (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) { if (showingNormalScreen && (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal())) {
setFrames(); // Regen the list of screens setFrames(); // Regen the list of screens
prevFrame = -1; // Force a GUI update
setInterval(0); // Update the screen right away
} }
nodeDB.updateGUI = false; nodeDB.updateGUI = false;
nodeDB.updateTextMessage = false; nodeDB.updateTextMessage = false;

View File

@@ -180,6 +180,9 @@ class Screen : public concurrency::OSThread
int handleStatusUpdate(const meshtastic::Status *arg); int handleStatusUpdate(const meshtastic::Status *arg);
/// Used to force (super slow) eink displays to draw critical frames
void forceDisplay();
protected: protected:
/// Updates the UI. /// Updates the UI.
// //
@@ -202,7 +205,7 @@ class Screen : public concurrency::OSThread
return true; // claim success if our display is not in use return true; // claim success if our display is not in use
else { else {
bool success = cmdQueue.enqueue(cmd, 0); bool success = cmdQueue.enqueue(cmd, 0);
setInterval(0); // handle ASAP enabled = true; // handle ASAP (we are the registered reader for cmdQueue, but might have been disabled)
return success; return success;
} }
} }
@@ -216,6 +219,9 @@ class Screen : public concurrency::OSThread
/// Rebuilds our list of frames (screens) to default ones. /// Rebuilds our list of frames (screens) to default ones.
void setFrames(); void setFrames();
/// Try to start drawing ASAP
void setFastFramerate();
/// Called when debug screen is to be drawn, calls through to debugInfo.drawFrame. /// 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); static void drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);

View File

@@ -11,8 +11,7 @@ static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl) TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl)
{ {
setGeometry(GEOMETRY_128_64); // FIXME - currently we lie and claim 128x64 because I'm not yet sure other resolutions will setGeometry(GEOMETRY_RAWMODE, 160, 80);
// work ie GEOMETRY_RAWMODE
} }
// Write the buffer to the display memory // Write the buffer to the display memory
@@ -22,11 +21,11 @@ void TFTDisplay::display(void)
// FIXME - only draw bits have changed (use backbuf similar to the other displays) // FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK); // tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) { for (uint8_t y = 0; y < displayHeight; y++) {
for (uint8_t x = 0; x < SCREEN_WIDTH; x++) { for (uint8_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent // get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto b = buffer[x + (y / 8) * SCREEN_WIDTH]; auto b = buffer[x + (y / 8) * displayWidth];
auto isset = b & (1 << (y & 7)); auto isset = b & (1 << (y & 7));
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK); tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
} }

View File

@@ -2,11 +2,7 @@
#include "fonts.h" #include "fonts.h"
#define FONT_HEIGHT 14 // actually 13 for "Arial 10" but want a little extra space
#define FONT_HEIGHT_16 (ArialMT_Plain_16[1] + 1)
// This means the *visible* area (sh1106 can address 132, but shows 128 for example) // This means the *visible* area (sh1106 can address 132, but shows 128 for example)
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define TRANSITION_FRAMERATE 30 // fps #define TRANSITION_FRAMERATE 30 // fps
#define IDLE_FRAMERATE 1 // in fps #define IDLE_FRAMERATE 1 // in fps
#define COMPASS_DIAM 44 #define COMPASS_DIAM 44

View File

@@ -128,31 +128,13 @@ class PowerFSMThread : public OSThread
/// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake /// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake
/// cpu for serial rx - FIXME) /// cpu for serial rx - FIXME)
canSleep = (powerFSM.getState() != &statePOWER); auto state = powerFSM.getState();
canSleep = (state != &statePOWER) && (state != &stateSERIAL);
return 10; return 10;
} }
}; };
static Periodic *ledPeriodic;
static OSThread *powerFSMthread;
// Prepare for button presses
#ifdef BUTTON_PIN
OneButton userButton;
#endif
#ifdef BUTTON_PIN_ALT
OneButton userButtonAlt;
#endif
void userButtonPressed()
{
powerFSM.trigger(EVENT_PRESS);
}
void userButtonPressedLong()
{
screen->adjustBrightness();
}
/** /**
* Watch a GPIO and if we get an IRQ, wake the main thread. * Watch a GPIO and if we get an IRQ, wake the main thread.
* Use to add wake on button press * Use to add wake on button press
@@ -168,6 +150,65 @@ void wakeOnIrq(int irq, int mode)
FALLING); FALLING);
} }
class ButtonThread : public OSThread
{
// Prepare for button presses
#ifdef BUTTON_PIN
OneButton userButton;
#endif
#ifdef BUTTON_PIN_ALT
OneButton userButtonAlt;
#endif
public:
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
ButtonThread() : OSThread("Button")
{
#ifdef BUTTON_PIN
userButton = OneButton(BUTTON_PIN, true, true);
userButton.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
wakeOnIrq(BUTTON_PIN, FALLING);
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
userButtonAlt.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
wakeOnIrq(BUTTON_PIN_ALT, FALLING);
#endif
}
protected:
/// If the button is pressed we suppress CPU sleep until release
int32_t runOnce()
{
canSleep = true; // Assume we should not keep the board awake
#ifdef BUTTON_PIN
userButton.tick();
canSleep &= userButton.isIdle();
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt.tick();
canSleep &= userButton.isIdle();
#endif
// if(!canSleep) DEBUG_MSG("Supressing sleep!\n");
return 5;
}
private:
static void userButtonPressed()
{
// DEBUG_MSG("press!\n");
powerFSM.trigger(EVENT_PRESS);
}
static void userButtonPressedLong() { screen->adjustBrightness(); }
};
static Periodic *ledPeriodic;
static OSThread *powerFSMthread, *buttonThread;
RadioInterface *rIf = NULL; RadioInterface *rIf = NULL;
void setup() void setup()
@@ -210,18 +251,7 @@ void setup()
#endif #endif
// Buttons & LED // Buttons & LED
#ifdef BUTTON_PIN buttonThread = new ButtonThread();
userButton = OneButton(BUTTON_PIN, true, true);
userButton.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
wakeOnIrq(BUTTON_PIN, FALLING);
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
userButtonAlt.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
wakeOnIrq(BUTTON_PIN_ALT, FALLING);
#endif
#ifdef LED_PIN #ifdef LED_PIN
pinMode(LED_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, 1 ^ LED_INVERTED); // turn on for now digitalWrite(LED_PIN, 1 ^ LED_INVERTED); // turn on for now
@@ -260,14 +290,6 @@ void setup()
// Initialize the screen first so we can show the logo while we start up everything else. // Initialize the screen first so we can show the logo while we start up everything else.
screen = new graphics::Screen(SSD1306_ADDRESS); screen = new graphics::Screen(SSD1306_ADDRESS);
#if defined(ST7735_CS) || defined(HAS_EINK)
screen->setup();
#else
if (ssd1306_found)
screen->setup();
#endif
screen->print("Started...\n");
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time) readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
@@ -308,6 +330,17 @@ void setup()
service.init(); service.init();
// Don't call screen setup until after nodedb is setup (because we need
// the current region name)
#if defined(ST7735_CS) || defined(HAS_EINK)
screen->setup();
#else
if (ssd1306_found)
screen->setup();
#endif
screen->print("Started...\n");
// We have now loaded our saved preferences from flash // We have now loaded our saved preferences from flash
// ONCE we will factory reset the GPS for bug #327 // ONCE we will factory reset the GPS for bug #327
@@ -361,6 +394,7 @@ void setup()
// Initialize Wifi // Initialize Wifi
initWifi(); initWifi();
if (!rIf) if (!rIf)
recordCriticalError(ErrNoRadio); recordCriticalError(ErrNoRadio);
@@ -410,13 +444,6 @@ void loop()
esp32Loop(); esp32Loop();
#endif #endif
#ifdef BUTTON_PIN
userButton.tick();
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt.tick();
#endif
// For debugging // For debugging
// if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving(); // if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving();
@@ -437,9 +464,9 @@ void loop()
/* if (mainController.nextThread && delayMsec) /* if (mainController.nextThread && delayMsec)
DEBUG_MSG("Next %s in %ld\n", mainController.nextThread->ThreadName.c_str(), DEBUG_MSG("Next %s in %ld\n", mainController.nextThread->ThreadName.c_str(),
mainController.nextThread->tillRun(millis())); mainController.nextThread->tillRun(millis())); */
*/
// We want to sleep as long as possible here - because it saves power // We want to sleep as long as possible here - because it saves power
mainDelay.delay(delayMsec); mainDelay.delay(delayMsec);
// if (didWake) DEBUG_MSG("wake!\n");
} }

View File

@@ -16,4 +16,7 @@ struct RegionInfo {
const char *name; // EU433 etc const char *name; // EU433 etc
}; };
extern const RegionInfo regions[]; extern const RegionInfo regions[];
extern const RegionInfo *myRegion;
extern void initRegion();

View File

@@ -147,6 +147,7 @@ bool NodeDB::resetRadioConfig()
radioConfig.preferences.wait_bluetooth_secs = 30; radioConfig.preferences.wait_bluetooth_secs = 30;
radioConfig.preferences.position_broadcast_secs = 6 * 60; radioConfig.preferences.position_broadcast_secs = 6 * 60;
radioConfig.preferences.ls_secs = 60; radioConfig.preferences.ls_secs = 60;
radioConfig.preferences.region = RegionCode_TW;
} }
return didFactoryReset; return didFactoryReset;
@@ -244,6 +245,9 @@ void NodeDB::init()
} }
} }
// Update the global myRegion
initRegion();
strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version)); strncpy(myNodeInfo.firmware_version, optstr(APP_VERSION), sizeof(myNodeInfo.firmware_version));
strncpy(myNodeInfo.hw_model, HW_VENDOR, sizeof(myNodeInfo.hw_model)); strncpy(myNodeInfo.hw_model, HW_VENDOR, sizeof(myNodeInfo.hw_model));

View File

@@ -144,11 +144,18 @@ const char *getChannelName();
PREF_GET(send_owner_interval, 4) PREF_GET(send_owner_interval, 4)
PREF_GET(position_broadcast_secs, 15 * 60) PREF_GET(position_broadcast_secs, 15 * 60)
PREF_GET(wait_bluetooth_secs, 120)
// Each time we wake into the DARK state allow 1 minute to send and receive BLE packets to the phone
PREF_GET(wait_bluetooth_secs, 60)
PREF_GET(screen_on_secs, 60) PREF_GET(screen_on_secs, 60)
PREF_GET(mesh_sds_timeout_secs, 2 * 60 * 60) PREF_GET(mesh_sds_timeout_secs, 2 * 60 * 60)
PREF_GET(phone_sds_timeout_sec, 2 * 60 * 60) PREF_GET(phone_sds_timeout_sec, 2 * 60 * 60)
PREF_GET(sds_secs, 365 * 24 * 60 * 60) PREF_GET(sds_secs, 365 * 24 * 60 * 60)
PREF_GET(ls_secs, 60 * 60)
// We default to sleeping (with bluetooth off for 5 minutes at a time). This seems to be a good tradeoff between
// latency for the user sending messages and power savings because of not having to run (expensive) ESP32 bluetooth
PREF_GET(ls_secs, 5 * 60)
PREF_GET(phone_timeout_secs, 15 * 60) PREF_GET(phone_timeout_secs, 15 * 60)
PREF_GET(min_wake_secs, 10) PREF_GET(min_wake_secs, 10)

View File

@@ -121,7 +121,14 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
case STATE_SEND_RADIO: case STATE_SEND_RADIO:
fromRadioScratch.which_variant = FromRadio_radio_tag; fromRadioScratch.which_variant = FromRadio_radio_tag;
fromRadioScratch.variant.radio = radioConfig; fromRadioScratch.variant.radio = radioConfig;
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
// using to the app (so that even old phone apps work with new device loads).
fromRadioScratch.variant.radio.preferences.ls_secs = getPref_ls_secs();
state = STATE_SEND_NODEINFO; state = STATE_SEND_NODEINFO;
break; break;

View File

@@ -26,7 +26,20 @@ const RegionInfo regions[] = {
RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last
}; };
static const RegionInfo *myRegion; const RegionInfo *myRegion;
void initRegion()
{
if (!myRegion) {
const RegionInfo *r = regions;
for (; r->code != RegionCode_Unset && r->code != radioConfig.preferences.region; r++)
;
myRegion = r;
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name);
myNodeInfo.num_channels = myRegion->numChannels; // Tell our android app how many channels we have
}
}
/** /**
* ## LoRaWAN for North America * ## LoRaWAN for North America
@@ -91,20 +104,10 @@ void printPacket(const char *prefix, const MeshPacket *p)
DEBUG_MSG(")\n"); DEBUG_MSG(")\n");
} }
RadioInterface::RadioInterface() RadioInterface::RadioInterface()
{ {
assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
if (!myRegion) {
const RegionInfo *r = regions;
for (; r->code != RegionCode_Unset && r->code != radioConfig.preferences.region; r++)
;
myRegion = r;
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name);
myNodeInfo.num_channels = myRegion->numChannels; // Tell our android app how many channels we have
}
// Can't print strings this early - serial not setup yet // Can't print strings this early - serial not setup yet
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name); // DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
} }
@@ -120,7 +123,7 @@ bool RadioInterface::init()
// we now expect interfaces to operate in promiscous mode // we now expect interfaces to operate in promiscous mode
// radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor // radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor
// time. // time.
return true; return true;
} }

View File

@@ -82,8 +82,8 @@ bool SX1262Interface::reconfigure()
assert(err == ERR_NONE); assert(err == ERR_NONE);
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now... // Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
// err = lora.setRxGain(true); err = lora.setRxGain(true);
// assert(err == ERR_NONE); assert(err == ERR_NONE);
err = lora.setSyncWord(syncWord); err = lora.setSyncWord(syncWord);
assert(err == ERR_NONE); assert(err == ERR_NONE);

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,11 @@
#pragma once #pragma once
#include "PhoneAPI.h"
#include <Arduino.h> #include <Arduino.h>
#include <functional> #include <functional>
void initWebServer(); void initWebServer();
void createSSLCert();
void handleNotFound(); void handleNotFound();
@@ -15,8 +17,21 @@ void notifyWebUI();
void handleHotspot(); void handleHotspot();
void handleStyleCSS(); void handleStyleCSS();
void handleRoot(); void handleRoot();
void handleScriptsScriptJS(); void handleScriptsScriptJS();
void handleJSONChatHistoryDummy(); void handleJSONChatHistoryDummy();
class HttpAPI : public PhoneAPI
{
public:
// Nothing here yet
private:
// Nothing here yet
protected:
// Nothing here yet
};

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
#include "meshwifi/meshhttp.h" #include "meshwifi/meshhttp.h"
#include "target_specific.h" #include "target_specific.h"
#include <DNSServer.h> #include <DNSServer.h>
#include <ESPmDNS.h>
#include <WiFi.h> #include <WiFi.h>
static void WiFiEvent(WiFiEvent_t event); static void WiFiEvent(WiFiEvent_t event);
@@ -17,8 +18,8 @@ static WiFiServerPort *apiPort;
uint8_t wifiDisconnectReason = 0; uint8_t wifiDisconnectReason = 0;
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier // Stores our hostname
static char ourHost[16]; char ourHost[16];
bool isWifiAvailable() bool isWifiAvailable()
{ {
@@ -29,9 +30,6 @@ bool isWifiAvailable()
// strcpy(radioConfig.preferences.wifi_password, ""); // strcpy(radioConfig.preferences.wifi_password, "");
if (*wifiName && *wifiPsw) { if (*wifiName && *wifiPsw) {
// Once every 10 seconds, try to reconnect.
return 1; return 1;
} else { } else {
return 0; return 0;
@@ -64,6 +62,8 @@ void initWifi()
return; return;
} }
createSSLCert();
if (radioConfig.has_preferences) { if (radioConfig.has_preferences) {
const char *wifiName = radioConfig.preferences.wifi_ssid; const char *wifiName = radioConfig.preferences.wifi_ssid;
const char *wifiPsw = radioConfig.preferences.wifi_password; const char *wifiPsw = radioConfig.preferences.wifi_password;
@@ -117,12 +117,23 @@ void initWifi()
} }
} }
} }
if (!MDNS.begin( "Meshtastic" )) {
DEBUG_MSG("Error setting up MDNS responder!\n");
while (1) {
delay(1000);
}
}
DEBUG_MSG("mDNS responder started\n");
DEBUG_MSG("mDNS Host: Meshtastic.local\n");
MDNS.addService("http", "tcp", 80);
MDNS.addService("https", "tcp", 443);
} else } else
DEBUG_MSG("Not using WIFI\n"); DEBUG_MSG("Not using WIFI\n");
} }
static void initApiServer() static void initApiServer()
{ {
// Start API server on port 4403 // Start API server on port 4403

View File

@@ -239,7 +239,7 @@ External serial flash WP25R1635FZUIL0
#define PIN_SPI_SCK (0 + 19) #define PIN_SPI_SCK (0 + 19)
// To debug via the segger JLINK console rather than the CDC-ACM serial device // To debug via the segger JLINK console rather than the CDC-ACM serial device
#define USE_SEGGER // #define USE_SEGGER
#ifdef __cplusplus #ifdef __cplusplus
} }