mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-23 19:20:41 +00:00
Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82fe55471d | ||
|
|
60d90c4533 | ||
|
|
9145945efa | ||
|
|
7b09fbe049 | ||
|
|
a90bab5455 | ||
|
|
3d9cc8a056 | ||
|
|
ff885ef215 | ||
|
|
eb4286b560 | ||
|
|
9c90de0f6f | ||
|
|
d7a1cef046 | ||
|
|
6a359e2124 | ||
|
|
ca75dcd64d | ||
|
|
aba05ba5ce | ||
|
|
99882a675b | ||
|
|
9c9347df23 | ||
|
|
b66856c53f | ||
|
|
285069703c | ||
|
|
d91ab5480f | ||
|
|
e3b74ece74 | ||
|
|
66557241f3 | ||
|
|
3c09c3e520 | ||
|
|
781077e799 | ||
|
|
22946b5e51 | ||
|
|
c0307cbcb0 | ||
|
|
6b568ab2fb | ||
|
|
67bad9a689 | ||
|
|
559a790286 | ||
|
|
08e5bd728b | ||
|
|
0cfeeba2e2 | ||
|
|
5007624ba5 | ||
|
|
bba4677915 | ||
|
|
ac969cdb26 | ||
|
|
1c3eff0ee5 | ||
|
|
cba9546a4d | ||
|
|
ceae60cf13 | ||
|
|
3de1607cea | ||
|
|
029b2f3139 | ||
|
|
ab6c97bfef | ||
|
|
a61b15e861 | ||
|
|
8c7aa07c70 | ||
|
|
6a402b13fa | ||
|
|
c30b570e16 | ||
|
|
9b25818a50 | ||
|
|
5311e44660 | ||
|
|
55dafcbecb | ||
|
|
178958c165 | ||
|
|
d7cf7e2eb4 | ||
|
|
fce8c16d52 | ||
|
|
b690868bb1 | ||
|
|
dec88a368b | ||
|
|
17394d8c1c | ||
|
|
a7da7cd32e | ||
|
|
f37dc9c776 | ||
|
|
d6658dbb2e | ||
|
|
05531b2684 | ||
|
|
8b1fb39ce1 | ||
|
|
da46d4ca0e | ||
|
|
047141eb34 | ||
|
|
cb1053850d | ||
|
|
7652331e8c | ||
|
|
12bf3795ea | ||
|
|
7f45184d90 | ||
|
|
829763af2c | ||
|
|
75806ee666 | ||
|
|
91ec29db03 | ||
|
|
d191b12801 | ||
|
|
e0d6456618 | ||
|
|
70eda2ee06 | ||
|
|
7c4eb3eddd | ||
|
|
91b4cadb1b | ||
|
|
a23f327461 |
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -23,4 +23,4 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
pip install -U adafruit-nrfutil
|
pip install -U adafruit-nrfutil
|
||||||
- name: Build
|
- name: Build
|
||||||
run: platformio run -e tbeam -e heltec -e nrf52840dk -e rak815
|
run: platformio run -e tbeam -e heltec -e lora-relay-v1
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -17,3 +17,5 @@ Thumbs.db
|
|||||||
.cproject
|
.cproject
|
||||||
.idea/*
|
.idea/*
|
||||||
.vagrant
|
.vagrant
|
||||||
|
|
||||||
|
flash.uf2
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ We currently support three models of radios.
|
|||||||
- 3D printable cases
|
- 3D printable cases
|
||||||
- [T-Beam V0](https://www.thingiverse.com/thing:3773717)
|
- [T-Beam V0](https://www.thingiverse.com/thing:3773717)
|
||||||
- [T-Beam V1](https://www.thingiverse.com/thing:3830711)
|
- [T-Beam V1](https://www.thingiverse.com/thing:3830711)
|
||||||
|
- Laser-cut cases
|
||||||
|
- [T-Beam V1](https://www.thingiverse.com/thing:4552771)
|
||||||
|
|
||||||
- [TTGO LORA32](https://www.aliexpress.com/item/4000211331316.html) - No GPS
|
- [TTGO LORA32](https://www.aliexpress.com/item/4000211331316.html) - No GPS
|
||||||
- version 2.1
|
- version 2.1
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ COUNTRIES="US EU433 EU865 CN JP"
|
|||||||
#COUNTRIES=US
|
#COUNTRIES=US
|
||||||
#COUNTRIES=CN
|
#COUNTRIES=CN
|
||||||
|
|
||||||
BOARDS="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"
|
||||||
|
|
||||||
|
# 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="$BOARDS_ESP32 $BOARDS_NRF52"
|
||||||
#BOARDS=tbeam
|
#BOARDS=tbeam
|
||||||
|
|
||||||
OUTDIR=release/latest
|
OUTDIR=release/latest
|
||||||
@@ -23,20 +27,17 @@ rm -f $OUTDIR/bins/*
|
|||||||
|
|
||||||
# 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 {
|
||||||
ENV_NAME=$1
|
echo "Building for $BOARD with $PLATFORMIO_BUILD_FLAGS"
|
||||||
echo "Building for $ENV_NAME with $PLATFORMIO_BUILD_FLAGS"
|
rm -f .pio/build/$BOARD/firmware.*
|
||||||
SRCBIN=.pio/build/$ENV_NAME/firmware.bin
|
|
||||||
SRCELF=.pio/build/$ENV_NAME/firmware.elf
|
|
||||||
rm -f $SRCBIN
|
|
||||||
|
|
||||||
# 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 HW_VERSION="1.0-$COUNTRY"
|
||||||
export APP_VERSION=$VERSION
|
export APP_VERSION=$VERSION
|
||||||
export COUNTRY
|
export COUNTRY
|
||||||
|
|
||||||
pio run --jobs 4 --environment $ENV_NAME # -v
|
pio run --jobs 4 --environment $BOARD # -v
|
||||||
cp $SRCBIN $OUTDIR/bins/firmware-$ENV_NAME-$COUNTRY-$VERSION.bin
|
SRCELF=.pio/build/$BOARD/firmware.elf
|
||||||
cp $SRCELF $OUTDIR/elfs/firmware-$ENV_NAME-$COUNTRY-$VERSION.elf
|
cp $SRCELF $OUTDIR/elfs/firmware-$BOARD-$COUNTRY-$VERSION.elf
|
||||||
}
|
}
|
||||||
|
|
||||||
# Make sure our submodules are current
|
# Make sure our submodules are current
|
||||||
@@ -49,6 +50,18 @@ for COUNTRY in $COUNTRIES; do
|
|||||||
for BOARD in $BOARDS; do
|
for BOARD in $BOARDS; do
|
||||||
do_build $BOARD
|
do_build $BOARD
|
||||||
done
|
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
|
done
|
||||||
|
|
||||||
# keep the bins in archive also
|
# keep the bins in archive also
|
||||||
|
|||||||
@@ -1,11 +1,45 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
# Usage info
|
||||||
|
show_help() {
|
||||||
|
cat << EOF
|
||||||
|
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] [-f FILENAME]
|
||||||
|
Flash image file to device, but first erasing and writing system information"
|
||||||
|
|
||||||
FILENAME=$1
|
-h Display this help and exit
|
||||||
|
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
|
||||||
|
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
echo "Trying to flash $FILENAME, but first erasing and writing system information"
|
|
||||||
esptool.py --baud 921600 erase_flash
|
|
||||||
esptool.py --baud 921600 write_flash 0x1000 system-info.bin
|
|
||||||
esptool.py --baud 921600 write_flash 0x10000 $FILENAME
|
|
||||||
|
|
||||||
|
while getopts ":h:p:f:" opt; do
|
||||||
|
case "${opt}" in
|
||||||
|
h)
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
p) export ESPTOOL_PORT=${OPTARG}
|
||||||
|
;;
|
||||||
|
f) FILENAME=${OPTARG}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid flag."
|
||||||
|
show_help >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
|
if [ -f "${FILENAME}" ]; then
|
||||||
|
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||||
|
esptool.py --baud 921600 erase_flash
|
||||||
|
esptool.py --baud 921600 write_flash 0x1000 system-info.bin
|
||||||
|
esptool.py --baud 921600 write_flash 0x10000 ${FILENAME}
|
||||||
|
else
|
||||||
|
echo "Invalid file: ${FILENAME}"
|
||||||
|
show_help
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|||||||
@@ -1,8 +1,43 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
# Usage info
|
||||||
|
show_help() {
|
||||||
|
cat << EOF
|
||||||
|
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] -f FILENAME
|
||||||
|
Flash image file to device, leave existing system intact."
|
||||||
|
|
||||||
FILENAME=$1
|
-h Display this help and exit
|
||||||
|
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
|
||||||
|
-f FILENAME The .bin file to flash. Custom to your device type and region.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
echo "Trying to update $FILENAME"
|
|
||||||
esptool.py --baud 921600 write_flash 0x10000 $FILENAME
|
while getopts ":h:p:f:" opt; do
|
||||||
|
case "${opt}" in
|
||||||
|
h)
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
p) export ESPTOOL_PORT=${OPTARG}
|
||||||
|
;;
|
||||||
|
f) FILENAME=${OPTARG}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid flag."
|
||||||
|
show_help >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
|
if [ -f "${FILENAME}" ]; then
|
||||||
|
echo "Trying to flash update ${FILENAME}."
|
||||||
|
esptool.py --baud 921600 write_flash 0x10000 ${FILENAME}
|
||||||
|
else
|
||||||
|
echo "Invalid file: ${FILENAME}"
|
||||||
|
show_help
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|||||||
314
bin/uf2conv.py
Executable file
314
bin/uf2conv.py
Executable file
@@ -0,0 +1,314 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
UF2_MAGIC_START0 = 0x0A324655 # "UF2\n"
|
||||||
|
UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected
|
||||||
|
UF2_MAGIC_END = 0x0AB16F30 # Ditto
|
||||||
|
|
||||||
|
families = {
|
||||||
|
'SAMD21': 0x68ed2b88,
|
||||||
|
'SAML21': 0x1851780a,
|
||||||
|
'SAMD51': 0x55114460,
|
||||||
|
'NRF52': 0x1b57745f,
|
||||||
|
'STM32F0': 0x647824b6,
|
||||||
|
'STM32F1': 0x5ee21072,
|
||||||
|
'STM32F2': 0x5d1a0a2e,
|
||||||
|
'STM32F3': 0x6b846188,
|
||||||
|
'STM32F4': 0x57755a57,
|
||||||
|
'STM32F7': 0x53b80f00,
|
||||||
|
'STM32G0': 0x300f5633,
|
||||||
|
'STM32G4': 0x4c71240a,
|
||||||
|
'STM32H7': 0x6db66082,
|
||||||
|
'STM32L0': 0x202e3a91,
|
||||||
|
'STM32L1': 0x1e1f432d,
|
||||||
|
'STM32L4': 0x00ff6919,
|
||||||
|
'STM32L5': 0x04240bdf,
|
||||||
|
'STM32WB': 0x70d16653,
|
||||||
|
'STM32WL': 0x21460ff0,
|
||||||
|
'ATMEGA32': 0x16573617,
|
||||||
|
'MIMXRT10XX': 0x4FB2D5BD
|
||||||
|
}
|
||||||
|
|
||||||
|
INFO_FILE = "/INFO_UF2.TXT"
|
||||||
|
|
||||||
|
appstartaddr = 0x2000
|
||||||
|
familyid = 0x0
|
||||||
|
|
||||||
|
|
||||||
|
def is_uf2(buf):
|
||||||
|
w = struct.unpack("<II", buf[0:8])
|
||||||
|
return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1
|
||||||
|
|
||||||
|
def is_hex(buf):
|
||||||
|
try:
|
||||||
|
w = buf[0:30].decode("utf-8")
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return False
|
||||||
|
if w[0] == ':' and re.match(b"^[:0-9a-fA-F\r\n]+$", buf):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def convert_from_uf2(buf):
|
||||||
|
global appstartaddr
|
||||||
|
numblocks = len(buf) // 512
|
||||||
|
curraddr = None
|
||||||
|
outp = b""
|
||||||
|
for blockno in range(numblocks):
|
||||||
|
ptr = blockno * 512
|
||||||
|
block = buf[ptr:ptr + 512]
|
||||||
|
hd = struct.unpack(b"<IIIIIIII", block[0:32])
|
||||||
|
if hd[0] != UF2_MAGIC_START0 or hd[1] != UF2_MAGIC_START1:
|
||||||
|
print("Skipping block at " + ptr + "; bad magic")
|
||||||
|
continue
|
||||||
|
if hd[2] & 1:
|
||||||
|
# NO-flash flag set; skip block
|
||||||
|
continue
|
||||||
|
datalen = hd[4]
|
||||||
|
if datalen > 476:
|
||||||
|
assert False, "Invalid UF2 data size at " + ptr
|
||||||
|
newaddr = hd[3]
|
||||||
|
if curraddr == None:
|
||||||
|
appstartaddr = newaddr
|
||||||
|
curraddr = newaddr
|
||||||
|
padding = newaddr - curraddr
|
||||||
|
if padding < 0:
|
||||||
|
assert False, "Block out of order at " + ptr
|
||||||
|
if padding > 10*1024*1024:
|
||||||
|
assert False, "More than 10M of padding needed at " + ptr
|
||||||
|
if padding % 4 != 0:
|
||||||
|
assert False, "Non-word padding size at " + ptr
|
||||||
|
while padding > 0:
|
||||||
|
padding -= 4
|
||||||
|
outp += b"\x00\x00\x00\x00"
|
||||||
|
outp += block[32 : 32 + datalen]
|
||||||
|
curraddr = newaddr + datalen
|
||||||
|
return outp
|
||||||
|
|
||||||
|
def convert_to_carray(file_content):
|
||||||
|
outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {"
|
||||||
|
for i in range(len(file_content)):
|
||||||
|
if i % 16 == 0:
|
||||||
|
outp += "\n"
|
||||||
|
outp += "0x%02x, " % ord(file_content[i])
|
||||||
|
outp += "\n};\n"
|
||||||
|
return outp
|
||||||
|
|
||||||
|
def convert_to_uf2(file_content):
|
||||||
|
global familyid
|
||||||
|
datapadding = b""
|
||||||
|
while len(datapadding) < 512 - 256 - 32 - 4:
|
||||||
|
datapadding += b"\x00\x00\x00\x00"
|
||||||
|
numblocks = (len(file_content) + 255) // 256
|
||||||
|
outp = b""
|
||||||
|
for blockno in range(numblocks):
|
||||||
|
ptr = 256 * blockno
|
||||||
|
chunk = file_content[ptr:ptr + 256]
|
||||||
|
flags = 0x0
|
||||||
|
if familyid:
|
||||||
|
flags |= 0x2000
|
||||||
|
hd = struct.pack(b"<IIIIIIII",
|
||||||
|
UF2_MAGIC_START0, UF2_MAGIC_START1,
|
||||||
|
flags, ptr + appstartaddr, 256, blockno, numblocks, familyid)
|
||||||
|
while len(chunk) < 256:
|
||||||
|
chunk += b"\x00"
|
||||||
|
block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END)
|
||||||
|
assert len(block) == 512
|
||||||
|
outp += block
|
||||||
|
return outp
|
||||||
|
|
||||||
|
class Block:
|
||||||
|
def __init__(self, addr):
|
||||||
|
self.addr = addr
|
||||||
|
self.bytes = bytearray(256)
|
||||||
|
|
||||||
|
def encode(self, blockno, numblocks):
|
||||||
|
global familyid
|
||||||
|
flags = 0x0
|
||||||
|
if familyid:
|
||||||
|
flags |= 0x2000
|
||||||
|
hd = struct.pack("<IIIIIIII",
|
||||||
|
UF2_MAGIC_START0, UF2_MAGIC_START1,
|
||||||
|
flags, self.addr, 256, blockno, numblocks, familyid)
|
||||||
|
hd += self.bytes[0:256]
|
||||||
|
while len(hd) < 512 - 4:
|
||||||
|
hd += b"\x00"
|
||||||
|
hd += struct.pack("<I", UF2_MAGIC_END)
|
||||||
|
return hd
|
||||||
|
|
||||||
|
def convert_from_hex_to_uf2(buf):
|
||||||
|
global appstartaddr
|
||||||
|
appstartaddr = None
|
||||||
|
upper = 0
|
||||||
|
currblock = None
|
||||||
|
blocks = []
|
||||||
|
for line in buf.split('\n'):
|
||||||
|
if line[0] != ":":
|
||||||
|
continue
|
||||||
|
i = 1
|
||||||
|
rec = []
|
||||||
|
while i < len(line) - 1:
|
||||||
|
rec.append(int(line[i:i+2], 16))
|
||||||
|
i += 2
|
||||||
|
tp = rec[3]
|
||||||
|
if tp == 4:
|
||||||
|
upper = ((rec[4] << 8) | rec[5]) << 16
|
||||||
|
elif tp == 2:
|
||||||
|
upper = ((rec[4] << 8) | rec[5]) << 4
|
||||||
|
assert (upper & 0xffff) == 0
|
||||||
|
elif tp == 1:
|
||||||
|
break
|
||||||
|
elif tp == 0:
|
||||||
|
addr = upper | (rec[1] << 8) | rec[2]
|
||||||
|
if appstartaddr == None:
|
||||||
|
appstartaddr = addr
|
||||||
|
i = 4
|
||||||
|
while i < len(rec) - 1:
|
||||||
|
if not currblock or currblock.addr & ~0xff != addr & ~0xff:
|
||||||
|
currblock = Block(addr & ~0xff)
|
||||||
|
blocks.append(currblock)
|
||||||
|
currblock.bytes[addr & 0xff] = rec[i]
|
||||||
|
addr += 1
|
||||||
|
i += 1
|
||||||
|
numblocks = len(blocks)
|
||||||
|
resfile = b""
|
||||||
|
for i in range(0, numblocks):
|
||||||
|
resfile += blocks[i].encode(i, numblocks)
|
||||||
|
return resfile
|
||||||
|
|
||||||
|
def to_str(b):
|
||||||
|
return b.decode("utf-8")
|
||||||
|
|
||||||
|
def get_drives():
|
||||||
|
drives = []
|
||||||
|
if sys.platform == "win32":
|
||||||
|
r = subprocess.check_output(["wmic", "PATH", "Win32_LogicalDisk",
|
||||||
|
"get", "DeviceID,", "VolumeName,",
|
||||||
|
"FileSystem,", "DriveType"])
|
||||||
|
for line in to_str(r).split('\n'):
|
||||||
|
words = re.split('\s+', line)
|
||||||
|
if len(words) >= 3 and words[1] == "2" and words[2] == "FAT":
|
||||||
|
drives.append(words[0])
|
||||||
|
else:
|
||||||
|
rootpath = "/media"
|
||||||
|
if sys.platform == "darwin":
|
||||||
|
rootpath = "/Volumes"
|
||||||
|
elif sys.platform == "linux":
|
||||||
|
tmp = rootpath + "/" + os.environ["USER"]
|
||||||
|
if os.path.isdir(tmp):
|
||||||
|
rootpath = tmp
|
||||||
|
for d in os.listdir(rootpath):
|
||||||
|
drives.append(os.path.join(rootpath, d))
|
||||||
|
|
||||||
|
|
||||||
|
def has_info(d):
|
||||||
|
try:
|
||||||
|
return os.path.isfile(d + INFO_FILE)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return list(filter(has_info, drives))
|
||||||
|
|
||||||
|
|
||||||
|
def board_id(path):
|
||||||
|
with open(path + INFO_FILE, mode='r') as file:
|
||||||
|
file_content = file.read()
|
||||||
|
return re.search("Board-ID: ([^\r\n]*)", file_content).group(1)
|
||||||
|
|
||||||
|
|
||||||
|
def list_drives():
|
||||||
|
for d in get_drives():
|
||||||
|
print(d, board_id(d))
|
||||||
|
|
||||||
|
|
||||||
|
def write_file(name, buf):
|
||||||
|
with open(name, "wb") as f:
|
||||||
|
f.write(buf)
|
||||||
|
print("Wrote %d bytes to %s" % (len(buf), name))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global appstartaddr, familyid
|
||||||
|
def error(msg):
|
||||||
|
print(msg)
|
||||||
|
sys.exit(1)
|
||||||
|
parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.')
|
||||||
|
parser.add_argument('input', metavar='INPUT', type=str, nargs='?',
|
||||||
|
help='input file (HEX, BIN or UF2)')
|
||||||
|
parser.add_argument('-b' , '--base', dest='base', type=str,
|
||||||
|
default="0x2000",
|
||||||
|
help='set base address of application for BIN format (default: 0x2000)')
|
||||||
|
parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str,
|
||||||
|
help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible')
|
||||||
|
parser.add_argument('-d' , '--device', dest="device_path",
|
||||||
|
help='select a device path to flash')
|
||||||
|
parser.add_argument('-l' , '--list', action='store_true',
|
||||||
|
help='list connected devices')
|
||||||
|
parser.add_argument('-c' , '--convert', action='store_true',
|
||||||
|
help='do not flash, just convert')
|
||||||
|
parser.add_argument('-D' , '--deploy', action='store_true',
|
||||||
|
help='just flash, do not convert')
|
||||||
|
parser.add_argument('-f' , '--family', dest='family', type=str,
|
||||||
|
default="0x0",
|
||||||
|
help='specify familyID - number or name (default: 0x0)')
|
||||||
|
parser.add_argument('-C' , '--carray', action='store_true',
|
||||||
|
help='convert binary file to a C array, not UF2')
|
||||||
|
args = parser.parse_args()
|
||||||
|
appstartaddr = int(args.base, 0)
|
||||||
|
|
||||||
|
if args.family.upper() in families:
|
||||||
|
familyid = families[args.family.upper()]
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
familyid = int(args.family, 0)
|
||||||
|
except ValueError:
|
||||||
|
error("Family ID needs to be a number or one of: " + ", ".join(families.keys()))
|
||||||
|
|
||||||
|
if args.list:
|
||||||
|
list_drives()
|
||||||
|
else:
|
||||||
|
if not args.input:
|
||||||
|
error("Need input file")
|
||||||
|
with open(args.input, mode='rb') as f:
|
||||||
|
inpbuf = f.read()
|
||||||
|
from_uf2 = is_uf2(inpbuf)
|
||||||
|
ext = "uf2"
|
||||||
|
if args.deploy:
|
||||||
|
outbuf = inpbuf
|
||||||
|
elif from_uf2:
|
||||||
|
outbuf = convert_from_uf2(inpbuf)
|
||||||
|
ext = "bin"
|
||||||
|
elif is_hex(inpbuf):
|
||||||
|
outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8"))
|
||||||
|
elif args.carray:
|
||||||
|
outbuf = convert_to_carray(inpbuf)
|
||||||
|
ext = "h"
|
||||||
|
else:
|
||||||
|
outbuf = convert_to_uf2(inpbuf)
|
||||||
|
print("Converting to %s, output size: %d, start address: 0x%x" %
|
||||||
|
(ext, len(outbuf), appstartaddr))
|
||||||
|
if args.convert or ext != "uf2":
|
||||||
|
drives = []
|
||||||
|
if args.output == None:
|
||||||
|
args.output = "flash." + ext
|
||||||
|
else:
|
||||||
|
drives = get_drives()
|
||||||
|
|
||||||
|
if args.output:
|
||||||
|
write_file(args.output, outbuf)
|
||||||
|
else:
|
||||||
|
if len(drives) == 0:
|
||||||
|
error("No drive to deploy.")
|
||||||
|
for d in drives:
|
||||||
|
print("Flashing %s (%s)" % (d, board_id(d)))
|
||||||
|
write_file(d + "/NEW.UF2", outbuf)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
4
bin/upload-to-bootloader.sh
Executable file
4
bin/upload-to-bootloader.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
echo "Converting to uf2 for NRF52 Adafruit bootloader"
|
||||||
|
bin/uf2conv.py .pio/build/lora-relay-v1/firmware.hex -f 0xADA52840
|
||||||
|
# cp flash.uf2 /media/kevinh/FTH*BOOT/
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
export VERSION=0.9.1
|
export VERSION=0.9.3
|
||||||
46
boards/lora-relay-v1.json
Normal file
46
boards/lora-relay-v1.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "nrf52840_s140_v6.ld"
|
||||||
|
},
|
||||||
|
"core": "nRF5",
|
||||||
|
"cpu": "cortex-m4",
|
||||||
|
"extra_flags": "-DARDUINO_NRF52840_LORA_RELAY_V1 -DNRF52840_XXAA",
|
||||||
|
"f_cpu": "64000000L",
|
||||||
|
"hwids": [["0x239A", "0x4404"]],
|
||||||
|
"usb_product": "LORA_RELAY",
|
||||||
|
"mcu": "nrf52840",
|
||||||
|
"variant": "lora_relay_v1",
|
||||||
|
"variants_dir": "variants",
|
||||||
|
"bsp": {
|
||||||
|
"name": "adafruit"
|
||||||
|
},
|
||||||
|
"softdevice": {
|
||||||
|
"sd_flags": "-DS140",
|
||||||
|
"sd_name": "s140",
|
||||||
|
"sd_version": "6.1.1",
|
||||||
|
"sd_fwid": "0x00B6"
|
||||||
|
},
|
||||||
|
"bootloader": {
|
||||||
|
"settings_addr": "0xFF000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectivity": ["bluetooth"],
|
||||||
|
"debug": {
|
||||||
|
"jlink_device": "nRF52840_xxAA",
|
||||||
|
"onboard_tools": ["jlink"],
|
||||||
|
"svd_path": "nrf52840.svd"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino"],
|
||||||
|
"name": "Meshtastic Lora Relay V1 (Adafruit BSP)",
|
||||||
|
"upload": {
|
||||||
|
"maximum_ram_size": 248832,
|
||||||
|
"maximum_size": 815104,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 115200,
|
||||||
|
"protocol": "jlink",
|
||||||
|
"protocols": ["jlink", "nrfjprog", "stlink"]
|
||||||
|
},
|
||||||
|
"url": "https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay",
|
||||||
|
"vendor": "BigCorvus"
|
||||||
|
}
|
||||||
@@ -66,6 +66,8 @@ The link above will return older more stable releases. We would prefer if you jo
|
|||||||
|
|
||||||
If you'd like to help with development, the source code is [on github](https://github.com/meshtastic/Meshtastic-Android).
|
If you'd like to help with development, the source code is [on github](https://github.com/meshtastic/Meshtastic-Android).
|
||||||
|
|
||||||
|
The app is also distributed for Amazon Fire devices via the Amazon appstore: [](https://www.amazon.com/Geeksville-Industries-Meshtastic/dp/B08CY9394Q)
|
||||||
|
|
||||||
## Supported hardware
|
## Supported hardware
|
||||||
|
|
||||||
We currently support two brands of radios. The [TTGO T-Beam](https://www.aliexpress.com/item/4001178678568.html) and the [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/). Most people should buy the T-Beam and a 18650 battery (total cost less than \$35). Also, the version of the T-Beam we link to is shipped with Meshtastic **preinstalled** by TTGO, so you don't have to install it yourself.
|
We currently support two brands of radios. The [TTGO T-Beam](https://www.aliexpress.com/item/4001178678568.html) and the [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/). Most people should buy the T-Beam and a 18650 battery (total cost less than \$35). Also, the version of the T-Beam we link to is shipped with Meshtastic **preinstalled** by TTGO, so you don't have to install it yourself.
|
||||||
|
|||||||
35
docs/hardware/corvus.md
Normal file
35
docs/hardware/corvus.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Notes on @BigCorvus boards
|
||||||
|
|
||||||
|
## Board version 1.1
|
||||||
|
|
||||||
|
variant name lora_relay_v1
|
||||||
|
|
||||||
|
### Remaining TODOs
|
||||||
|
|
||||||
|
- power hold for the ST7735
|
||||||
|
- look at example sketch
|
||||||
|
- turn on xmit boost
|
||||||
|
|
||||||
|
## Recommendations for future boards
|
||||||
|
|
||||||
|
@BigCorvus your board is **really** nice. Here's some ideas for the future:
|
||||||
|
|
||||||
|
- make the SWDIO header more standard (the small ARM 2x5 micro footprint?) or at least througholes so it is easy to solder a header
|
||||||
|
|
||||||
|
## How to program bootloader
|
||||||
|
|
||||||
|
Download from here: https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases
|
||||||
|
|
||||||
|
```
|
||||||
|
nrfjprog -f nrf52 --eraseall
|
||||||
|
Erasing user available code and UICR flash areas.
|
||||||
|
Applying system reset.
|
||||||
|
|
||||||
|
nrfjprog -f nrf52 --program feather_nrf52840_express_bootloader-0.3.2_s140_6.1.1.hex
|
||||||
|
Parsing hex file.
|
||||||
|
Reading flash area to program to guarantee it is erased.
|
||||||
|
Checking that the area to write is not protected.
|
||||||
|
Programming device.
|
||||||
|
```
|
||||||
|
|
||||||
|
Then reboot the board, if all went well it now shows up as a mountable filesystem on your USB bus.
|
||||||
@@ -1,15 +1,30 @@
|
|||||||
# Build instructions
|
# Build instructions
|
||||||
|
|
||||||
This project uses the simple PlatformIO build system. You can use the IDE, but for brevity
|
This project uses the simple PlatformIO build system. PlatformIO is an extension to Microsoft VSCode.
|
||||||
in these instructions I describe use of their command line tool.
|
|
||||||
|
|
||||||
1. Purchase a suitable radio (see above)
|
## GUI
|
||||||
|
1. Purchase a suitable [radio](https://github.com/meshtastic/Meshtastic-device/wiki/Hardware-Information).
|
||||||
|
2. Install [PlatformIO](https://platformio.org/platformio-ide).
|
||||||
|
3. Click the PlatformIO icon on the side bar. 
|
||||||
|
4. Under `Quick Access, Miscellaneous, Clone Git Project` enter the URL of the Meshtastic repo found [here](https://github.com/meshtastic/Meshtastic-device). 
|
||||||
|
5. Select a file location to save the repo.
|
||||||
|
6. Once loaded, open the `platformio.ini` file.
|
||||||
|
7. At the line `default_envs` you can change it to the board type you are building for ie. `tlora-v2, tlora-v1, tlora-v2-1-1.6, tbeam, heltec, tbeam0.7` (boards are listed further down in the file).
|
||||||
|
8. Click the PlatformIO icon on the side bar. Under `Project Tasks` you can now build or upload.
|
||||||
|
|
||||||
|
## Command Line
|
||||||
|
1. Purchase a suitable [radio](https://github.com/meshtastic/Meshtastic-device/wiki/Hardware-Information).
|
||||||
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:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/meshtastic/Meshtastic-device.git
|
||||||
|
cd Meshtastic-device
|
||||||
|
```
|
||||||
4. Run `git submodule update --init --recursive` to pull in dependencies this project needs.
|
4. Run `git submodule update --init --recursive` to pull in dependencies this project needs.
|
||||||
5. If you are outside the USA, run "export COUNTRY=EU865" (or whatever) to set the correct frequency range for your country. Options are provided for `EU433`, `EU865`, `CN`, `JP` and `US` (default). Pull-requests eagerly accepted for other countries.
|
5. If you are outside the USA, run "export COUNTRY=EU865" (or whatever) to set the correct frequency range for your country. Options are provided for `EU433`, `EU865`, `CN`, `JP` and `US` (default). Pull-requests eagerly accepted for other countries.
|
||||||
6. Plug the radio into your USB port
|
6. Plug the radio into your USB port
|
||||||
7. 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. 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 `tlora-v2, tlora-v1, tlora-v2-1-1.6, tbeam, heltec, tbeam0.7`).
|
||||||
8. 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.
|
8. 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
|
||||||
|
|||||||
@@ -1,5 +1,75 @@
|
|||||||
# Mesh broadcast algorithm
|
# Mesh broadcast algorithm
|
||||||
|
|
||||||
|
## Current algorithm
|
||||||
|
|
||||||
|
The routing protocol for Meshtastic is really quite simple (and suboptimal). It is heavily influenced by the mesh routing algorithm used in [Radiohead](https://www.airspayce.com/mikem/arduino/RadioHead/) (which was used in very early versions of this project). It has four conceptual layers.
|
||||||
|
|
||||||
|
### A note about protocol buffers
|
||||||
|
|
||||||
|
Because we want our devices to work across various vendors and implementations, we use [Protocol Buffers](https://github.com/meshtastic/Meshtastic-protobufs) pervasively. For information on how the protocol buffers are used wrt API clients see [sw-design](sw-design.md), for purposes of this document you mostly only
|
||||||
|
need to consider the MeshPacket and Subpacket message types.
|
||||||
|
|
||||||
|
### Layer 1: Non reliable zero hop messaging
|
||||||
|
|
||||||
|
This layer is conventional non-reliable lora packet transmission. The transmitted packet has the following representation on the ether:
|
||||||
|
|
||||||
|
- A 32 bit LORA preamble (to allow receiving radios to synchronize clocks and start framing). We use a longer than minimum (8 bit) preamble to maximize the amount of time the LORA receivers can stay asleep, which dramatically lowers power consumption.
|
||||||
|
|
||||||
|
After the preamble the 16 byte packet header is transmitted. This header is described directly by the PacketHeader class in the C++ source code. But indirectly it matches the first portion of the "MeshPacket" protobuf definition. But notably: this portion of the packet is sent directly as the following 16 bytes (rather than using the protobuf encoding). We do this to both save airtime and to allow receiving radio hardware the option of filtering packets before even waking the main CPU.
|
||||||
|
|
||||||
|
- to (4 bytes): the unique NodeId of the destination (or 0xffffffff for NodeNum_BROADCAST)
|
||||||
|
- from (4 bytes): the unique NodeId of the sender)
|
||||||
|
- id (4 bytes): the unique (wrt the sending node only) packet ID number for this packet. We use a large (32 bit) packet ID to ensure there is enough unique state to protect any encrypted payload from attack.
|
||||||
|
- flags (4 bytes): Only a few bits are are currently used - 3 bits for for the "HopLimit" (see below) and 1 bit for "WantAck"
|
||||||
|
|
||||||
|
After the packet header the actual packet is placed onto the the wire. These bytes are merely the encrypted packed protobuf encoding of the SubPacket protobuf. A full description of our encryption is available in [crypto](crypto.md). It is worth noting that only this SubPacket is encrypted, headers are not. Which leaves open the option of eventually allowing nodes to route packets without knowing the keys used to encrypt.
|
||||||
|
|
||||||
|
NodeIds are constructed from the bottom four bytes of the macaddr of the bluetooth address. Because the OUI is assigned by the IEEE and we currently only support a few CPU manufacturers, the upper byte is defacto guaranteed unique for each vendor. The bottom 3 bytes are guaranteed unique by that vendor.
|
||||||
|
|
||||||
|
To prevent collisions all transmitters will listen before attempting to send. If they hear some other node transmitting, they will reattempt transmission in x milliseconds. This retransmission delay is random between FIXME and FIXME (these two numbers are currently hardwired, but really should be scaled based on expected packet transmission time at current channel settings).
|
||||||
|
|
||||||
|
### Layer 2: Reliable zero hop messaging
|
||||||
|
|
||||||
|
This layer adds reliable messaging between the node and its immediate neighbors (only).
|
||||||
|
|
||||||
|
The default messaging provided by layer-1 is extended by setting the "want-ack" flag in the MeshPacket protobuf. If want-ack is set the following documentation from mesh.proto applies:
|
||||||
|
|
||||||
|
"""This packet is being sent as a reliable message, we would prefer it to arrive
|
||||||
|
at the destination. We would like to receive a ack packet in response.
|
||||||
|
|
||||||
|
Broadcasts messages treat this flag specially: Since acks for broadcasts would
|
||||||
|
rapidly flood the channel, the normal ack behavior is suppressed. Instead,
|
||||||
|
the original sender listens to see if at least one node is rebroadcasting this
|
||||||
|
packet (because naive flooding algorithm). If it hears that the odds (given
|
||||||
|
typical LoRa topologies) the odds are very high that every node should
|
||||||
|
eventually receive the message. So FloodingRouter.cpp generates an implicit
|
||||||
|
ack which is delivered to the original sender. If after some time we don't
|
||||||
|
hear anyone rebroadcast our packet, we will timeout and retransmit, using the
|
||||||
|
regular resend logic."""
|
||||||
|
|
||||||
|
If a transmitting node does not receive an ACK (or a NAK) packet within FIXME milliseconds, it will use layer-1 to attempt a retransmission of the sent packet. A reliable packet (at this 'zero hop' level) will be resent a maximum of three times. If no ack or nak has been received by then the local node will internally generate a nak (either for local consumption or use by higher layers of the protocol).
|
||||||
|
|
||||||
|
### Layer 3: (Naive) flooding for multi-hop messaging
|
||||||
|
|
||||||
|
Given our use-case for the initial release, most of our protocol is built around [flooding](<https://en.wikipedia.org/wiki/Flooding_(computer_networking)>). The implementation is currently 'naive' - i.e. it doesn't try to optimize flooding other than abandoning retransmission once we've seen a nearby receiver has acked the packet. Therefore, for each source packet up to N retransmissions might occur (if there are N nodes in the mesh).
|
||||||
|
|
||||||
|
Each node in the mesh, if it sees a packet on the ether with HopLimit set to a value other than zero, it will decrement that HopLimit and attempt retransmission on behalf of the original sending node.
|
||||||
|
|
||||||
|
### Layer 4: DSR for multi-hop unicast messaging
|
||||||
|
|
||||||
|
This layer is not yet fully implemented (and not yet used). But eventually (if we stay with our own transport rather than switching to QMesh or Reticulum)
|
||||||
|
we will use conventional DSR for unicast messaging. Currently (even when not requiring 'broadcasts') we send any multi-hop unicasts as 'broadcasts' so that we can
|
||||||
|
leverage our (functional) flooding implementation. This is suboptimal but it is a very rare use-case, because the odds are high that most nodes (given our small networks and 'hiking' use case) are within a very small number of hops. When any node witnesses an ack for a packet, it will realize that it can abandon its own
|
||||||
|
broadcast attempt for that packet.
|
||||||
|
|
||||||
|
## Misc notes on remaining tasks
|
||||||
|
|
||||||
|
This section is currently poorly formatted, it is mostly a mere set of todo lists and notes for @geeksville during his initial development. After release 1.0 ideas for future optimization include:
|
||||||
|
|
||||||
|
- Make flood-routing less naive (because we have GPS and radio signal strength as heuristics to avoid redundant retransmissions)
|
||||||
|
- If nodes have been user marked as 'routers', preferentially do flooding via those nodes
|
||||||
|
- Fully implement DSR to improve unicast efficiency (or switch to QMesh/Reticulum as these projects mature)
|
||||||
|
|
||||||
great source of papers and class notes: http://www.cs.jhu.edu/~cs647/
|
great source of papers and class notes: http://www.cs.jhu.edu/~cs647/
|
||||||
|
|
||||||
flood routing improvements
|
flood routing improvements
|
||||||
@@ -146,23 +216,3 @@ look into the literature for this idea specifically.
|
|||||||
build the most recent version of reality, and if some nodes are too far, then nodes closer in will eventually forward their changes to the distributed db.
|
build the most recent version of reality, and if some nodes are too far, then nodes closer in will eventually forward their changes to the distributed db.
|
||||||
- construct non ambigious rules for who broadcasts to request db updates. ideally the algorithm should nicely realize node X can see most other nodes, so they should just listen to all those nodes and minimize the # of broadcasts. the distributed picture of nodes rssi could be useful here?
|
- construct non ambigious rules for who broadcasts to request db updates. ideally the algorithm should nicely realize node X can see most other nodes, so they should just listen to all those nodes and minimize the # of broadcasts. the distributed picture of nodes rssi could be useful here?
|
||||||
- possibly view the BLE protocol to the radio the same way - just a process of reconverging the node/msgdb database.
|
- possibly view the BLE protocol to the radio the same way - just a process of reconverging the node/msgdb database.
|
||||||
|
|
||||||
# Old notes
|
|
||||||
|
|
||||||
FIXME, merge into the above:
|
|
||||||
|
|
||||||
good description of batman protocol: https://www.open-mesh.org/projects/open-mesh/wiki/BATMANConcept
|
|
||||||
|
|
||||||
interesting paper on lora mesh: https://portal.research.lu.se/portal/files/45735775/paper.pdf
|
|
||||||
It seems like DSR might be the algorithm used by RadioheadMesh. DSR is described in https://tools.ietf.org/html/rfc4728
|
|
||||||
https://en.wikipedia.org/wiki/Dynamic_Source_Routing
|
|
||||||
|
|
||||||
broadcast solution:
|
|
||||||
Use naive flooding at first (FIXME - do some math for a 20 node, 3 hop mesh. A single flood will require a max of 20 messages sent)
|
|
||||||
Then move to MPR later (http://www.olsr.org/docs/report_html/node28.html). Use altitude and location as heursitics in selecting the MPR set
|
|
||||||
|
|
||||||
compare to db sync algorithm?
|
|
||||||
|
|
||||||
what about never flooding gps broadcasts. instead only have them go one hop in the common case, but if any node X is looking at the position of Y on their gui, then send a unicast to Y asking for position update. Y replies.
|
|
||||||
|
|
||||||
If Y were to die, at least the neighbor nodes of Y would have their last known position of Y.
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
|
- shrink soft device RAM usage
|
||||||
|
- get nrf52832 working again (currently OOM)
|
||||||
- i2c gps comms not quite right
|
- i2c gps comms not quite right
|
||||||
- ble: AdafruitBluefruit::begin - adafruit_ble_task was assigned an invalid stack pointer. out of memory?
|
- ble: AdafruitBluefruit::begin - adafruit_ble_task was assigned an invalid stack pointer. out of memory?
|
||||||
- measure power draw
|
- measure power draw
|
||||||
|
|||||||
BIN
images/amazon-fire-button.png
Normal file
BIN
images/amazon-fire-button.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -9,7 +9,7 @@
|
|||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
default_envs = tbeam ; Note: the github actions CI test build can't yet build NRF52 targets
|
default_envs = tbeam # lora-relay-v1
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
; common is not currently used
|
; common is not currently used
|
||||||
@@ -32,7 +32,6 @@ 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 = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Os -Wl,-Map,.pio/build/output.map
|
build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Os -Wl,-Map,.pio/build/output.map
|
||||||
-DAXP_DEBUG_PORT=Serial
|
|
||||||
-DHW_VERSION_${sysenv.COUNTRY}
|
-DHW_VERSION_${sysenv.COUNTRY}
|
||||||
-DAPP_VERSION=${sysenv.APP_VERSION}
|
-DAPP_VERSION=${sysenv.APP_VERSION}
|
||||||
-DHW_VERSION=${sysenv.HW_VERSION}
|
-DHW_VERSION=${sysenv.HW_VERSION}
|
||||||
@@ -69,6 +68,7 @@ lib_deps =
|
|||||||
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
|
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
|
||||||
https://github.com/meshtastic/RadioLib.git#d6b12f7eb0a06bd2414c79b437b25d377e3f603f
|
https://github.com/meshtastic/RadioLib.git#d6b12f7eb0a06bd2414c79b437b25d377e3f603f
|
||||||
https://github.com/meshtastic/TinyGPSPlus.git
|
https://github.com/meshtastic/TinyGPSPlus.git
|
||||||
|
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
||||||
|
|
||||||
; Common settings for ESP targes, mixin with extends = esp32_base
|
; Common settings for ESP targes, mixin with extends = esp32_base
|
||||||
[esp32_base]
|
[esp32_base]
|
||||||
@@ -80,6 +80,7 @@ debug_init_break = tbreak setup
|
|||||||
build_flags =
|
build_flags =
|
||||||
${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue -lnimble -std=c++11
|
${env.build_flags} -Wall -Wextra -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
|
||||||
# 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
|
||||||
@@ -99,7 +100,6 @@ extends = esp32_base
|
|||||||
board = ttgo-t-beam
|
board = ttgo-t-beam
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
https://github.com/meshtastic/AXP202X_Library.git
|
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_base.build_flags} -D TBEAM_V10
|
${esp32_base.build_flags} -D TBEAM_V10
|
||||||
|
|
||||||
@@ -186,6 +186,9 @@ board = nrf52840_dk
|
|||||||
[env:nrf52840dk-geeksville]
|
[env:nrf52840dk-geeksville]
|
||||||
extends = nrf52_base
|
extends = nrf52_base
|
||||||
board = nrf52840_dk_modified
|
board = nrf52840_dk_modified
|
||||||
|
# add our variants files to the include and src paths
|
||||||
|
build_flags = ${nrf52_base.build_flags} -Ivariants/pca10056-rc-clock
|
||||||
|
src_filter = ${nrf52_base.src_filter} +<../variants/pca10056-rc-clock>
|
||||||
|
|
||||||
; Note: By default no lora device is created for this build - it uses a simulated interface
|
; Note: By default no lora device is created for this build - it uses a simulated interface
|
||||||
[env:feather_nrf52832]
|
[env:feather_nrf52832]
|
||||||
@@ -212,6 +215,19 @@ lib_deps =
|
|||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
UC1701
|
UC1701
|
||||||
|
|
||||||
|
; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus
|
||||||
|
[env:lora-relay-v1]
|
||||||
|
extends = nrf52_base
|
||||||
|
board = lora-relay-v1
|
||||||
|
# add our variants files to the include and src paths
|
||||||
|
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_relay_v1
|
||||||
|
src_filter = ${nrf52_base.src_filter} +<../variants/lora_relay_v1>
|
||||||
|
lib_deps =
|
||||||
|
${env.lib_deps}
|
||||||
|
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
|
||||||
|
TFT_eSPI
|
||||||
|
# Adafruit ST7735 and ST7789 Library
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
proto
2
proto
Submodule proto updated: 0523977d1f...3caee2e5b9
1
release/.gitignore
vendored
1
release/.gitignore
vendored
@@ -2,3 +2,4 @@
|
|||||||
*.bin
|
*.bin
|
||||||
*.map
|
*.map
|
||||||
*.zip
|
*.zip
|
||||||
|
*.uf2
|
||||||
|
|||||||
145
src/Power.cpp
145
src/Power.cpp
@@ -1,27 +1,92 @@
|
|||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utils.h"
|
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
|
#include "utils.h"
|
||||||
#ifdef TBEAM_V10
|
|
||||||
|
|
||||||
// FIXME. nasty hack cleanup how we load axp192
|
// FIXME. nasty hack cleanup how we load axp192
|
||||||
#undef AXP192_SLAVE_ADDRESS
|
#undef AXP192_SLAVE_ADDRESS
|
||||||
#include "axp20x.h"
|
#include "axp20x.h"
|
||||||
|
|
||||||
|
#ifdef TBEAM_V10
|
||||||
AXP20X_Class axp;
|
AXP20X_Class axp;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool pmu_irq = false;
|
bool pmu_irq = false;
|
||||||
|
|
||||||
Power *power;
|
Power *power;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this board has a battery level sensor, set this to a valid implementation
|
||||||
|
*/
|
||||||
|
static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level sensor
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple battery level sensor that assumes the battery voltage is attached via a voltage-divider to an analog input
|
||||||
|
*/
|
||||||
|
class AnalogBatteryLevel : public HasBatteryLevel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Battery state of charge, from 0 to 100 or -1 for unknown
|
||||||
|
*
|
||||||
|
* FIXME - use a lipo lookup table, the current % full is super wrong
|
||||||
|
*/
|
||||||
|
virtual int getBattPercentage()
|
||||||
|
{
|
||||||
|
float v = getBattVoltage() / 1000;
|
||||||
|
|
||||||
|
if (v < 2.1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 100 * (v - 3.27) / (4.2 - 3.27);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw voltage of the batteryin millivolts or NAN if unknown
|
||||||
|
*/
|
||||||
|
virtual float getBattVoltage()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
#ifdef BATTERY_PIN
|
||||||
|
1000.0 * analogRead(BATTERY_PIN) * 2.0 * (3.3 / 1024.0);
|
||||||
|
#else
|
||||||
|
NAN;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if there is a battery installed in this unit
|
||||||
|
*/
|
||||||
|
virtual bool isBatteryConnect() { return true; }
|
||||||
|
} analogLevel;
|
||||||
|
|
||||||
|
bool Power::analogInit()
|
||||||
|
{
|
||||||
|
#ifdef BATTERY_PIN
|
||||||
|
DEBUG_MSG("Using analog input for battery level\n");
|
||||||
|
adcAttachPin(BATTERY_PIN);
|
||||||
|
// adcStart(BATTERY_PIN);
|
||||||
|
analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
|
||||||
|
batteryLevel = &analogLevel;
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool Power::setup()
|
bool Power::setup()
|
||||||
{
|
{
|
||||||
|
bool found = axp192Init();
|
||||||
|
|
||||||
axp192Init();
|
if (!found) {
|
||||||
concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
|
found = analogInit();
|
||||||
setPeriod(1);
|
}
|
||||||
|
if (found) {
|
||||||
|
concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
|
||||||
|
setPeriod(1);
|
||||||
|
}
|
||||||
|
|
||||||
return axp192_found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads power status to powerStatus singleton.
|
/// Reads power status to powerStatus singleton.
|
||||||
@@ -29,29 +94,34 @@ bool Power::setup()
|
|||||||
// TODO(girts): move this and other axp stuff to power.h/power.cpp.
|
// TODO(girts): move this and other axp stuff to power.h/power.cpp.
|
||||||
void Power::readPowerStatus()
|
void Power::readPowerStatus()
|
||||||
{
|
{
|
||||||
bool hasBattery = axp.isBatteryConnect();
|
if (batteryLevel) {
|
||||||
int batteryVoltageMv = 0;
|
bool hasBattery = batteryLevel->isBatteryConnect();
|
||||||
uint8_t batteryChargePercent = 0;
|
int batteryVoltageMv = 0;
|
||||||
if (hasBattery) {
|
uint8_t batteryChargePercent = 0;
|
||||||
batteryVoltageMv = axp.getBattVoltage();
|
if (hasBattery) {
|
||||||
// If the AXP192 returns a valid battery percentage, use it
|
batteryVoltageMv = batteryLevel->getBattVoltage();
|
||||||
if (axp.getBattPercentage() >= 0) {
|
// If the AXP192 returns a valid battery percentage, use it
|
||||||
batteryChargePercent = axp.getBattPercentage();
|
if (batteryLevel->getBattPercentage() >= 0) {
|
||||||
} else {
|
batteryChargePercent = batteryLevel->getBattPercentage();
|
||||||
// If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
|
} else {
|
||||||
// In that case, we compute an estimate of the charge percent based on maximum and minimum voltages defined in power.h
|
// If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
|
||||||
batteryChargePercent = clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)), 0, 100);
|
// In that case, we compute an estimate of the charge percent based on maximum and minimum voltages defined in
|
||||||
|
// power.h
|
||||||
|
batteryChargePercent =
|
||||||
|
clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)),
|
||||||
|
0, 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify any status instances that are observing us
|
||||||
|
const meshtastic::PowerStatus powerStatus = meshtastic::PowerStatus(
|
||||||
|
hasBattery, batteryLevel->isVBUSPlug(), batteryLevel->isChargeing(), batteryVoltageMv, batteryChargePercent);
|
||||||
|
newStatus.notifyObservers(&powerStatus);
|
||||||
|
|
||||||
|
// If we have a battery at all and it is less than 10% full, force deep sleep
|
||||||
|
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
|
||||||
|
powerFSM.trigger(EVENT_LOW_BATTERY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify any status instances that are observing us
|
|
||||||
const meshtastic::PowerStatus powerStatus = meshtastic::PowerStatus(hasBattery, axp.isVBUSPlug(), axp.isChargeing(), batteryVoltageMv, batteryChargePercent);
|
|
||||||
newStatus.notifyObservers(&powerStatus);
|
|
||||||
|
|
||||||
// If we have a battery at all and it is less than 10% full, force deep sleep
|
|
||||||
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() &&
|
|
||||||
axp.getBattVoltage() < MIN_BAT_MILLIVOLTS)
|
|
||||||
powerFSM.trigger(EVENT_LOW_BATTERY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Power::doTask()
|
void Power::doTask()
|
||||||
@@ -59,12 +129,10 @@ void Power::doTask()
|
|||||||
readPowerStatus();
|
readPowerStatus();
|
||||||
|
|
||||||
// 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
|
||||||
if(statusHandler && statusHandler->isInitialized())
|
if (statusHandler && statusHandler->isInitialized())
|
||||||
setPeriod(1000 * 20);
|
setPeriod(1000 * 20);
|
||||||
}
|
}
|
||||||
#endif // TBEAM_V10
|
|
||||||
|
|
||||||
#ifdef AXP192_SLAVE_ADDRESS
|
|
||||||
/**
|
/**
|
||||||
* Init the power manager chip
|
* Init the power manager chip
|
||||||
*
|
*
|
||||||
@@ -74,10 +142,13 @@ void Power::doTask()
|
|||||||
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
|
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
|
||||||
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
|
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
|
||||||
*/
|
*/
|
||||||
void Power::axp192Init()
|
bool Power::axp192Init()
|
||||||
{
|
{
|
||||||
|
#ifdef TBEAM_V10
|
||||||
if (axp192_found) {
|
if (axp192_found) {
|
||||||
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
|
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
|
||||||
|
batteryLevel = &axp;
|
||||||
|
|
||||||
DEBUG_MSG("AXP192 Begin PASS\n");
|
DEBUG_MSG("AXP192 Begin PASS\n");
|
||||||
|
|
||||||
// axp.setChgLEDMode(LED_BLINK_4HZ);
|
// axp.setChgLEDMode(LED_BLINK_4HZ);
|
||||||
@@ -135,12 +206,15 @@ void Power::axp192Init()
|
|||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("AXP192 not found\n");
|
DEBUG_MSG("AXP192 not found\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return axp192_found;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void Power::loop()
|
void Power::loop()
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef PMU_IRQ
|
#ifdef PMU_IRQ
|
||||||
if (pmu_irq) {
|
if (pmu_irq) {
|
||||||
pmu_irq = false;
|
pmu_irq = false;
|
||||||
@@ -174,6 +248,5 @@ void Power::loop()
|
|||||||
axp.clearIRQ();
|
axp.clearIRQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // T_BEAM_V10
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace meshtastic
|
|||||||
CallbackObserver<Status, const Status *> statusObserver = CallbackObserver<Status, const Status *>(this, &Status::updateStatus);
|
CallbackObserver<Status, const Status *> statusObserver = CallbackObserver<Status, const Status *>(this, &Status::updateStatus);
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
// Workaround for no typeid support
|
// Workaround for no typeid support
|
||||||
int statusType;
|
int statusType = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Allows us to generate observable events
|
// Allows us to generate observable events
|
||||||
|
|||||||
339
src/User_Setup.h
Normal file
339
src/User_Setup.h
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
// This file is used to set TFT/eInk preferences for the TFT.cpp driver
|
||||||
|
|
||||||
|
#include <variant.h>
|
||||||
|
|
||||||
|
// USER DEFINED SETTINGS
|
||||||
|
// Set driver type, fonts to be loaded, pins used and SPI control method etc
|
||||||
|
//
|
||||||
|
// See the User_Setup_Select.h file if you wish to be able to define multiple
|
||||||
|
// setups and then easily select which setup file is used by the compiler.
|
||||||
|
//
|
||||||
|
// If this file is edited correctly then all the library example sketches should
|
||||||
|
// run without the need to make any more changes for a particular hardware setup!
|
||||||
|
// Note that some sketches are designed for a particular TFT pixel width/height
|
||||||
|
|
||||||
|
|
||||||
|
// ##################################################################################
|
||||||
|
//
|
||||||
|
// Section 1. Call up the right driver file and any options for it
|
||||||
|
//
|
||||||
|
// ##################################################################################
|
||||||
|
|
||||||
|
// Define STM32 to invoke optimised processor support (only for STM32)
|
||||||
|
//#define STM32
|
||||||
|
|
||||||
|
// Defining the STM32 board allows the library to optimise the performance
|
||||||
|
// for UNO compatible "MCUfriend" style shields
|
||||||
|
//#define NUCLEO_64_TFT
|
||||||
|
//#define NUCLEO_144_TFT
|
||||||
|
|
||||||
|
// STM32 8 bit parallel only:
|
||||||
|
// If STN32 Port A or B pins 0-7 are used for 8 bit parallel data bus bits 0-7
|
||||||
|
// then this will improve rendering performance by a factor of ~8x
|
||||||
|
//#define STM_PORTA_DATA_BUS
|
||||||
|
//#define STM_PORTA_DATA_BUS
|
||||||
|
|
||||||
|
// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed)
|
||||||
|
//#define TFT_PARALLEL_8_BIT
|
||||||
|
|
||||||
|
// Display type - only define if RPi display
|
||||||
|
//#define RPI_DISPLAY_TYPE // 20MHz maximum SPI
|
||||||
|
|
||||||
|
// Only define one driver, the other ones must be commented out
|
||||||
|
//#define ILI9341_DRIVER
|
||||||
|
#define ST7735_DRIVER // Define additional parameters below for this display
|
||||||
|
//#define ILI9163_DRIVER // Define additional parameters below for this display
|
||||||
|
//#define S6D02A1_DRIVER
|
||||||
|
//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
|
||||||
|
//#define HX8357D_DRIVER
|
||||||
|
//#define ILI9481_DRIVER
|
||||||
|
//#define ILI9486_DRIVER
|
||||||
|
//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
|
||||||
|
//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
|
||||||
|
//#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
|
||||||
|
//#define R61581_DRIVER
|
||||||
|
//#define RM68140_DRIVER
|
||||||
|
//#define ST7796_DRIVER
|
||||||
|
//#define SSD1963_480_DRIVER // Untested
|
||||||
|
//#define SSD1963_800_DRIVER // Untested
|
||||||
|
//#define SSD1963_800ALT_DRIVER // Untested
|
||||||
|
|
||||||
|
// Some displays support SPI reads via the MISO pin, other displays have a single
|
||||||
|
// bi-directional SDA pin and the library will try to read this via the MOSI line.
|
||||||
|
// To use the SDA line for reading data from the TFT uncomment the following line:
|
||||||
|
|
||||||
|
// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 display only
|
||||||
|
|
||||||
|
// For ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display
|
||||||
|
// Try ONE option at a time to find the correct colour order for your display
|
||||||
|
|
||||||
|
// #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
|
||||||
|
// #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
|
||||||
|
|
||||||
|
// For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below
|
||||||
|
|
||||||
|
// #define M5STACK
|
||||||
|
|
||||||
|
// For ST7789, ST7735 and ILI9163 ONLY, define the pixel width and height in portrait orientation
|
||||||
|
#define TFT_WIDTH 80
|
||||||
|
// #define TFT_WIDTH 128
|
||||||
|
// #define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
|
||||||
|
#define TFT_HEIGHT 160
|
||||||
|
// #define TFT_HEIGHT 128
|
||||||
|
// #define TFT_HEIGHT 240 // ST7789 240 x 240
|
||||||
|
// #define TFT_HEIGHT 320 // ST7789 240 x 320
|
||||||
|
|
||||||
|
// For ST7735 ONLY, define the type of display, originally this was based on the
|
||||||
|
// colour of the tab on the screen protector film but this is not always true, so try
|
||||||
|
// out the different options below if the screen does not display graphics correctly,
|
||||||
|
// e.g. colours wrong, mirror images, or tray pixels at the edges.
|
||||||
|
// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this
|
||||||
|
// this User_Setup file, then rebuild and upload the sketch to the board again:
|
||||||
|
|
||||||
|
// #define ST7735_INITB
|
||||||
|
#define ST7735_GREENTAB
|
||||||
|
// #define ST7735_GREENTAB2
|
||||||
|
// #define ST7735_GREENTAB3
|
||||||
|
// #define ST7735_GREENTAB128 // For 128 x 128 display
|
||||||
|
// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset)
|
||||||
|
// #define ST7735_REDTAB
|
||||||
|
// #define ST7735_BLACKTAB
|
||||||
|
// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset
|
||||||
|
|
||||||
|
// If colours are inverted (white shows as black) then uncomment one of the next
|
||||||
|
// 2 lines try both options, one of the options should correct the inversion.
|
||||||
|
|
||||||
|
// #define TFT_INVERSION_ON
|
||||||
|
// #define TFT_INVERSION_OFF
|
||||||
|
|
||||||
|
|
||||||
|
// ##################################################################################
|
||||||
|
//
|
||||||
|
// Section 2. Define the pins that are used to interface with the display here
|
||||||
|
//
|
||||||
|
// ##################################################################################
|
||||||
|
|
||||||
|
// If a backlight control signal is available then define the TFT_BL pin in Section 2
|
||||||
|
// below. The backlight will be turned ON when tft.begin() is called, but the library
|
||||||
|
// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be
|
||||||
|
// driven with a PWM signal or turned OFF/ON then this must be handled by the user
|
||||||
|
// sketch. e.g. with digitalWrite(TFT_BL, LOW);
|
||||||
|
|
||||||
|
#define TFT_BL ST7735_BACKLIGHT_EN // LED back-light control pin
|
||||||
|
#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// We must use hardware SPI, a minimum of 3 GPIO pins is needed.
|
||||||
|
// Typical setup for ESP8266 NodeMCU ESP-12 is :
|
||||||
|
//
|
||||||
|
// Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT)
|
||||||
|
// Display LED to NodeMCU pin VIN (or 5V, see below)
|
||||||
|
// Display SCK to NodeMCU pin D5
|
||||||
|
// Display SDI/MOSI to NodeMCU pin D7
|
||||||
|
// Display DC (RS/AO)to NodeMCU pin D3
|
||||||
|
// Display RESET to NodeMCU pin D4 (or RST, see below)
|
||||||
|
// Display CS to NodeMCU pin D8 (or GND, see below)
|
||||||
|
// Display GND to NodeMCU pin GND (0V)
|
||||||
|
// Display VCC to NodeMCU 5V or 3.3V
|
||||||
|
//
|
||||||
|
// The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin
|
||||||
|
//
|
||||||
|
// The DC (Data Command) pin may be labeled AO or RS (Register Select)
|
||||||
|
//
|
||||||
|
// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more
|
||||||
|
// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS
|
||||||
|
// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin
|
||||||
|
// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected.
|
||||||
|
//
|
||||||
|
// The NodeMCU D0 pin can be used for RST
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin
|
||||||
|
// If 5V is not available at a pin you can use 3.3V but backlight brightness
|
||||||
|
// will be lower.
|
||||||
|
|
||||||
|
|
||||||
|
// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ######
|
||||||
|
|
||||||
|
// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
|
||||||
|
#define TFT_CS ST7735_CS // Chip select control pin D8
|
||||||
|
#define TFT_DC ST7735_RS // Data Command control pin
|
||||||
|
#define TFT_RST ST7735_RESET // Reset pin (could connect to NodeMCU RST, see next line)
|
||||||
|
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
|
||||||
|
|
||||||
|
//#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin)
|
||||||
|
|
||||||
|
//#define TOUCH_CS PIN_D2 // Chip select pin (T_CS) of touch screen
|
||||||
|
|
||||||
|
//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
|
||||||
|
|
||||||
|
|
||||||
|
// ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ######
|
||||||
|
|
||||||
|
// Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact
|
||||||
|
// but saves pins for other functions. It is best not to connect MISO as some displays
|
||||||
|
// do not tristate that line wjen chip select is high!
|
||||||
|
// On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode
|
||||||
|
// On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK
|
||||||
|
// In ESP8266 overlap mode the following must be defined
|
||||||
|
|
||||||
|
//#define TFT_SPI_OVERLAP
|
||||||
|
|
||||||
|
// In ESP8266 overlap mode the TFT chip select MUST connect to pin D3
|
||||||
|
//#define TFT_CS PIN_D3
|
||||||
|
//#define TFT_DC PIN_D5 // Data Command control pin
|
||||||
|
//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
|
||||||
|
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
|
||||||
|
|
||||||
|
|
||||||
|
// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ######
|
||||||
|
|
||||||
|
// For ESP32 Dev board (only tested with ILI9341 display)
|
||||||
|
// The hardware SPI can be mapped to any pins
|
||||||
|
|
||||||
|
//#define TFT_MISO 19
|
||||||
|
//#define TFT_MOSI 23
|
||||||
|
//#define TFT_SCLK 18
|
||||||
|
//#define TFT_CS 15 // Chip select control pin
|
||||||
|
//#define TFT_DC 2 // Data Command control pin
|
||||||
|
//#define TFT_RST 4 // Reset pin (could connect to RST pin)
|
||||||
|
//#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
|
||||||
|
|
||||||
|
//#define TOUCH_CS 21 // Chip select pin (T_CS) of touch screen
|
||||||
|
|
||||||
|
//#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only
|
||||||
|
|
||||||
|
// For the M5Stack module use these #define lines
|
||||||
|
//#define TFT_MISO 19
|
||||||
|
//#define TFT_MOSI 23
|
||||||
|
//#define TFT_SCLK 18
|
||||||
|
//#define TFT_CS 14 // Chip select control pin
|
||||||
|
//#define TFT_DC 27 // Data Command control pin
|
||||||
|
//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
|
||||||
|
//#define TFT_BL 32 // LED back-light (required for M5Stack)
|
||||||
|
|
||||||
|
// ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ######
|
||||||
|
|
||||||
|
// The library supports 8 bit parallel TFTs with the ESP32, the pin
|
||||||
|
// selection below is compatible with ESP32 boards in UNO format.
|
||||||
|
// Wemos D32 boards need to be modified, see diagram in Tools folder.
|
||||||
|
// Only ILI9481 and ILI9341 based displays have been tested!
|
||||||
|
|
||||||
|
// Parallel bus is only supported for the STM32 and ESP32
|
||||||
|
// Example below is for ESP32 Parallel interface with UNO displays
|
||||||
|
|
||||||
|
// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed)
|
||||||
|
//#define TFT_PARALLEL_8_BIT
|
||||||
|
|
||||||
|
// The ESP32 and TFT the pins used for testing are:
|
||||||
|
//#define TFT_CS 33 // Chip select control pin (library pulls permanently low
|
||||||
|
//#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31
|
||||||
|
//#define TFT_RST 32 // Reset pin, toggles on startup
|
||||||
|
|
||||||
|
//#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31
|
||||||
|
//#define TFT_RD 2 // Read strobe control pin
|
||||||
|
|
||||||
|
//#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus
|
||||||
|
//#define TFT_D1 13 // so a single register write sets/clears all bits.
|
||||||
|
//#define TFT_D2 26 // Pins can be randomly assigned, this does not affect
|
||||||
|
//#define TFT_D3 25 // TFT screen update performance.
|
||||||
|
//#define TFT_D4 17
|
||||||
|
//#define TFT_D5 16
|
||||||
|
//#define TFT_D6 27
|
||||||
|
//#define TFT_D7 14
|
||||||
|
|
||||||
|
// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ######
|
||||||
|
|
||||||
|
// The TFT can be connected to SPI port 1 or 2
|
||||||
|
//#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz
|
||||||
|
//#define TFT_MOSI PA7
|
||||||
|
//#define TFT_MISO PA6
|
||||||
|
//#define TFT_SCLK PA5
|
||||||
|
|
||||||
|
//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz
|
||||||
|
//#define TFT_MOSI PB15
|
||||||
|
//#define TFT_MISO PB14
|
||||||
|
//#define TFT_SCLK PB13
|
||||||
|
|
||||||
|
// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select
|
||||||
|
//#define TFT_CS D5 // Chip select control pin to TFT CS
|
||||||
|
//#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
|
||||||
|
//#define TFT_RST D7 // Reset pin to TFT RST (or RESET)
|
||||||
|
// OR alternatively, we can use STM32 port reference names PXnn
|
||||||
|
//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5
|
||||||
|
//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6
|
||||||
|
//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7
|
||||||
|
|
||||||
|
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset
|
||||||
|
// Use an Arduino pin for initial testing as connecting to processor reset
|
||||||
|
// may not work (pulse too short at power up?)
|
||||||
|
|
||||||
|
// ##################################################################################
|
||||||
|
//
|
||||||
|
// Section 3. Define the fonts that are to be used here
|
||||||
|
//
|
||||||
|
// ##################################################################################
|
||||||
|
|
||||||
|
// Comment out the #defines below with // to stop that font being loaded
|
||||||
|
// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
|
||||||
|
// normally necessary. If all fonts are loaded the extra FLASH space required is
|
||||||
|
// about 17Kbytes. To save FLASH space only enable the fonts you need!
|
||||||
|
|
||||||
|
//#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
|
||||||
|
//#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
|
||||||
|
//#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
|
||||||
|
//#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
|
||||||
|
//#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
|
||||||
|
//#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
|
||||||
|
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
|
||||||
|
//#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
|
||||||
|
|
||||||
|
// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
|
||||||
|
// this will save ~20kbytes of FLASH
|
||||||
|
//#define SMOOTH_FONT
|
||||||
|
|
||||||
|
|
||||||
|
// ##################################################################################
|
||||||
|
//
|
||||||
|
// Section 4. Other options
|
||||||
|
//
|
||||||
|
// ##################################################################################
|
||||||
|
|
||||||
|
// Define the SPI clock frequency, this affects the graphics rendering speed. Too
|
||||||
|
// fast and the TFT driver will not keep up and display corruption appears.
|
||||||
|
// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
|
||||||
|
// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
|
||||||
|
// With an ILI9163 display 27 MHz works OK.
|
||||||
|
|
||||||
|
// #define SPI_FREQUENCY 1000000
|
||||||
|
// #define SPI_FREQUENCY 5000000
|
||||||
|
// #define SPI_FREQUENCY 10000000
|
||||||
|
// #define SPI_FREQUENCY 20000000
|
||||||
|
#define SPI_FREQUENCY 27000000
|
||||||
|
// #define SPI_FREQUENCY 40000000
|
||||||
|
// #define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
|
||||||
|
// #define SPI_FREQUENCY 80000000
|
||||||
|
|
||||||
|
// Optional reduced SPI frequency for reading TFT
|
||||||
|
#define SPI_READ_FREQUENCY 20000000
|
||||||
|
|
||||||
|
// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
|
||||||
|
#define SPI_TOUCH_FREQUENCY 2500000
|
||||||
|
|
||||||
|
// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
|
||||||
|
// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
|
||||||
|
// then uncomment the following line:
|
||||||
|
//#define USE_HSPI_PORT
|
||||||
|
|
||||||
|
// Comment out the following #define if "SPI Transactions" do not need to be
|
||||||
|
// supported. When commented out the code size will be smaller and sketches will
|
||||||
|
// run slightly faster, so leave it commented out unless you need it!
|
||||||
|
|
||||||
|
// Transaction support is needed to work with SD library but not needed with TFT_SdFat
|
||||||
|
// Transaction support is required if other SPI devices are connected.
|
||||||
|
|
||||||
|
// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
|
||||||
|
// so changing it here has no effect
|
||||||
|
|
||||||
|
// #define SUPPORT_TRANSACTIONS
|
||||||
@@ -158,16 +158,29 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define BUTTON_PIN 38 // The middle button GPIO on the T-Beam
|
#define BUTTON_PIN 38 // The middle button GPIO on the T-Beam
|
||||||
#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed
|
#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed
|
||||||
|
|
||||||
#ifndef USE_JTAG
|
// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
|
||||||
#define RF95_RESET 14
|
// not found then probe for SX1262
|
||||||
|
#define USE_RF95
|
||||||
|
#define USE_SX1262
|
||||||
|
|
||||||
|
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||||
|
#define LORA_RESET 23
|
||||||
|
#define LORA_DIO1 33 // SX1262 IRQ
|
||||||
|
#define LORA_DIO2 32 // SX1262 BUSY
|
||||||
|
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||||
|
|
||||||
|
#ifdef USE_SX1262
|
||||||
|
#define SX1262_CS RF95_NSS // FIXME - we really should define LORA_CS instead
|
||||||
|
#define SX1262_DIO1 LORA_DIO1
|
||||||
|
#define SX1262_BUSY LORA_DIO2
|
||||||
|
#define SX1262_RESET LORA_RESET
|
||||||
|
#define SX1262_E22 // Not really an E22 but TTGO seems to be trying to clone that
|
||||||
|
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
|
||||||
|
// code)
|
||||||
#endif
|
#endif
|
||||||
#define RF95_IRQ 26
|
|
||||||
#define RF95_DIO1 33 // Note: not really used on this board
|
|
||||||
#define RF95_DIO2 32 // Note: not really used on this board
|
|
||||||
|
|
||||||
// Leave undefined to disable our PMU IRQ handler
|
// Leave undefined to disable our PMU IRQ handler
|
||||||
#define PMU_IRQ 35
|
#define PMU_IRQ 35
|
||||||
|
|
||||||
#define AXP192_SLAVE_ADDRESS 0x34
|
#define AXP192_SLAVE_ADDRESS 0x34
|
||||||
|
|
||||||
#elif defined(TBEAM_V07)
|
#elif defined(TBEAM_V07)
|
||||||
@@ -180,13 +193,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define I2C_SCL 22
|
#define I2C_SCL 22
|
||||||
|
|
||||||
#define BUTTON_PIN 39
|
#define BUTTON_PIN 39
|
||||||
|
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||||
|
|
||||||
#ifndef USE_JTAG
|
#define USE_RF95
|
||||||
#define RF95_RESET 23
|
|
||||||
#endif
|
#define USE_RF95
|
||||||
#define RF95_IRQ 26
|
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||||
#define RF95_DIO1 33 // Note: not really used on this board
|
#define LORA_RESET 23
|
||||||
#define RF95_DIO2 32 // Note: not really used on this board
|
#define LORA_DIO1 33 // Not really used
|
||||||
|
#define LORA_DIO2 32 // Not really used
|
||||||
|
|
||||||
// This board has different GPS pins than all other boards
|
// This board has different GPS pins than all other boards
|
||||||
#undef GPS_RX_PIN
|
#undef GPS_RX_PIN
|
||||||
@@ -216,12 +231,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define LED_PIN 25 // If defined we will blink this LED
|
#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
|
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
|
||||||
|
|
||||||
|
#define USE_RF95
|
||||||
|
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||||
#ifndef USE_JTAG
|
#ifndef USE_JTAG
|
||||||
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
|
#define LORA_RESET 14
|
||||||
#endif
|
#endif
|
||||||
#define RF95_IRQ 26
|
#define LORA_DIO1 35 // Not really used
|
||||||
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
#define LORA_DIO2 34 // Not really used
|
||||||
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
|
||||||
#elif defined(TLORA_V1)
|
#elif defined(TLORA_V1)
|
||||||
// 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 "tlora-v1"
|
#define HW_VENDOR "tlora-v1"
|
||||||
@@ -239,10 +256,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define LED_PIN 2 // If defined we will blink this LED
|
#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 BUTTON_PIN 0 // If defined, this will be used for user button presses
|
||||||
|
|
||||||
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
|
#define USE_RF95
|
||||||
#define RF95_IRQ 26 // IRQ line for the LORA radio
|
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||||
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
#define LORA_RESET 14
|
||||||
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
#define LORA_DIO1 35 // Not really used
|
||||||
|
#define LORA_DIO2 34 // Not really used
|
||||||
|
|
||||||
#elif defined(TLORA_V2)
|
#elif defined(TLORA_V2)
|
||||||
// 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
|
||||||
@@ -264,10 +282,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
0 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
|
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
|
// between this pin and ground
|
||||||
|
|
||||||
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
|
#define USE_RF95
|
||||||
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
|
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||||
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
#define LORA_RESET 14
|
||||||
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
#define LORA_DIO1 35 // Not really used
|
||||||
|
#define LORA_DIO2 34 // Not really used
|
||||||
|
|
||||||
#elif defined(TLORA_V2_1_16)
|
#elif defined(TLORA_V2_1_16)
|
||||||
// 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
|
||||||
@@ -278,6 +297,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define GPS_RX_PIN 36
|
#define GPS_RX_PIN 36
|
||||||
#define GPS_TX_PIN 39
|
#define GPS_TX_PIN 39
|
||||||
|
|
||||||
|
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||||
|
|
||||||
#define I2C_SDA 21 // I2C pins for this board
|
#define I2C_SDA 21 // I2C pins for this board
|
||||||
#define I2C_SCL 22
|
#define I2C_SCL 22
|
||||||
|
|
||||||
@@ -289,10 +310,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
12 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
|
12 // 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
|
// between this pin and ground
|
||||||
|
|
||||||
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
|
#define USE_RF95
|
||||||
#define RF95_IRQ 26 // IRQ line for the LORA radio
|
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||||
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
#define LORA_RESET 14
|
||||||
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
|
#define LORA_DIO1 35 // Not really used
|
||||||
|
#define LORA_DIO2 34 // Not really used
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARDUINO_NRF52840_PCA10056
|
#ifdef ARDUINO_NRF52840_PCA10056
|
||||||
@@ -314,6 +337,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_RF95
|
||||||
|
#define RF95_RESET LORA_RESET
|
||||||
|
#define RF95_IRQ LORA_DIO0 // on SX1262 version this is a no connect DIO0
|
||||||
|
#define RF95_DIO1 LORA_DIO1 // Note: not really used for RF95
|
||||||
|
#define RF95_DIO2 LORA_DIO2 // Note: not really used for RF95
|
||||||
|
#endif
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// DEBUG
|
// DEBUG
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -337,8 +367,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
// Debug printing to segger console
|
// Debug printing to segger console
|
||||||
#define SEGGER_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
#define SEGGER_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||||
|
|
||||||
// nrf52 gets its settings via variant files
|
// If we are not on a NRF52840 (which has built in USB-ACM serial support) and we don't have serial pins hooked up, then we MUST
|
||||||
#ifndef PIN_SERIAL_RX
|
// use SEGGER for debug output
|
||||||
|
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
|
||||||
// No serial ports on this board - ONLY use segger in memory console
|
// No serial ports on this board - ONLY use segger in memory console
|
||||||
#define USE_SEGGER
|
#define USE_SEGGER
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ void readFromRTC();
|
|||||||
*
|
*
|
||||||
* When new data is available it will notify observers.
|
* When new data is available it will notify observers.
|
||||||
*/
|
*/
|
||||||
class GPS : public Observable<void *>
|
class GPS
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
bool hasValidLocation = false; // default to false, until we complete our first read
|
bool hasValidLocation = false; // default to false, until we complete our first read
|
||||||
@@ -48,6 +48,7 @@ class GPS : public Observable<void *>
|
|||||||
|
|
||||||
virtual ~GPS() {}
|
virtual ~GPS() {}
|
||||||
|
|
||||||
|
/** We will notify this observable anytime GPS state has changed meaningfully */
|
||||||
Observable<const meshtastic::GPSStatus *> newStatus;
|
Observable<const meshtastic::GPSStatus *> newStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -66,10 +66,6 @@ void NEMAGPS::loop()
|
|||||||
|
|
||||||
// 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 NEMA GPS pos lat=%f, lon=%f, alt=%d, hdop=%f, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2, heading * 1e-5);
|
DEBUG_MSG("new NEMA GPS pos lat=%f, lon=%f, alt=%d, hdop=%f, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2, heading * 1e-5);
|
||||||
|
|
||||||
hasValidLocation = (latitude != 0) || (longitude != 0); // bogus lat lon is reported as 0,0
|
|
||||||
if (hasValidLocation)
|
|
||||||
notifyObservers(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify any status instances that are observing us
|
// Notify any status instances that are observing us
|
||||||
|
|||||||
@@ -52,39 +52,7 @@ bool UBloxGPS::setup()
|
|||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
||||||
|
|
||||||
bool factoryReset = false;
|
if (!setUBXMode())
|
||||||
bool ok;
|
|
||||||
if (factoryReset) {
|
|
||||||
// It is useful to force back into factory defaults (9600baud, NEMA to test the behavior of boards that don't have
|
|
||||||
// GPS_TX connected)
|
|
||||||
ublox.factoryReset();
|
|
||||||
delay(3000);
|
|
||||||
tryConnect();
|
|
||||||
DEBUG_MSG("Factory reset success=%d\n", isConnected);
|
|
||||||
ok = ublox.saveConfiguration(3000);
|
|
||||||
assert(ok);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
if (_serial_gps) {
|
|
||||||
ok = ublox.setUART1Output(COM_TYPE_UBX, 500); // Use native API
|
|
||||||
assert(ok);
|
|
||||||
}
|
|
||||||
if (i2cAddress) {
|
|
||||||
ok = ublox.setI2COutput(COM_TYPE_UBX, 500);
|
|
||||||
assert(ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = ublox.setNavigationFrequency(1, 500); // Produce 4x/sec to keep the amount of time we stall in getPVT low
|
|
||||||
assert(ok);
|
|
||||||
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
|
|
||||||
// assert(ok);
|
|
||||||
// ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds
|
|
||||||
// assert(ok);
|
|
||||||
ok = ublox.powerSaveMode(true, 2000); // use power save mode, the default timeout (1100ms seems a bit too tight)
|
|
||||||
assert(ok);
|
|
||||||
}
|
|
||||||
ok = ublox.saveConfiguration(3000);
|
|
||||||
if (!ok)
|
|
||||||
recordCriticalError(UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
recordCriticalError(UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
||||||
|
|
||||||
concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
|
concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
|
||||||
@@ -95,6 +63,59 @@ bool UBloxGPS::setup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UBloxGPS::setUBXMode()
|
||||||
|
{
|
||||||
|
if (_serial_gps) {
|
||||||
|
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (i2cAddress) {
|
||||||
|
if (!ublox.setI2COutput(COM_TYPE_UBX, 1000))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ublox.setNavigationFrequency(1, 1000)) // Produce 4x/sec to keep the amount of time we stall in getPVT low
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
|
||||||
|
// assert(ok);
|
||||||
|
// ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds
|
||||||
|
// assert(ok);
|
||||||
|
if (!ublox.powerSaveMode(true, 2000)) // use power save mode, the default timeout (1100ms seems a bit too tight)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ublox.saveConfiguration(3000))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset our GPS back to factory settings
|
||||||
|
*
|
||||||
|
* @return true for success
|
||||||
|
*/
|
||||||
|
bool UBloxGPS::factoryReset()
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
// It is useful to force back into factory defaults (9600baud, NEMA to test the behavior of boards that don't have
|
||||||
|
// GPS_TX connected)
|
||||||
|
ublox.factoryReset();
|
||||||
|
delay(5000);
|
||||||
|
tryConnect(); // sets isConnected
|
||||||
|
|
||||||
|
// try a second time, the ublox lib serial parsing is buggy?
|
||||||
|
if (!tryConnect())
|
||||||
|
tryConnect();
|
||||||
|
|
||||||
|
DEBUG_MSG("GPS Factory reset success=%d\n", isConnected);
|
||||||
|
if (isConnected)
|
||||||
|
ok = setUBXMode();
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
||||||
int UBloxGPS::prepareSleep(void *unused)
|
int UBloxGPS::prepareSleep(void *unused)
|
||||||
{
|
{
|
||||||
@@ -106,73 +127,72 @@ int UBloxGPS::prepareSleep(void *unused)
|
|||||||
|
|
||||||
void UBloxGPS::doTask()
|
void UBloxGPS::doTask()
|
||||||
{
|
{
|
||||||
uint8_t fixtype = 3; // If we are only using the RX pin, assume we have a 3d fix
|
if (isConnected) {
|
||||||
|
// Consume all characters that have arrived
|
||||||
|
|
||||||
assert(isConnected);
|
uint8_t fixtype = 3; // If we are only using the RX pin, assume we have a 3d fix
|
||||||
|
|
||||||
// Consume all characters that have arrived
|
// if using i2c or serial look too see if any chars are ready
|
||||||
|
ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
|
||||||
|
|
||||||
// if using i2c or serial look too see if any chars are ready
|
// If we don't have a fix (a quick check), don't try waiting for a solution)
|
||||||
ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
|
// Hmmm my fix type reading returns zeros for fix, which doesn't seem correct, because it is still sptting out positions
|
||||||
|
// turn off for now
|
||||||
|
uint16_t maxWait = i2cAddress ? 300 : 0; // If using i2c we must poll with wait
|
||||||
|
fixtype = ublox.getFixType(maxWait);
|
||||||
|
DEBUG_MSG("GPS fix type %d\n", fixtype);
|
||||||
|
|
||||||
// If we don't have a fix (a quick check), don't try waiting for a solution)
|
// DEBUG_MSG("sec %d\n", ublox.getSecond());
|
||||||
// Hmmm my fix type reading returns zeros for fix, which doesn't seem correct, because it is still sptting out positions
|
// DEBUG_MSG("lat %d\n", ublox.getLatitude());
|
||||||
// turn off for now
|
|
||||||
uint16_t maxWait = i2cAddress ? 300 : 0; // If using i2c we must poll with wait
|
|
||||||
fixtype = ublox.getFixType(maxWait);
|
|
||||||
DEBUG_MSG("GPS fix type %d\n", fixtype);
|
|
||||||
|
|
||||||
// DEBUG_MSG("sec %d\n", ublox.getSecond());
|
// any fix that has time
|
||||||
// DEBUG_MSG("lat %d\n", ublox.getLatitude());
|
|
||||||
|
|
||||||
// any fix that has time
|
if (ublox.getT(maxWait)) {
|
||||||
|
/* 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 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
|
||||||
|
*/
|
||||||
|
struct tm t;
|
||||||
|
t.tm_sec = ublox.getSecond(0);
|
||||||
|
t.tm_min = ublox.getMinute(0);
|
||||||
|
t.tm_hour = ublox.getHour(0);
|
||||||
|
t.tm_mday = ublox.getDay(0);
|
||||||
|
t.tm_mon = ublox.getMonth(0) - 1;
|
||||||
|
t.tm_year = ublox.getYear(0) - 1900;
|
||||||
|
t.tm_isdst = false;
|
||||||
|
perhapsSetRTC(t);
|
||||||
|
}
|
||||||
|
|
||||||
if (ublox.getT(maxWait)) {
|
latitude = ublox.getLatitude(0);
|
||||||
/* Convert to unix time
|
longitude = ublox.getLongitude(0);
|
||||||
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970
|
altitude = ublox.getAltitude(0) / 1000; // in mm convert to meters
|
||||||
(midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
|
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
|
||||||
*/
|
heading = ublox.getHeading(0);
|
||||||
struct tm t;
|
numSatellites = ublox.getSIV(0);
|
||||||
t.tm_sec = ublox.getSecond(0);
|
|
||||||
t.tm_min = ublox.getMinute(0);
|
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
||||||
t.tm_hour = ublox.getHour(0);
|
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
||||||
t.tm_mday = ublox.getDay(0);
|
hasValidLocation =
|
||||||
t.tm_mon = ublox.getMonth(0) - 1;
|
(latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0);
|
||||||
t.tm_year = ublox.getYear(0) - 1900;
|
|
||||||
t.tm_isdst = false;
|
// we only notify if position has changed due to a new fix
|
||||||
perhapsSetRTC(t);
|
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
|
||||||
|
{
|
||||||
|
if (hasValidLocation) {
|
||||||
|
wantNewLocation = false;
|
||||||
|
// ublox.powerOff();
|
||||||
|
}
|
||||||
|
} else // we didn't get a location update, go back to sleep and hope the characters show up
|
||||||
|
wantNewLocation = true;
|
||||||
|
|
||||||
|
// Notify any status instances that are observing us
|
||||||
|
const meshtastic::GPSStatus status =
|
||||||
|
meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
|
||||||
|
newStatus.notifyObservers(&status);
|
||||||
}
|
}
|
||||||
|
|
||||||
latitude = ublox.getLatitude(0);
|
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 10s until we have something
|
||||||
longitude = ublox.getLongitude(0);
|
// over the serial
|
||||||
altitude = ublox.getAltitude(0) / 1000; // in mm convert to meters
|
|
||||||
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
|
|
||||||
heading = ublox.getHeading(0);
|
|
||||||
numSatellites = ublox.getSIV(0);
|
|
||||||
|
|
||||||
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
|
||||||
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
|
||||||
hasValidLocation =
|
|
||||||
(latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0);
|
|
||||||
|
|
||||||
// we only notify if position has changed due to a new fix
|
|
||||||
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
|
|
||||||
{
|
|
||||||
if (hasValidLocation) {
|
|
||||||
wantNewLocation = false;
|
|
||||||
notifyObservers(NULL);
|
|
||||||
// ublox.powerOff();
|
|
||||||
}
|
|
||||||
} else // we didn't get a location update, go back to sleep and hope the characters show up
|
|
||||||
wantNewLocation = true;
|
|
||||||
|
|
||||||
// Notify any status instances that are observing us
|
|
||||||
const meshtastic::GPSStatus status =
|
|
||||||
meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
|
|
||||||
newStatus.notifyObservers(&status);
|
|
||||||
|
|
||||||
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 1s until we have something over
|
|
||||||
// the serial
|
|
||||||
setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 10 * 1000);
|
setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 10 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../concurrency/PeriodicTask.h"
|
||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
#include "../concurrency/PeriodicTask.h"
|
|
||||||
#include "SparkFun_Ublox_Arduino_Library.h"
|
#include "SparkFun_Ublox_Arduino_Library.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,12 +33,22 @@ class UBloxGPS : public GPS, public concurrency::PeriodicTask
|
|||||||
* called after the CPU wakes from light-sleep state */
|
* called after the CPU wakes from light-sleep state */
|
||||||
virtual void startLock();
|
virtual void startLock();
|
||||||
|
|
||||||
private:
|
/**
|
||||||
|
* Reset our GPS back to factory settings
|
||||||
|
*
|
||||||
|
* @return true for success
|
||||||
|
*/
|
||||||
|
bool factoryReset();
|
||||||
|
|
||||||
|
private:
|
||||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
||||||
/// always returns 0 to indicate okay to sleep
|
/// always returns 0 to indicate okay to sleep
|
||||||
int prepareSleep(void *unused);
|
int prepareSleep(void *unused);
|
||||||
|
|
||||||
/// Attempt to connect to our GPS, returns false if no gps is present
|
/// Attempt to connect to our GPS, returns false if no gps is present
|
||||||
bool tryConnect();
|
bool tryConnect();
|
||||||
|
|
||||||
|
/// Switch to our desired operating mode and save the settings to flash
|
||||||
|
/// returns true for success
|
||||||
|
bool setUBXMode();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
|
#include "Screen.h"
|
||||||
|
#include "configs.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "graphics/images.h"
|
#include "graphics/images.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "Screen.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "configs.h"
|
|
||||||
|
|
||||||
using namespace meshtastic; /** @todo remove */
|
using namespace meshtastic; /** @todo remove */
|
||||||
|
|
||||||
@@ -43,10 +43,14 @@ static FrameCallback normalFrames[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
|
|||||||
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
||||||
static char btPIN[16] = "888888";
|
static char btPIN[16] = "888888";
|
||||||
|
|
||||||
uint8_t imgBattery[16] = { 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C };
|
// This image definition is here instead of images.h because it's modified dynamically by the drawBattery function
|
||||||
uint8_t imgSatellite[8] = { 0x70, 0x71, 0x22, 0xFA, 0xFA, 0x22, 0x71, 0x70 };
|
uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C};
|
||||||
|
|
||||||
uint32_t dopThresholds[5] = { 2000, 1000, 500, 200, 100 };
|
// Threshold values for the GPS lock accuracy bar display
|
||||||
|
uint32_t dopThresholds[5] = {2000, 1000, 500, 200, 100};
|
||||||
|
|
||||||
|
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
|
||||||
|
static char ourId[5];
|
||||||
|
|
||||||
#ifdef SHOW_REDRAWS
|
#ifdef SHOW_REDRAWS
|
||||||
static bool heartbeat = false;
|
static bool heartbeat = false;
|
||||||
@@ -116,7 +120,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
|||||||
assert(mp.decoded.which_payload == SubPacket_data_tag);
|
assert(mp.decoded.which_payload == SubPacket_data_tag);
|
||||||
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes);
|
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes);
|
||||||
|
|
||||||
display->drawStringMaxWidth(4 + x, 10 + y, 128, tempBuf);
|
display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw a series of fields in a column, wrapping to multiple colums if needed
|
/// Draw a series of fields in a column, wrapping to multiple colums if needed
|
||||||
@@ -204,37 +208,32 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
|
|||||||
// Draw GPS status summary
|
// Draw GPS status summary
|
||||||
static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||||
{
|
{
|
||||||
if (!gps->getIsConnected())
|
if (!gps->getIsConnected()) {
|
||||||
{
|
|
||||||
display->drawString(x, y - 2, "No GPS");
|
display->drawString(x, y - 2, "No GPS");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty);
|
display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty);
|
||||||
if (!gps->getHasLock())
|
if (!gps->getHasLock()) {
|
||||||
{
|
|
||||||
display->drawString(x + 8, y - 2, "No sats");
|
display->drawString(x + 8, y - 2, "No sats");
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
char satsString[3];
|
char satsString[3];
|
||||||
uint8_t bar[2] = { 0 };
|
uint8_t bar[2] = {0};
|
||||||
|
|
||||||
//Draw DOP signal bars
|
// Draw DOP signal bars
|
||||||
for(int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++) {
|
||||||
{
|
|
||||||
if (gps->getDOP() <= dopThresholds[i])
|
if (gps->getDOP() <= dopThresholds[i])
|
||||||
bar[0] = ~((1 << (5 - i)) - 1);
|
bar[0] = ~((1 << (5 - i)) - 1);
|
||||||
else
|
else
|
||||||
bar[0] = 0b10000000;
|
bar[0] = 0b10000000;
|
||||||
//bar[1] = bar[0];
|
// bar[1] = bar[0];
|
||||||
display->drawFastImage(x + 9 + (i * 2), y, 2, 8, bar);
|
display->drawFastImage(x + 9 + (i * 2), y, 2, 8, bar);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Draw satellite image
|
// Draw satellite image
|
||||||
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, "%d", gps->getNumSatellites());
|
||||||
display->drawString(x + 34, y - 2, satsString);
|
display->drawString(x + 34, y - 2, satsString);
|
||||||
}
|
}
|
||||||
@@ -386,7 +385,6 @@ static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t comp
|
|||||||
float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f;
|
float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f;
|
||||||
Point leftArrow(tip.x - arrowOffsetX, tip.y - arrowOffsetY), rightArrow(tip.x + arrowOffsetX, tip.y - arrowOffsetY);
|
Point leftArrow(tip.x - arrowOffsetX, tip.y - arrowOffsetY), rightArrow(tip.x + arrowOffsetX, tip.y - arrowOffsetY);
|
||||||
|
|
||||||
|
|
||||||
Point *arrowPoints[] = {&tip, &tail, &leftArrow, &rightArrow};
|
Point *arrowPoints[] = {&tip, &tail, &leftArrow, &rightArrow};
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
@@ -402,13 +400,13 @@ static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t comp
|
|||||||
// Draw the compass heading
|
// Draw the compass heading
|
||||||
static void drawCompassHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading)
|
static void drawCompassHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading)
|
||||||
{
|
{
|
||||||
Point N1(-0.04f, -0.65f), N2( 0.04f, -0.65f);
|
Point N1(-0.04f, -0.65f), N2(0.04f, -0.65f);
|
||||||
Point N3(-0.04f, -0.55f), N4( 0.04f, -0.55f);
|
Point N3(-0.04f, -0.55f), N4(0.04f, -0.55f);
|
||||||
Point *rosePoints[] = {&N1, &N2, &N3, &N4};
|
Point *rosePoints[] = {&N1, &N2, &N3, &N4};
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
rosePoints[i]->rotate(myHeading);
|
rosePoints[i]->rotate(myHeading);
|
||||||
rosePoints[i]->scale(COMPASS_DIAM);
|
rosePoints[i]->scale(-1 * COMPASS_DIAM);
|
||||||
rosePoints[i]->translate(compassX, compassY);
|
rosePoints[i]->translate(compassX, compassY);
|
||||||
}
|
}
|
||||||
drawLine(display, N1, N3);
|
drawLine(display, N1, N3);
|
||||||
@@ -436,8 +434,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
displayedNodeNum = n->num;
|
displayedNodeNum = n->num;
|
||||||
|
|
||||||
// We just changed to a new node screen, ask that node for updated state if it's older than 2 minutes
|
// We just changed to a new node screen, ask that node for updated state if it's older than 2 minutes
|
||||||
if(sinceLastSeen(n) > 120)
|
if (sinceLastSeen(n) > 120) {
|
||||||
{
|
|
||||||
service.sendNetworkPing(displayedNodeNum, true);
|
service.sendNetworkPing(displayedNodeNum, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -473,14 +470,12 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
int16_t compassX = x + SCREEN_WIDTH - COMPASS_DIAM / 2 - 5, compassY = y + SCREEN_HEIGHT / 2;
|
int16_t compassX = x + SCREEN_WIDTH - COMPASS_DIAM / 2 - 5, compassY = y + SCREEN_HEIGHT / 2;
|
||||||
bool hasNodeHeading = false;
|
bool hasNodeHeading = false;
|
||||||
|
|
||||||
if(ourNode && hasPosition(ourNode))
|
if (ourNode && hasPosition(ourNode)) {
|
||||||
{
|
|
||||||
Position &op = ourNode->position;
|
Position &op = ourNode->position;
|
||||||
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||||
drawCompassHeading(display, compassX, compassY, myHeading);
|
drawCompassHeading(display, compassX, compassY, myHeading);
|
||||||
|
|
||||||
if(hasPosition(node))
|
if (hasPosition(node)) {
|
||||||
{
|
|
||||||
// display direction toward node
|
// display direction toward node
|
||||||
hasNodeHeading = true;
|
hasNodeHeading = true;
|
||||||
Position &p = node->position;
|
Position &p = node->position;
|
||||||
@@ -497,14 +492,13 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
drawNodeHeading(display, compassX, compassY, headingRadian);
|
drawNodeHeading(display, compassX, compassY, headingRadian);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!hasNodeHeading)
|
if (!hasNodeHeading)
|
||||||
// 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 / 4, compassY - FONT_HEIGHT / 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
|
||||||
drawColumns(display, x, y, fields);
|
drawColumns(display, x, y, fields);
|
||||||
}
|
}
|
||||||
@@ -594,6 +588,11 @@ void Screen::setup()
|
|||||||
dispdev.flipScreenVertically();
|
dispdev.flipScreenVertically();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Get our hardware ID
|
||||||
|
uint8_t dmac[6];
|
||||||
|
getMacAddr(dmac);
|
||||||
|
sprintf(ourId, "%02x%02x", dmac[4], dmac[5]);
|
||||||
|
|
||||||
// Turn on the display.
|
// Turn on the display.
|
||||||
handleSetOn(true);
|
handleSetOn(true);
|
||||||
|
|
||||||
@@ -770,7 +769,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
char channelStr[20];
|
char channelStr[20];
|
||||||
{
|
{
|
||||||
concurrency::LockGuard guard(&lock);
|
concurrency::LockGuard guard(&lock);
|
||||||
snprintf(channelStr, sizeof(channelStr), "#%s", channelName.c_str());
|
snprintf(channelStr, sizeof(channelStr), "%s", channelName.c_str());
|
||||||
|
|
||||||
// Display power status
|
// Display power status
|
||||||
if (powerStatus->getHasBattery())
|
if (powerStatus->getHasBattery())
|
||||||
@@ -783,8 +782,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
|
||||||
display->drawString(x, y + FONT_HEIGHT, channelStr);
|
display->drawString(x, y + FONT_HEIGHT, channelStr);
|
||||||
|
// 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->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT, ourId);
|
||||||
|
|
||||||
|
// Draw any log messages
|
||||||
display->drawLogBuffer(x, y + (FONT_HEIGHT * 2));
|
display->drawLogBuffer(x, y + (FONT_HEIGHT * 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 */
|
||||||
@@ -812,16 +816,15 @@ void Screen::adjustBrightness()
|
|||||||
|
|
||||||
int Screen::handleStatusUpdate(const meshtastic::Status *arg)
|
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 (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal())
|
setFrames();
|
||||||
setFrames();
|
prevFrame = -1;
|
||||||
prevFrame = -1;
|
nodeDB.updateGUI = false;
|
||||||
nodeDB.updateGUI = false;
|
nodeDB.updateTextMessage = false;
|
||||||
nodeDB.updateTextMessage = false;
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
setPeriod(1); // Update the screen right away
|
setPeriod(1); // Update the screen right away
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
17
src/graphics/TFT.cpp
Normal file
17
src/graphics/TFT.cpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#ifdef ST7735_CS
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip
|
||||||
|
|
||||||
|
TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
|
||||||
|
|
||||||
|
void TFTinit()
|
||||||
|
{
|
||||||
|
tft.init();
|
||||||
|
tft.setRotation(1);
|
||||||
|
tft.fillScreen(TFT_BLUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
3
src/graphics/TFT.h
Normal file
3
src/graphics/TFT.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void TFTinit();
|
||||||
@@ -6,11 +6,13 @@ const uint8_t SATELLITE_IMAGE[] PROGMEM = {0x00, 0x08, 0x00, 0x1C, 0x00, 0x0E, 0
|
|||||||
0xF8, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC8, 0x01, 0x9C, 0x54,
|
0xF8, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC8, 0x01, 0x9C, 0x54,
|
||||||
0x0E, 0x52, 0x07, 0x48, 0x02, 0x26, 0x00, 0x10, 0x00, 0x0E};
|
0x0E, 0x52, 0x07, 0x48, 0x02, 0x26, 0x00, 0x10, 0x00, 0x0E};
|
||||||
|
|
||||||
|
const uint8_t imgSatellite[] PROGMEM = { 0x70, 0x71, 0x22, 0xFA, 0xFA, 0x22, 0x71, 0x70 };
|
||||||
const uint8_t imgUSB[] PROGMEM = { 0x60, 0x60, 0x30, 0x18, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x24, 0x24, 0x24, 0x3C };
|
const uint8_t imgUSB[] PROGMEM = { 0x60, 0x60, 0x30, 0x18, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x24, 0x24, 0x24, 0x3C };
|
||||||
const uint8_t imgPower[] PROGMEM = { 0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08, 0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22 };
|
const uint8_t imgPower[] PROGMEM = { 0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08, 0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22 };
|
||||||
const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C };
|
const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C };
|
||||||
const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF };
|
const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF };
|
||||||
const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF };
|
const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF };
|
||||||
|
const uint8_t imgInfo[] PROGMEM = { 0xFF, 0x81, 0x81, 0xB5, 0xB5, 0x81, 0x81, 0xFF };
|
||||||
|
|
||||||
#include "img/icon.xbm"
|
#include "img/icon.xbm"
|
||||||
|
|
||||||
|
|||||||
62
src/main.cpp
62
src/main.cpp
@@ -210,13 +210,11 @@ void setup()
|
|||||||
esp32Setup();
|
esp32Setup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TBEAM_V10
|
|
||||||
// Currently only the tbeam has a PMU
|
// Currently only the tbeam has a PMU
|
||||||
power = new Power();
|
power = new Power();
|
||||||
power->setup();
|
power->setup();
|
||||||
power->setStatusHandler(powerStatus);
|
power->setStatusHandler(powerStatus);
|
||||||
powerStatus->observe(&power->newStatus);
|
powerStatus->observe(&power->newStatus);
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef NRF52_SERIES
|
#ifdef NRF52_SERIES
|
||||||
nrf52Setup();
|
nrf52Setup();
|
||||||
@@ -233,15 +231,18 @@ void setup()
|
|||||||
// If we know we have a L80 GPS, don't try UBLOX
|
// If we know we have a L80 GPS, don't try UBLOX
|
||||||
#ifndef L80_RESET
|
#ifndef L80_RESET
|
||||||
// Init GPS - first try ublox
|
// Init GPS - first try ublox
|
||||||
gps = new UBloxGPS();
|
auto ublox = new UBloxGPS();
|
||||||
|
gps = ublox;
|
||||||
if (!gps->setup()) {
|
if (!gps->setup()) {
|
||||||
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
|
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
|
||||||
|
|
||||||
|
delete ublox;
|
||||||
|
gps = ublox = NULL;
|
||||||
|
|
||||||
if (GPS::_serial_gps) {
|
if (GPS::_serial_gps) {
|
||||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
||||||
// assume NEMA at 9600 baud.
|
// assume NEMA at 9600 baud.
|
||||||
DEBUG_MSG("Hoping that NEMA might work\n");
|
DEBUG_MSG("Hoping that NEMA might work\n");
|
||||||
delete gps;
|
|
||||||
|
|
||||||
// dumb NEMA access only work for serial GPSes)
|
// dumb NEMA access only work for serial GPSes)
|
||||||
gps = new NEMAGPS();
|
gps = new NEMAGPS();
|
||||||
@@ -257,6 +258,16 @@ void setup()
|
|||||||
|
|
||||||
service.init();
|
service.init();
|
||||||
|
|
||||||
|
// We have now loaded our saved preferences from flash
|
||||||
|
|
||||||
|
// ONCE we will factory reset the GPS for bug #327
|
||||||
|
if (ublox && !devicestate.did_gps_reset) {
|
||||||
|
if (ublox->factoryReset()) { // If we don't succeed try again next time
|
||||||
|
devicestate.did_gps_reset = true;
|
||||||
|
nodeDB.saveToDisk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SX1262_ANT_SW
|
#ifdef SX1262_ANT_SW
|
||||||
// make analog PA vs not PA switch on SX1262 eval board work properly
|
// make analog PA vs not PA switch on SX1262 eval board work properly
|
||||||
pinMode(SX1262_ANT_SW, OUTPUT);
|
pinMode(SX1262_ANT_SW, OUTPUT);
|
||||||
@@ -273,17 +284,42 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// MUST BE AFTER service.init, so we have our radio config settings (from nodedb init)
|
// MUST BE AFTER service.init, so we have our radio config settings (from nodedb init)
|
||||||
RadioInterface *rIf =
|
RadioInterface *rIf = NULL;
|
||||||
|
|
||||||
#if defined(RF95_IRQ)
|
#if defined(RF95_IRQ)
|
||||||
// new CustomRF95(); old Radiohead based driver
|
if (!rIf) {
|
||||||
new RF95Interface(RF95_NSS, RF95_IRQ, RF95_RESET, SPI);
|
rIf = new RF95Interface(RF95_NSS, RF95_IRQ, RF95_RESET, SPI);
|
||||||
#elif defined(SX1262_CS)
|
if (!rIf->init()) {
|
||||||
new SX1262Interface(SX1262_CS, SX1262_DIO1, SX1262_RESET, SX1262_BUSY, SPI);
|
DEBUG_MSG("Warning: Failed to find RF95 radio\n");
|
||||||
#else
|
delete rIf;
|
||||||
new SimRadio();
|
rIf = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!rIf || !rIf->init())
|
#if defined(SX1262_CS)
|
||||||
|
if (!rIf) {
|
||||||
|
rIf = new SX1262Interface(SX1262_CS, SX1262_DIO1, SX1262_RESET, SX1262_BUSY, SPI);
|
||||||
|
if (!rIf->init()) {
|
||||||
|
DEBUG_MSG("Warning: Failed to find SX1262 radio\n");
|
||||||
|
delete rIf;
|
||||||
|
rIf = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SIM_RADIO
|
||||||
|
if (!rIf) {
|
||||||
|
rIf = new SimRadio;
|
||||||
|
if (!rIf->init()) {
|
||||||
|
DEBUG_MSG("Warning: Failed to find simulated radio\n");
|
||||||
|
delete rIf;
|
||||||
|
rIf = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!rIf)
|
||||||
recordCriticalError(ErrNoRadio);
|
recordCriticalError(ErrNoRadio);
|
||||||
else
|
else
|
||||||
router.addInterface(rIf);
|
router.addInterface(rIf);
|
||||||
@@ -364,7 +400,7 @@ void loop()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Update the screen last, after we've figured out what to show.
|
// Update the screen last, after we've figured out what to show.
|
||||||
screen.debug_info()->setChannelNameStatus(channelSettings.name);
|
screen.debug_info()->setChannelNameStatus(getChannelName());
|
||||||
// screen.debug()->setPowerStatus(powerStatus);
|
// screen.debug()->setPowerStatus(powerStatus);
|
||||||
|
|
||||||
// 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)
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ void MeshService::init()
|
|||||||
sendOwnerPeriod.setup();
|
sendOwnerPeriod.setup();
|
||||||
nodeDB.init();
|
nodeDB.init();
|
||||||
|
|
||||||
gpsObserver.observe(gps);
|
assert(gps);
|
||||||
|
gpsObserver.observe(&gps->newStatus);
|
||||||
packetReceivedObserver.observe(&router.notifyPacketReceived);
|
packetReceivedObserver.observe(&router.notifyPacketReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,9 +284,8 @@ void MeshService::sendOurPosition(NodeNum dest, bool wantReplies)
|
|||||||
sendToMesh(p);
|
sendToMesh(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MeshService::onGPSChanged(void *unused)
|
int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
||||||
{
|
{
|
||||||
// DEBUG_MSG("got gps notify\n");
|
|
||||||
|
|
||||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||||
MeshPacket *p = router.allocForSending();
|
MeshPacket *p = router.allocForSending();
|
||||||
@@ -305,6 +305,8 @@ int MeshService::onGPSChanged(void *unused)
|
|||||||
pos.battery_level = powerStatus->getBatteryChargePercent();
|
pos.battery_level = powerStatus->getBatteryChargePercent();
|
||||||
updateBatteryLevel(pos.battery_level);
|
updateBatteryLevel(pos.battery_level);
|
||||||
|
|
||||||
|
// DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level);
|
||||||
|
|
||||||
// We limit our GPS broadcasts to a max rate
|
// We limit our GPS broadcasts to a max rate
|
||||||
static uint32_t lastGpsSend;
|
static uint32_t lastGpsSend;
|
||||||
uint32_t now = timing::millis();
|
uint32_t now = timing::millis();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "GPSStatus.h"
|
||||||
#include "MemoryPool.h"
|
#include "MemoryPool.h"
|
||||||
#include "MeshRadio.h"
|
#include "MeshRadio.h"
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
@@ -17,7 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
class MeshService
|
class MeshService
|
||||||
{
|
{
|
||||||
CallbackObserver<MeshService, void *> gpsObserver = CallbackObserver<MeshService, void *>(this, &MeshService::onGPSChanged);
|
CallbackObserver<MeshService, const meshtastic::GPSStatus *> gpsObserver =
|
||||||
|
CallbackObserver<MeshService, const meshtastic::GPSStatus *>(this, &MeshService::onGPSChanged);
|
||||||
CallbackObserver<MeshService, const MeshPacket *> packetReceivedObserver =
|
CallbackObserver<MeshService, const MeshPacket *> packetReceivedObserver =
|
||||||
CallbackObserver<MeshService, const MeshPacket *>(this, &MeshService::handleFromRadio);
|
CallbackObserver<MeshService, const MeshPacket *>(this, &MeshService::handleFromRadio);
|
||||||
|
|
||||||
@@ -85,7 +87,7 @@ class MeshService
|
|||||||
|
|
||||||
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
||||||
/// returns 0 to allow futher processing
|
/// returns 0 to allow futher processing
|
||||||
int onGPSChanged(void *arg);
|
int onGPSChanged(const meshtastic::GPSStatus *arg);
|
||||||
|
|
||||||
/// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it needs
|
/// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it needs
|
||||||
/// to keep the packet around it makes a copy
|
/// to keep the packet around it makes a copy
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ DeviceState versions used to be defined in the .proto file but really only this
|
|||||||
#define here.
|
#define here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DEVICESTATE_CUR_VER 10
|
#define DEVICESTATE_CUR_VER 11
|
||||||
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
|
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
|
||||||
|
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
@@ -66,6 +66,33 @@ static uint8_t ourMacAddr[6];
|
|||||||
*/
|
*/
|
||||||
NodeNum displayedNodeNum;
|
NodeNum displayedNodeNum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs.
|
||||||
|
* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they
|
||||||
|
their nodes
|
||||||
|
* aren't talking to each other.
|
||||||
|
*
|
||||||
|
* This string is of the form "#name-XY".
|
||||||
|
*
|
||||||
|
* Where X is a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together.
|
||||||
|
* Y is not yet used but should eventually indicate 'speed/range' of the link
|
||||||
|
*
|
||||||
|
* This function will also need to be implemented in GUI apps that talk to the radio.
|
||||||
|
*
|
||||||
|
* https://github.com/meshtastic/Meshtastic-device/issues/269
|
||||||
|
*/
|
||||||
|
const char *getChannelName()
|
||||||
|
{
|
||||||
|
static char buf[32];
|
||||||
|
|
||||||
|
uint8_t code = 0;
|
||||||
|
for (int i = 0; i < sizeof(channelSettings.psk.size); i++)
|
||||||
|
code ^= channelSettings.psk.bytes[i];
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "#%s-%c", channelSettings.name, 'A' + (code % 26));
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
|
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
|
||||||
|
|
||||||
void NodeDB::resetRadioConfig()
|
void NodeDB::resetRadioConfig()
|
||||||
@@ -93,7 +120,7 @@ void NodeDB::resetRadioConfig()
|
|||||||
// so incompatible radios can talk together
|
// so incompatible radios can talk together
|
||||||
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
|
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
|
||||||
|
|
||||||
channelSettings.tx_power = 23;
|
channelSettings.tx_power = 0; // default
|
||||||
memcpy(&channelSettings.psk.bytes, &defaultpsk, sizeof(channelSettings.psk));
|
memcpy(&channelSettings.psk.bytes, &defaultpsk, sizeof(channelSettings.psk));
|
||||||
channelSettings.psk.size = sizeof(defaultpsk);
|
channelSettings.psk.size = sizeof(defaultpsk);
|
||||||
strcpy(channelSettings.name, "Default");
|
strcpy(channelSettings.name, "Default");
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Observer.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "Observer.h"
|
|
||||||
|
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
#include "mesh-pb-constants.h"
|
|
||||||
#include "NodeStatus.h"
|
#include "NodeStatus.h"
|
||||||
|
#include "mesh-pb-constants.h"
|
||||||
|
|
||||||
extern DeviceState devicestate;
|
extern DeviceState devicestate;
|
||||||
extern MyNodeInfo &myNodeInfo;
|
extern MyNodeInfo &myNodeInfo;
|
||||||
@@ -95,7 +95,8 @@ class NodeDB
|
|||||||
NodeInfo *getOrCreateNode(NodeNum n);
|
NodeInfo *getOrCreateNode(NodeNum n);
|
||||||
|
|
||||||
/// Notify observers of changes to the DB
|
/// Notify observers of changes to the DB
|
||||||
void notifyObservers(bool forceUpdate = false) {
|
void notifyObservers(bool forceUpdate = false)
|
||||||
|
{
|
||||||
// Notify observers of the current node state
|
// Notify observers of the current node state
|
||||||
const meshtastic::NodeStatus status = meshtastic::NodeStatus(getNumOnlineNodes(), getNumNodes(), forceUpdate);
|
const meshtastic::NodeStatus status = meshtastic::NodeStatus(getNumOnlineNodes(), getNumNodes(), forceUpdate);
|
||||||
newStatus.notifyObservers(&status);
|
newStatus.notifyObservers(&status);
|
||||||
@@ -115,3 +116,20 @@ class NodeDB
|
|||||||
extern NodeNum displayedNodeNum;
|
extern NodeNum displayedNodeNum;
|
||||||
|
|
||||||
extern NodeDB nodeDB;
|
extern NodeDB nodeDB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs.
|
||||||
|
* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they
|
||||||
|
their nodes
|
||||||
|
* aren't talking to each other.
|
||||||
|
*
|
||||||
|
* This string is of the form "#name-XY".
|
||||||
|
*
|
||||||
|
* Where X is a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together.
|
||||||
|
* Y is not yet used but should eventually indicate 'speed/range' of the link
|
||||||
|
*
|
||||||
|
* This function will also need to be implemented in GUI apps that talk to the radio.
|
||||||
|
*
|
||||||
|
* https://github.com/meshtastic/Meshtastic-device/issues/269
|
||||||
|
*/
|
||||||
|
const char *getChannelName();
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
#include "PhoneAPI.h"
|
#include "PhoneAPI.h"
|
||||||
|
#include "GPS.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "RadioInterface.h"
|
#include "RadioInterface.h"
|
||||||
#include "GPS.h"
|
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
@@ -80,7 +80,6 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next packet we want to send to the phone, or NULL if no such packet is available.
|
* Get the next packet we want to send to the phone, or NULL if no such packet is available.
|
||||||
*
|
*
|
||||||
@@ -96,7 +95,7 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
|||||||
size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||||
{
|
{
|
||||||
if (!available()) {
|
if (!available()) {
|
||||||
DEBUG_MSG("getFromRadio, !available\n");
|
// DEBUG_MSG("getFromRadio, !available\n");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("getFromRadio, state=%d\n", state);
|
DEBUG_MSG("getFromRadio, state=%d\n", state);
|
||||||
|
|||||||
@@ -115,22 +115,28 @@ unsigned long hash(char *str)
|
|||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define POWER_DEFAULT 17
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pull our channel settings etc... from protobufs to the dumb interface settings
|
* Pull our channel settings etc... from protobufs to the dumb interface settings
|
||||||
*/
|
*/
|
||||||
void RadioInterface::applyModemConfig()
|
void RadioInterface::applyModemConfig()
|
||||||
{
|
{
|
||||||
// Set up default configuration
|
// Set up default configuration
|
||||||
// No Sync Words in LORA mode.
|
// No Sync Words in LORA mode
|
||||||
modemConfig = (ModemConfigChoice)channelSettings.modem_config;
|
|
||||||
|
|
||||||
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
|
|
||||||
int channel_num = hash(channelSettings.name) % NUM_CHANNELS;
|
|
||||||
freq = CH0 + CH_SPACING * channel_num;
|
|
||||||
power = channelSettings.tx_power;
|
power = channelSettings.tx_power;
|
||||||
|
if (power == 0)
|
||||||
|
power = POWER_DEFAULT;
|
||||||
|
|
||||||
|
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
|
||||||
|
int channel_num = (channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelSettings.name)) % NUM_CHANNELS;
|
||||||
|
freq = CH0 + CH_SPACING * channel_num;
|
||||||
|
|
||||||
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelSettings.name, channelSettings.modem_config, channel_num,
|
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelSettings.name, channelSettings.modem_config, channel_num,
|
||||||
channelSettings.tx_power);
|
power);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SimRadio::send(MeshPacket *p)
|
ErrorCode SimRadio::send(MeshPacket *p)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../concurrency/NotifiedWorkerThread.h"
|
||||||
#include "MemoryPool.h"
|
#include "MemoryPool.h"
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
#include "PointerQueue.h"
|
#include "PointerQueue.h"
|
||||||
#include "../concurrency/NotifiedWorkerThread.h"
|
|
||||||
#include "mesh.pb.h"
|
#include "mesh.pb.h"
|
||||||
|
|
||||||
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
|
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
|
||||||
@@ -31,13 +31,6 @@ typedef struct {
|
|||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
} PacketHeader;
|
} PacketHeader;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
Bw125Cr45Sf128 = 0, ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range
|
|
||||||
Bw500Cr45Sf128, ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range
|
|
||||||
Bw31_25Cr48Sf512, ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range
|
|
||||||
Bw125Cr48Sf4096, ///< Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on. Slow+long range
|
|
||||||
} ModemConfigChoice;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic operations all radio chipsets must implement.
|
* Basic operations all radio chipsets must implement.
|
||||||
*
|
*
|
||||||
@@ -72,9 +65,7 @@ class RadioInterface : protected concurrency::NotifiedWorkerThread
|
|||||||
void deliverToReceiver(MeshPacket *p);
|
void deliverToReceiver(MeshPacket *p);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
float freq = 915.0; // FIXME, init all these params from user setings
|
float freq = 915.0;
|
||||||
int8_t power = 17;
|
|
||||||
ModemConfigChoice modemConfig;
|
|
||||||
|
|
||||||
/** pool is the pool we will alloc our rx packets from
|
/** pool is the pool we will alloc our rx packets from
|
||||||
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
|
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
|
||||||
@@ -116,6 +107,8 @@ class RadioInterface : protected concurrency::NotifiedWorkerThread
|
|||||||
virtual bool reconfigure() = 0;
|
virtual bool reconfigure() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
int8_t power = 17; // Set by applyModemConfig()
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of bytes to send (including the
|
* given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of bytes to send (including the
|
||||||
* PacketHeader & payload).
|
* PacketHeader & payload).
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "RadioLibInterface.h"
|
#include "RadioLibInterface.h"
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include <configuration.h>
|
#include <configuration.h>
|
||||||
#include <pb_decode.h>
|
#include <pb_decode.h>
|
||||||
@@ -12,7 +13,6 @@ RadioLibInterface::RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq
|
|||||||
SPIClass &spi, PhysicalLayer *_iface)
|
SPIClass &spi, PhysicalLayer *_iface)
|
||||||
: concurrency::PeriodicTask(0), module(cs, irq, rst, busy, spi, spiSettings), iface(_iface)
|
: concurrency::PeriodicTask(0), module(cs, irq, rst, busy, spi, spiSettings), iface(_iface)
|
||||||
{
|
{
|
||||||
assert(!instance); // We assume only one for now
|
|
||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,29 +64,41 @@ void RadioLibInterface::applyModemConfig()
|
|||||||
{
|
{
|
||||||
RadioInterface::applyModemConfig();
|
RadioInterface::applyModemConfig();
|
||||||
|
|
||||||
switch (modemConfig) {
|
if (channelSettings.spread_factor == 0) {
|
||||||
case Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range
|
switch (channelSettings.modem_config) {
|
||||||
bw = 125;
|
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium
|
||||||
cr = 5;
|
///< range
|
||||||
sf = 7;
|
bw = 125;
|
||||||
break;
|
cr = 5;
|
||||||
case Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range
|
sf = 7;
|
||||||
bw = 500;
|
break;
|
||||||
cr = 5;
|
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short
|
||||||
sf = 7;
|
///< range
|
||||||
break;
|
bw = 500;
|
||||||
case Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range
|
cr = 5;
|
||||||
bw = 31.25;
|
sf = 7;
|
||||||
cr = 8;
|
break;
|
||||||
sf = 9;
|
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long
|
||||||
break;
|
///< range
|
||||||
case Bw125Cr48Sf4096:
|
bw = 31.25;
|
||||||
bw = 125;
|
cr = 8;
|
||||||
cr = 8;
|
sf = 9;
|
||||||
sf = 12;
|
break;
|
||||||
break;
|
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
|
||||||
default:
|
bw = 125;
|
||||||
assert(0); // Unknown enum
|
cr = 8;
|
||||||
|
sf = 12;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0); // Unknown enum
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sf = channelSettings.spread_factor;
|
||||||
|
cr = channelSettings.coding_rate;
|
||||||
|
bw = channelSettings.bandwidth;
|
||||||
|
|
||||||
|
if (bw == 31) // This parameter is not an integer
|
||||||
|
bw = 31.25;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,19 @@ SX1262Interface::SX1262Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RA
|
|||||||
/// \return true if initialisation succeeded.
|
/// \return true if initialisation succeeded.
|
||||||
bool SX1262Interface::init()
|
bool SX1262Interface::init()
|
||||||
{
|
{
|
||||||
|
#ifdef SX1262_POWER_EN
|
||||||
|
digitalWrite(SX1262_POWER_EN, HIGH);
|
||||||
|
pinMode(SX1262_POWER_EN, OUTPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
RadioLibInterface::init();
|
RadioLibInterface::init();
|
||||||
|
|
||||||
#ifdef SX1262_RXEN // set not rx or tx mode
|
#ifdef SX1262_RXEN // set not rx or tx mode
|
||||||
|
digitalWrite(SX1262_RXEN, LOW); // Set low before becoming an output
|
||||||
pinMode(SX1262_RXEN, OUTPUT);
|
pinMode(SX1262_RXEN, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
#ifdef SX1262_TXEN
|
#ifdef SX1262_TXEN
|
||||||
|
digitalWrite(SX1262_TXEN, LOW);
|
||||||
pinMode(SX1262_TXEN, OUTPUT);
|
pinMode(SX1262_TXEN, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ typedef struct _DeviceState {
|
|||||||
MeshPacket rx_text_message;
|
MeshPacket rx_text_message;
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
bool no_save;
|
bool no_save;
|
||||||
|
bool did_gps_reset;
|
||||||
} DeviceState;
|
} DeviceState;
|
||||||
|
|
||||||
typedef struct _FromRadio {
|
typedef struct _FromRadio {
|
||||||
@@ -250,7 +251,7 @@ typedef struct _ToRadio {
|
|||||||
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, {0, 0, 0}}
|
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, {0, 0, 0}}
|
||||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
||||||
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
|
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0}
|
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
|
||||||
#define DebugString_init_default {""}
|
#define DebugString_init_default {""}
|
||||||
#define FromRadio_init_default {0, 0, {MeshPacket_init_default}}
|
#define FromRadio_init_default {0, 0, {MeshPacket_init_default}}
|
||||||
#define ToRadio_init_default {0, {MeshPacket_init_default}}
|
#define ToRadio_init_default {0, {MeshPacket_init_default}}
|
||||||
@@ -266,7 +267,7 @@ typedef struct _ToRadio {
|
|||||||
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, {0, 0, 0}}
|
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, {0, 0, 0}}
|
||||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
||||||
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
|
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0}
|
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
|
||||||
#define DebugString_init_zero {""}
|
#define DebugString_init_zero {""}
|
||||||
#define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}}
|
#define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}}
|
||||||
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
|
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
|
||||||
@@ -363,6 +364,7 @@ typedef struct _ToRadio {
|
|||||||
#define DeviceState_version_tag 8
|
#define DeviceState_version_tag 8
|
||||||
#define DeviceState_rx_text_message_tag 7
|
#define DeviceState_rx_text_message_tag 7
|
||||||
#define DeviceState_no_save_tag 9
|
#define DeviceState_no_save_tag 9
|
||||||
|
#define DeviceState_did_gps_reset_tag 10
|
||||||
#define FromRadio_packet_tag 2
|
#define FromRadio_packet_tag 2
|
||||||
#define FromRadio_my_info_tag 3
|
#define FromRadio_my_info_tag 3
|
||||||
#define FromRadio_node_info_tag 4
|
#define FromRadio_node_info_tag 4
|
||||||
@@ -516,7 +518,8 @@ X(a, STATIC, REPEATED, MESSAGE, node_db, 4) \
|
|||||||
X(a, STATIC, REPEATED, MESSAGE, receive_queue, 5) \
|
X(a, STATIC, REPEATED, MESSAGE, receive_queue, 5) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \
|
X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, version, 8) \
|
X(a, STATIC, SINGULAR, UINT32, version, 8) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, no_save, 9)
|
X(a, STATIC, SINGULAR, BOOL, no_save, 9) \
|
||||||
|
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 10)
|
||||||
#define DeviceState_CALLBACK NULL
|
#define DeviceState_CALLBACK NULL
|
||||||
#define DeviceState_DEFAULT NULL
|
#define DeviceState_DEFAULT NULL
|
||||||
#define DeviceState_radio_MSGTYPE RadioConfig
|
#define DeviceState_radio_MSGTYPE RadioConfig
|
||||||
@@ -614,7 +617,7 @@ extern const pb_msgdesc_t ManufacturingData_msg;
|
|||||||
#define RadioConfig_UserPreferences_size 188
|
#define RadioConfig_UserPreferences_size 188
|
||||||
#define NodeInfo_size 132
|
#define NodeInfo_size 132
|
||||||
#define MyNodeInfo_size 110
|
#define MyNodeInfo_size 110
|
||||||
#define DeviceState_size 5427
|
#define DeviceState_size 5429
|
||||||
#define DebugString_size 258
|
#define DebugString_size 258
|
||||||
#define FromRadio_size 322
|
#define FromRadio_size 322
|
||||||
#define ToRadio_size 316
|
#define ToRadio_size 316
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "NRF52Bluetooth.h"
|
#include "NRF52Bluetooth.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "graphics/TFT.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ble_gap.h>
|
#include <ble_gap.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
@@ -98,4 +99,9 @@ void nrf52Setup()
|
|||||||
// randomSeed(r);
|
// randomSeed(r);
|
||||||
DEBUG_MSG("FIXME, call randomSeed\n");
|
DEBUG_MSG("FIXME, call randomSeed\n");
|
||||||
// ::printf("TESTING PRINTF\n");
|
// ::printf("TESTING PRINTF\n");
|
||||||
|
|
||||||
|
// Setup TFT display - FIXME do somewhere else
|
||||||
|
#ifdef ST7735_CS
|
||||||
|
TFTinit();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
18
src/power.h
18
src/power.h
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "concurrency/PeriodicTask.h"
|
|
||||||
#include "PowerStatus.h"
|
#include "PowerStatus.h"
|
||||||
|
#include "concurrency/PeriodicTask.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Per @spattinson
|
* Per @spattinson
|
||||||
@@ -18,23 +18,23 @@
|
|||||||
class Power : public concurrency::PeriodicTask
|
class Power : public concurrency::PeriodicTask
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Observable<const meshtastic::PowerStatus *> newStatus;
|
Observable<const meshtastic::PowerStatus *> newStatus;
|
||||||
|
|
||||||
void readPowerStatus();
|
void readPowerStatus();
|
||||||
void loop();
|
void loop();
|
||||||
virtual bool setup();
|
virtual bool setup();
|
||||||
virtual void doTask();
|
virtual void doTask();
|
||||||
void setStatusHandler(meshtastic::PowerStatus *handler)
|
void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; }
|
||||||
{
|
|
||||||
statusHandler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
meshtastic::PowerStatus *statusHandler;
|
meshtastic::PowerStatus *statusHandler;
|
||||||
virtual void axp192Init();
|
|
||||||
|
|
||||||
|
/// Setup a axp192, return true if found
|
||||||
|
bool axp192Init();
|
||||||
|
|
||||||
|
/// Setup a simple ADC input based battery sensor
|
||||||
|
bool analogInit();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Power *power;
|
extern Power *power;
|
||||||
105
variants/lora_relay_v1/variant.cpp
Normal file
105
variants/lora_relay_v1/variant.cpp
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||||
|
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||||
|
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "variant.h"
|
||||||
|
#include "nrf.h"
|
||||||
|
#include "wiring_constants.h"
|
||||||
|
#include "wiring_digital.h"
|
||||||
|
|
||||||
|
const uint32_t g_ADigitalPinMap[] = {
|
||||||
|
// D0 .. D13
|
||||||
|
25, // D0 is P0.25 (UART TX)
|
||||||
|
24, // D1 is P0.24 (UART RX
|
||||||
|
10, // D2 is P0.10 (NFC2)
|
||||||
|
47, // D3 is P1.15 (LED1)
|
||||||
|
42, // D4 is P1.10 (LED2)
|
||||||
|
40, // D5 is P1.08
|
||||||
|
7, // D6 is P0.07
|
||||||
|
34, // D7 is P1.02 (Button)
|
||||||
|
16, // D8 is P0.16 (NeoPixel)
|
||||||
|
26, // D9 is P0.26 D_RS (IPS data/command control)
|
||||||
|
27, // D10 is P0.27
|
||||||
|
6, // D11 is P0.06 D_RES (IPS display reset)
|
||||||
|
8, // D12 is P0.08 D_CS (IPS display chip select)
|
||||||
|
41, // D13 is P1.09 BLT (IPS display backlight)
|
||||||
|
4, // D14 is P0.04 SX1262 RXEN
|
||||||
|
5, // D15 is P0.05 BOOST_EN (5V buck converter enable for the the radio power)
|
||||||
|
|
||||||
|
// D14 .. D21 (aka A0 .. A7)
|
||||||
|
30, // D16 is P0.30 (A0)
|
||||||
|
28, // D17 is P0.28 (A1)
|
||||||
|
2, // D18 is P0.02 (A2)
|
||||||
|
3, // D19 is P0.03 (A3)
|
||||||
|
29, // D20 is P0.29 (A4, Battery)
|
||||||
|
31, // D21 is P0.31 (A5, ARef)
|
||||||
|
|
||||||
|
// D22 .. D23 (aka I2C pins)
|
||||||
|
12, // D22 is P0.12 (SDA)
|
||||||
|
11, // D23 is P0.11 (SCL)
|
||||||
|
|
||||||
|
// D24 .. D26 (aka SPI pins)
|
||||||
|
15, // D24 is P0.15 (SPI MISO)
|
||||||
|
13, // D25 is P0.13 (SPI MOSI)
|
||||||
|
14, // D26 is P0.14 (SPI SCK )
|
||||||
|
|
||||||
|
// QSPI pins (not exposed via any header / test point)
|
||||||
|
// 19, // P0.19 (QSPI CLK)
|
||||||
|
// 20, // P0.20 (QSPI CS)
|
||||||
|
// 17, // P0.17 (QSPI Data 0)
|
||||||
|
// 22, // P0.22 (QSPI Data 1)
|
||||||
|
// 23, // P0.23 (QSPI Data 2)
|
||||||
|
// 21, // P0.21 (QSPI Data 3)
|
||||||
|
|
||||||
|
// The remaining NFC pin
|
||||||
|
9, // D27 P0.09 (NFC1, exposed only via test point on bottom of board)
|
||||||
|
|
||||||
|
// The following pins were never listed as they were considered unusable
|
||||||
|
// 0, // P0.00 is XL1 (attached to 32.768kHz crystal) Never expose as GPIOs
|
||||||
|
// 1, // P0.01 is XL2 (attached to 32.768kHz crystal)
|
||||||
|
18, // D28 P0.18 is RESET (attached to switch)
|
||||||
|
// 32, // P1.00 is SWO (attached to debug header)
|
||||||
|
|
||||||
|
// D29-D43
|
||||||
|
27, // D29 P0.27 E22-SX1262 DIO1
|
||||||
|
28, // D30 P0.28 E22-SX1262 DIO2
|
||||||
|
30, // D31 P0.30 E22-SX1262 TXEN
|
||||||
|
35, // D32 P1.03 E22-SX1262 NSS
|
||||||
|
32 + 8, // D33 P1.08 E22-SX1262 BUSY
|
||||||
|
32 + 12, // D34 P1.12 E22-SX1262 RESET
|
||||||
|
32 + 1, // P1.01 BTN_UP
|
||||||
|
32 + 2, // P1.02 SWITCH
|
||||||
|
32 + 14, // D37 P1.14 is not connected per schematic
|
||||||
|
36, // P1.04 is not connected per schematic
|
||||||
|
37, // P1.05 is not connected per schematic
|
||||||
|
38, // P1.06 is not connected per schematic
|
||||||
|
39, // P1.07 is not connected per schematic
|
||||||
|
43, // P1.11 is not connected per schematic
|
||||||
|
45, // P1.13 is not connected per schematic
|
||||||
|
};
|
||||||
|
|
||||||
|
void initVariant()
|
||||||
|
{
|
||||||
|
// LED1 & LED2
|
||||||
|
pinMode(PIN_LED1, OUTPUT);
|
||||||
|
ledOff(PIN_LED1);
|
||||||
|
|
||||||
|
pinMode(PIN_LED2, OUTPUT);
|
||||||
|
ledOff(PIN_LED2);
|
||||||
|
}
|
||||||
145
variants/lora_relay_v1/variant.h
Normal file
145
variants/lora_relay_v1/variant.h
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||||
|
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||||
|
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _VARIANT_LORA_RELAY_V1_
|
||||||
|
#define _VARIANT_LORA_RELAY_V1_
|
||||||
|
|
||||||
|
/** Master clock frequency */
|
||||||
|
#define VARIANT_MCK (64000000ul)
|
||||||
|
|
||||||
|
#define USE_LFXO // Board uses 32khz crystal for LF
|
||||||
|
// define USE_LFRC // Board uses RC for LF
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
* Headers
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "WVariant.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
// Number of pins defined in PinDescription array
|
||||||
|
#define PINS_COUNT (43)
|
||||||
|
#define NUM_DIGITAL_PINS (43)
|
||||||
|
#define NUM_ANALOG_INPUTS (6) // A6 is used for battery, A7 is analog reference
|
||||||
|
#define NUM_ANALOG_OUTPUTS (0)
|
||||||
|
|
||||||
|
// LEDs
|
||||||
|
#define PIN_LED1 (3)
|
||||||
|
#define PIN_LED2 (4)
|
||||||
|
#define PIN_NEOPIXEL (8)
|
||||||
|
|
||||||
|
#define LED_BUILTIN PIN_LED1
|
||||||
|
#define LED_CONN PIN_LED2
|
||||||
|
|
||||||
|
#define LED_RED PIN_LED1
|
||||||
|
#define LED_BLUE PIN_LED2
|
||||||
|
|
||||||
|
#define LED_STATE_ON 1 // State when LED is litted
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Buttons
|
||||||
|
*/
|
||||||
|
#define PIN_BUTTON1 (7)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Analog pins
|
||||||
|
*/
|
||||||
|
#define PIN_A0 (16)
|
||||||
|
#define PIN_A1 (17)
|
||||||
|
#define PIN_A2 (18)
|
||||||
|
#define PIN_A3 (19)
|
||||||
|
#define PIN_A4 (20)
|
||||||
|
#define PIN_A5 (21)
|
||||||
|
|
||||||
|
static const uint8_t A0 = PIN_A0;
|
||||||
|
static const uint8_t A1 = PIN_A1;
|
||||||
|
static const uint8_t A2 = PIN_A2;
|
||||||
|
static const uint8_t A3 = PIN_A3;
|
||||||
|
static const uint8_t A4 = PIN_A4;
|
||||||
|
static const uint8_t A5 = PIN_A5;
|
||||||
|
#define ADC_RESOLUTION 14
|
||||||
|
|
||||||
|
// Other pins
|
||||||
|
#define PIN_AREF PIN_A5
|
||||||
|
#define PIN_VBAT PIN_A4
|
||||||
|
#define PIN_NFC1 (33)
|
||||||
|
#define PIN_NFC2 (2)
|
||||||
|
#define PIN_PIEZO (37)
|
||||||
|
static const uint8_t AREF = PIN_AREF;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serial interfaces
|
||||||
|
*/
|
||||||
|
#define PIN_SERIAL1_RX (1)
|
||||||
|
#define PIN_SERIAL1_TX (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPI Interfaces
|
||||||
|
*/
|
||||||
|
#define SPI_INTERFACES_COUNT 1
|
||||||
|
|
||||||
|
#define PIN_SPI_MISO (24)
|
||||||
|
#define PIN_SPI_MOSI (25)
|
||||||
|
#define PIN_SPI_SCK (26)
|
||||||
|
|
||||||
|
static const uint8_t SS = (5);
|
||||||
|
static const uint8_t MOSI = PIN_SPI_MOSI;
|
||||||
|
static const uint8_t MISO = PIN_SPI_MISO;
|
||||||
|
static const uint8_t SCK = PIN_SPI_SCK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wire Interfaces
|
||||||
|
*/
|
||||||
|
#define WIRE_INTERFACES_COUNT 1
|
||||||
|
|
||||||
|
#define PIN_WIRE_SDA (22)
|
||||||
|
#define PIN_WIRE_SCL (23)
|
||||||
|
|
||||||
|
// I2C device addresses
|
||||||
|
#define I2C_ADDR_BQ27441 0x55 // Battery gauge
|
||||||
|
|
||||||
|
// CUSTOM GPIOs the SX1262
|
||||||
|
#define SX1262_CS (32)
|
||||||
|
#define SX1262_DIO1 (29)
|
||||||
|
#define SX1262_DIO2 (30)
|
||||||
|
#define SX1262_BUSY (33) // Supposed to be P0.18 but because of reworks, now on P0.31 (18)
|
||||||
|
#define SX1262_RESET (34)
|
||||||
|
// #define SX1262_ANT_SW (32 + 10)
|
||||||
|
#define SX1262_RXEN (14)
|
||||||
|
#define SX1262_TXEN (31)
|
||||||
|
#define SX1262_POWER_EN \
|
||||||
|
(15) // FIXME, see warning hre https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay/blob/master/LORA_RELAY_NRF52840.ino
|
||||||
|
#define SX1262_E22 // Indicates this SX1262 is inside of an ebyte E22 module and special config should be done for that
|
||||||
|
|
||||||
|
#define ST7735_RESET (11) // Output
|
||||||
|
#define ST7735_CS (12)
|
||||||
|
#define ST7735_BACKLIGHT_EN (13)
|
||||||
|
#define ST7735_RS (9)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
* Arduino objects - C++ only
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -128,7 +128,25 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
|||||||
#define PIN_WIRE_SDA (32 + 2)
|
#define PIN_WIRE_SDA (32 + 2)
|
||||||
#define PIN_WIRE_SCL (32)
|
#define PIN_WIRE_SCL (32)
|
||||||
|
|
||||||
#define GPS_I2C_ADDR FIXME
|
// CUSTOM GPIOs the SX1262
|
||||||
|
#define SX1262_CS (10)
|
||||||
|
#define SX1262_DIO1 (20)
|
||||||
|
#define SX1262_DIO2 (26)
|
||||||
|
#define SX1262_BUSY (31) // Supposed to be P0.18 but because of reworks, now on P0.31 (18)
|
||||||
|
#define SX1262_RESET (17)
|
||||||
|
// #define SX1262_ANT_SW (32 + 10)
|
||||||
|
#define SX1262_RXEN (22)
|
||||||
|
#define SX1262_TXEN (24)
|
||||||
|
#define SX1262_E22 // Indicates this SX1262 is inside of an ebyte E22 module and special config should be done for that
|
||||||
|
|
||||||
|
// ERC12864-10 LCD
|
||||||
|
#define ERC12864_CS (32 + 4)
|
||||||
|
#define ERC12864_RESET (32 + 6)
|
||||||
|
#define ERC12864_CD (32 + 9)
|
||||||
|
|
||||||
|
// L80 GPS
|
||||||
|
#define L80_PPS (28)
|
||||||
|
#define L80_RESET (29)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user