Compare commits

..

1 Commits

Author SHA1 Message Date
Kevin Hester
b6740548f3 todo update 2021-08-28 13:46:28 -07:00
280 changed files with 3524 additions and 7028 deletions

View File

@@ -3,61 +3,19 @@ on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ master ]
paths-ignore:
- '**.md'
- '**.yml'
# Note: This is different from "pull_request". Need to specify ref when doing checkouts.
pull_request_target:
pull_request:
branches: [ master ]
paths-ignore:
- '**.md'
- '**.yml'
jobs:
ci-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
submodules: 'recursive'
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install cppcheck
run: |
sudo apt-get install -y cppcheck
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Cache python libs
uses: actions/cache@v1
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
- name: Upgrade python tools and install platformio
run: |
python -m pip install --upgrade pip
pip install -U platformio
- name: Upgrade platformio
run: |
pio upgrade
- name: Check everything
run: bin/check-all.sh
# setup:
# runs-on: ubuntu-latest
# steps:
# - name: Startup
# run: echo "No action setup currently needed, skipping..."
ci-build:
# needs: setup
runs-on: ubuntu-latest
steps:
@@ -65,8 +23,6 @@ jobs:
uses: actions/checkout@v2
with:
submodules: 'recursive'
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
uses: actions/setup-python@v2
@@ -80,6 +36,10 @@ jobs:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
#- name: Install linux apt packages
# run: |
# sudo apt-get install -y libgpiod-dev
- name: Upgrade python tools
# We actually want to run this every time
# if: steps.cache-pip.outputs.cache-hit != 'true'
@@ -98,19 +58,6 @@ jobs:
run: |
pio upgrade
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "meshtastic/meshtastic-web"
file: "build.tar"
target: "build.tar"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
# We now run integration test before other build steps (to quickly see runtime failures)
- name: Build for native
run: platformio run -e native
@@ -121,23 +68,22 @@ jobs:
echo "Simulator started, launching python test..."
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
- name: Cat bin/build-all.sh
run: |
cat bin/build-all.sh
# - name: Build for tbeam
# run: platformio run -e tbeam
# - name: Build for heltec
# run: platformio run -e heltec
# - name: Build for wisblock RAK4631
# run: platformio run -e rak4631
- name: Build everything
run: bin/build-all.sh
- name: Get release version string
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v2
with:
name: firmware-${{ steps.version.outputs.version }}.zip
path: release/archive/firmware-${{ steps.version.outputs.version }}.zip
retention-days: 90
name: built
path: release/archive/firmware-*.zip
retention-days: 30
- name: Store debugging elf files as an artifact
uses: actions/upload-artifact@v2
@@ -145,18 +91,3 @@ jobs:
name: debug-elfs
path: release/archive/elfs-*.zip
retention-days: 7
- name: Download firmware.zip
uses: actions/download-artifact@master
with:
name: firmware-${{ steps.version.outputs.version }}.zip
path: ./
- name: Pull request artifacts
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
uses: gavv/pull-request-artifacts@v1.0.0
with:
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
artifacts-branch: artifacts
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip

View File

@@ -1,15 +1,15 @@
name: Make Release
on:
# Can optionally take parameters from the github UI, more info here https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/#:~:text=You%20can%20now%20create%20workflows,the%20workflow%20is%20run%20on.
workflow_dispatch:
# workflow_dispatch:
# inputs:
# Only want to run if version.properties is bumped in master
# Only want to be run if a new tag starting with v is pushed.
push:
branches:
- master
paths:
- 'version.properties'
- "!*"
tags:
- "v1*"
jobs:
release-build:
@@ -21,15 +21,19 @@ jobs:
with:
submodules: 'recursive'
# get github branch and tag names as ${{ steps.branch_name.outputs.SOURCE_TAG }}
- name: Branch name
id: branch_name
run: |
echo ::set-output name=SOURCE_NAME::${GITHUB_REF#refs/*/}
echo ::set-output name=SOURCE_BRANCH::${GITHUB_REF#refs/heads/}
echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/}
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.x
# Will be available in steps.version.outputs.version
- name: Get release version string
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
id: version
# Note: we don't use caches on release builds because we don't want to accidentally not have a virgin build machine
- name: Upgrade python tools
@@ -43,18 +47,10 @@ jobs:
run: |
pio upgrade
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "meshtastic/meshtastic-web"
file: "build.tar"
target: "build.tar"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
# Will be available in steps.version.outputs.version
- name: Get version string
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
id: version
- name: Build everything
run: bin/build-all.sh
@@ -66,7 +62,8 @@ jobs:
draft: true
prerelease: true
release_name: ${{ steps.version.outputs.version }} alpha
tag_name: v${{ steps.version.outputs.version }}
tag_name: ${{ steps.branch_name.outputs.SOURCE_TAG }}
# was ${{ github.ref }}
body: |
Autogenerated by github action, developer should edit as required before publishing...
env:
@@ -90,4 +87,4 @@ jobs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: release/archive/elfs-${{ steps.version.outputs.version }}.zip
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
asset_content_type: application/zip
asset_content_type: application/zip

View File

@@ -1,33 +0,0 @@
name: "Update protobufs and regenerate classes"
on: workflow_dispatch
jobs:
update-protobufs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
submodules: true
- name: Update submodule
run: |
git submodule update --remote proto
- name: Download nanopb
run: |
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.4-linux-x86.tar.gz
tar xvzf nanopb-0.4.4-linux-x86.tar.gz
mv nanopb-0.4.4-linux-x86 nanopb-0.4.4
- name: Re-generate protocol buffers
run: |
./bin/regen-protos.sh
- name: Create pull request
uses: peter-evans/create-pull-request@v3
with:
add-paths: |
proto
src/mesh

8
.gitignore vendored
View File

@@ -9,7 +9,7 @@ main/credentials.h
!.vscode/extensions.json
*.code-workspace
.idea
.idea/workspace.xml
.DS_Store
Thumbs.db
@@ -23,9 +23,3 @@ flash.uf2
cmake-build*
__pycache__
*.swp
*.swo
*~
venv/
release/

View File

@@ -1,50 +0,0 @@
image: python:latest
variables:
# make sure GitLab check out submodules
GIT_SUBMODULE_STRATEGY: recursive
stages:
- buildall
- upload
build:
stage: buildall
before_script:
# we need zip later for packaging
- "apt update;apt -y install zip"
- "pip install -U platformio"
script:
# clean up residues from previous run
- rm -rf release
- bin/build-all.sh
# This is for my local environment, if your runners are tagged differently, modify or remove
tags:
- dockerized
# The files which are to be made available in GitLab
artifacts:
paths:
- release/archive/firmware*.zip
upload:
image: curlimages/curl:latest
stage: upload
script:
- |
PACKAGE_REGISTRY_URL="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${CI_PROJECT_NAME}/master"
cd release/archive
for f in *.zip; do
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file ${f} ${PACKAGE_REGISTRY_URL}/${f}
done
echo 'Package uploaded!'
# This is for my local environment, if your runners are tagged differently, modify or remove
tags:
- dockerized

7
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<clangFormatSettings>
<option name="ENABLED" value="true" />
</clangFormatSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

2
.idea/meshtastic-esp32.iml generated Normal file
View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

4
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/meshtastic-esp32.iml" filepath="$PROJECT_DIR$/.idea/meshtastic-esp32.iml" />
</modules>
</component>
</project>

9
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/design" vcs="Git" />
<mapping directory="$PROJECT_DIR$/proto" vcs="Git" />
<mapping directory="$PROJECT_DIR$/sdk-nrfxlib" vcs="Git" />
</component>
</project>

View File

@@ -50,8 +50,7 @@
"cassert": "cpp",
"iterator": "cpp",
"shared_mutex": "cpp",
"iostream": "cpp",
"esp_nimble_hci.h": "c"
"iostream": "cpp"
},
"cSpell.words": [
"Blox",

View File

@@ -1,16 +0,0 @@
FROM ubuntu
MAINTAINER Kevin Hester <kevinh@geeksville.com>
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install wget python3 g++ zip python3-venv git vim
RUN wget https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py -O get-platformio.py; chmod +x get-platformio.py
RUN python3 get-platformio.py
RUN git clone https://github.com/meshtastic/Meshtastic-device.git
RUN cd Meshtastic-device; git submodule update --init --recursive
# only build the simulator
RUN sed -i 's/^BOARDS_ESP32.*/BOARDS_ESP32=""/' Meshtastic-device/bin/build-all.sh
RUN sed -i 's/^BOARDS_NRF52.*/BOARDS_NRF52=""/' Meshtastic-device/bin/build-all.sh
RUN sed -i 's/echo "Building SPIFFS.*/exit/' Meshtastic-device/bin/build-all.sh
RUN . ~/.platformio/penv/bin/activate; cd Meshtastic-device; ./bin/build-all.sh
CMD ["/Meshtastic-device/release/latest/bins/universal/meshtasticd_linux_amd64"]

View File

@@ -1,14 +1,5 @@
# Meshtastic-device
[![Open in Visual Studio Code](https://open.vscode.dev/badges/open-in-vscode.svg)](https://open.vscode.dev/meshtastic/Meshtastic-device)
[![Continuous Integration](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml/badge.svg)](https://github.com/meshtastic/Meshtastic-device/actions/workflows/main.yml)
![GitHub all releases](https://img.shields.io/github/downloads/meshtastic/meshtastic-device/total)
## This repository contains the device firmware used in the [Meshtastic](https://meshtastic.org) project.
Update Instructions
[For ESP32 devices click here](https://meshtastic.org/docs/getting-started/flashing-esp32)
[For nRF52 devices click here](https://meshtastic.org/docs/getting-started/flashing-nrf52)
For developer information and specific building instructions, please see the [developer doccumentation](https://meshtastic.org/docs/developers)

View File

@@ -1,15 +1,15 @@
#!/usr/bin/env bash
#!/bin/bash
set -e
VERSION=`bin/buildinfo.py long`
SHORT_VERSION=`bin/buildinfo.py short`
BOARDS_ESP32="rak11200 tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1"
BOARDS_ESP32="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v2.0 heltec-v2.1 tbeam0.7"
#BOARDS_ESP32=tbeam
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
BOARDS_NRF52="rak4631_5005 rak4631_19003 t-echo"
BOARDS_NRF52="rak4631 t-echo"
#BOARDS_NRF52=""
OUTDIR=release/latest
@@ -28,7 +28,7 @@ function do_build() {
BOARD=$1
isNrf=$3
echo "Building for $BOARD ($isNrf) with $PLATFORMIO_BUILD_FLAGS"
echo "Building for $BOARD with $PLATFORMIO_BUILD_FLAGS"
rm -f .pio/build/$BOARD/firmware.*
# The shell vars the build tool expects to find
@@ -59,7 +59,6 @@ function do_boards() {
declare isNrf=$2
for board in $boards; do
# Build universal
echo "about to build $board $isNrf"
do_build $board "" "$isNrf"
done
}

38
bin/build-nightly.sh Executable file
View File

@@ -0,0 +1,38 @@
#!/bin/bash
source ~/.bashrc
# Meshtastic Nightly Build Script.
# McHamster (jm@casler.org)
#
# This is the script that is used for the nightly build server.
#
# It's probably not useful for most people, but you may want to run your own
# nightly builds.
#
# The last line of ~/.bashrc contains an inclusion of platformio in the path.
# Without this, the build script won't run from the crontab:
#
# export PATH="$HOME/.platformio/penv/bin:$PATH"
#
# The crontab contains:
# 0 2 * * * cd ~/meshtastic/github/meshtastic && source "~/.bashrc"; ./build-nightly.sh > ~/cronout.txt 2> ~/cronout.txt
cd Meshtastic-device
git pull
bin/build-all.sh
date_stamp=$(date +'%Y-%m-%d')
cd ..
# TODO: Archive the same binaries used by the build-all script.
#zip -r meshtastic_device_nightly_${date_stamp} Meshtastic-device/release/latest/bins
cp Meshtastic-device/release/archive/`ls -t ./Meshtastic-device/release/archive/| head -1` meshtastic_device_nightly_${date_stamp}.zip
# Copy the file to the webserver
scp meshtastic_device_nightly_${date_stamp}.zip jm@10.11.12.20:/volume1/web/meshtastic/nightly_builds/
# Delete the local copy
rm meshtastic_device_nightly_${date_stamp}.zip

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env bash
# Note: This is a prototype for how we could add static code analysis to the CI.
set -e
VERSION=`bin/buildinfo.py long`
# The shell vars the build tool expects to find
export APP_VERSION=$VERSION
if [[ $# -gt 0 ]]; then
# can override which environment by passing arg
BOARDS="$@"
else
BOARDS="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1 rak4631_5005 rak4631_19003 rak11200 t-echo"
fi
echo "BOARDS:${BOARDS}"
CHECK=""
for BOARD in $BOARDS; do
CHECK="${CHECK} -e ${BOARD}"
done
pio check --flags "-DAPP_VERSION=${APP_VERSION} --suppressions-list=suppressions.txt" $CHECK --skip-packages --pattern="src/" --fail-on-defect=low --fail-on-defect=medium --fail-on-defect=high

View File

@@ -11,7 +11,7 @@ Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME]
Flash image file to device, but first erasing and writing system information"
-h Display this help and exit
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
-f FILENAME The .bin file to flash. Custom to your device type and region.
EOF
@@ -46,10 +46,10 @@ shift "$((OPTIND-1))"
if [ -f "${FILENAME}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
"$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x1000 system-info.bin
"$PYTHON" -m esptool write_flash 0x00390000 spiffs-*.bin
"$PYTHON" -m esptool write_flash 0x10000 ${FILENAME}
$PYTHON -m esptool --baud 921600 erase_flash
$PYTHON -m esptool --baud 921600 write_flash 0x1000 system-info.bin
$PYTHON -m esptool --baud 921600 write_flash 0x00390000 spiffs-*.bin
$PYTHON -m esptool --baud 921600 write_flash 0x10000 ${FILENAME}
else
echo "Invalid file: ${FILENAME}"
show_help

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
arm-none-eabi-readelf -s -e .pio/build/nrf52dk/firmware.elf | head -80
nm -CSr --size-sort .pio/build/nrf52dk/firmware.elf | grep '^200'

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
set -e

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/python2
# This is a layout for 4MB of flash
# Name, Type, SubType, Offset, Size, Flags
@@ -38,4 +38,4 @@ app0, app, ota_0, , 0x{app:x},
app1, app, ota_1, , 0x{app:x},
spiffs, data, spiffs, , 0x{spi:x} """.format(**locals())
print(table)
print(table)

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
# You probably don't want to use this script, it programs a custom bootloader build onto a nrf52 board
set -e

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
# You probably don't want to use this script, it programs a custom bootloader build onto a nrf52 board
set -e

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env bash
mosquitto_sub -h mqtt.meshtastic.org -v -t \$SYS/\# -t msh/+/stat/\# -t msh/+/json/\#
# mosquitto_sub -h test.mosquitto.org -v -t mesh/\# -F "%j"

View File

@@ -1,3 +1 @@
#!/usr/bin/env bash
mosquitto_pub -h mqtt.meshtastic.org -u meshdev -P large4cats -t msh/1/stat/FakeNode -m online -d

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
set -e
pio run --environment native
gdbserver --once localhost:2345 .pio/build/native/program "$@"

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
set -e
pio run --environment native
.pio/build/native/program "$@"

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
# JLinkRTTViewer
JLinkRTTClient
JLinkRTTClient

View File

@@ -1,3 +1,3 @@
#!/usr/bin/env bash
JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52832_XXAA

View File

@@ -1,3 +1,3 @@
#!/usr/bin/env bash
JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52833_XXAA

View File

@@ -1,3 +1,3 @@
#!/usr/bin/env bash
JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52840_XXAA -SuppressInfoUpdateFW -DisableAutoUpdateFW -rtos GDBServer/RTOSPlugin_FreeRTOS

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
esptool.py --baud 921600 write_flash 0x10000 release/archive/old/firmware-tbeam-EU865-1.0.0.bin
echo "Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used"
esptool.py --baud 921600 erase_region 0xe000 0x2000

View File

@@ -1,3 +1 @@
#!/usr/bin/env bash
esptool.py --baud 921600 write_flash 0x10000 release/archive/old/firmware-tbeam-1.1.50.bin

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env bash
set -e

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env bash
set -e

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env bash
set -e

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
set -e
echo "This script is only for developers who are publishing new builds on github. Most users don't need it"
@@ -8,10 +6,6 @@ VERSION=`bin/buildinfo.py long`
# Must have a V prefix to trigger github
git tag "v${VERSION}"
# Commented out per https://github.com/meshtastic/Meshtastic-device/issues/947
#git push root "v${VERSION}" # push the tag
git push origin "v${VERSION}" # push the tag
git push root "v${VERSION}" # push the tag
echo "Tag ${VERSION} pushed to github, github actions should now be building the draft release. If it seems good, click to publish it"

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
# You probably don't need this - it is a basic test of the serial flash on the TTGO eink board
nrfjprog --qspiini nrf52/ttgo_eink_qpsi.ini --qspieraseall

View File

@@ -1,3 +1 @@
#!/usr/bin/env bash
esptool.py --baud 921600 read_flash 0x1000 0xf000 system-info.img

View File

@@ -1 +0,0 @@
cd proto && ..\nanopb-0.4.4\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\proto *.proto

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
set -e
@@ -12,4 +12,4 @@ cd proto
#echo "Regenerating protobuf documentation - if you see an error message"
#echo "you can ignore it unless doing a new protobuf release to github."
#bin/regen-docs.sh
#bin/regen-docs.sh

View File

@@ -1,3 +1 @@
#!/usr/bin/env bash
pio run --upload-port /dev/ttyUSB0 -t upload -t monitor

View File

@@ -1,3 +1 @@
#!/usr/bin/env bash
pio run --upload-port /dev/ttyUSB1 -t upload -t monitor

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
set -e
echo uploading to usb1

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
set -e
TARG=tbeam

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
# /home/kevinh/.platformio/packages/tool-openocd-esp32/bin/openocd -s /home/kevinh/.platformio/packages/tool-openocd-esp32 -c gdb_port pipe; tcl_port disabled; telnet_port disabled -s /home/kevinh/.platformio/packages/tool-openocd-esp32/share/openocd/scripts -f interface/jlink.cfg -f board/esp-wroom-32.cfg
/home/kevinh/.platformio/packages/tool-openocd-esp32/bin/openocd -s /home/kevinh/.platformio/packages/tool-openocd-esp32 -s /home/kevinh/.platformio/packages/tool-openocd-esp32/share/openocd/scripts -f interface/jlink.cfg -f ./lora32-openocd.cfg

View File

@@ -1,3 +1 @@
#!/usr/bin/env bash
pio device monitor -b 921600

View File

@@ -1,3 +1 @@
#!/usr/bin/env bash
pio device monitor -p /dev/ttyUSB1 -b 921600

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
set -e
echo "Starting simulator"

View File

@@ -1,2 +0,0 @@
@echo off
if [%1]==[] (echo "Please specify a platformio NRF target (i.e. rak4631) as the first argument.") else (python3 .\bin\uf2conv.py .\.pio\build\%1\firmware.hex -c -o .\.pio\build\%1\firmware.uf2 -f 0xADA52840)

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
set -e
echo "building for t-echo"

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
set -e
echo "Converting to uf2 for NRF52 Adafruit bootloader"

View File

@@ -1,3 +1 @@
#!/usr/bin/env bash
pio run --upload-port /dev/ttyUSB1 -t upload

View File

@@ -1,4 +1,2 @@
#!/usr/bin/env bash
echo using amap tool to display memory map
amap .pio/build/output.map

View File

@@ -16,9 +16,9 @@
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_flags": "-DS113",
"sd_name": "s113",
"sd_version": "7.2.0",
"sd_fwid": "0x00B6"
},
"bootloader": {

View File

@@ -1,39 +0,0 @@
{
"build": {
"arduino":{
"ldscript": "esp32_out.ld"
},
"core": "esp32",
"extra_flags": "-DARDUINO_ESP32_DEV",
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "WisCore_RAK11200_Board"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"frameworks": [
"arduino",
"espidf"
],
"name": "WisCore RAK11200 Board",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"protocols": [
"esptool",
"espota",
"ftdi"
],
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.rakwireless.com",
"vendor": "RAKwireless"
}

View File

1
data/static/index.html Normal file
View File

@@ -0,0 +1 @@
not yet supported - soon will be included in build

BIN
deprecated/icon-18dp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

1
deprecated/icon-24px.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 5c-3.87 0-7 3.13-7 7h2c0-2.76 2.24-5 5-5s5 2.24 5 5h2c0-3.87-3.13-7-7-7zm1 9.29c.88-.39 1.5-1.26 1.5-2.29 0-1.38-1.12-2.5-2.5-2.5S9.5 10.62 9.5 12c0 1.02.62 1.9 1.5 2.29v3.3L7.59 21 9 22.41l3-3 3 3L16.41 21 13 17.59v-3.3zM12 1C5.93 1 1 5.93 1 12h2c0-4.97 4.03-9 9-9s9 4.03 9 9h2c0-6.07-4.93-11-11-11z"/></svg>

After

Width:  |  Height:  |  Size: 442 B

BIN
deprecated/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,17 +0,0 @@
To build:
docker build -t meshtastic/device .
To run:
docker run --rm -p 4403:4403 meshtastic/device
or, to get a shell on the docker image:
docker run -it meshtastic/device bash
To use python cli against it:
meshtastic --info --host localhost
To stop:
# run this to get id
docker ps
# tip: you can just use the first few characters of the id in the next command
docker kill <id>

View File

@@ -325,7 +325,7 @@ Items after the first final candidate release.
- add "store and forward" support for messages, or move to the DB sync model. This would allow messages to be eventually delivered even if nodes are out of contact at the moment.
- use variable length Strings in protobufs (instead of current fixed buffers). This would save lots of RAM
- use BLEDevice::setPower to lower our BLE transmit power - extra range doesn't help us, it costs amps and it increases snoopability
- make a Ham build: just a new frequency list, a bool to say 'never do encryption' and use the callsign as that node's unique id. -from Girts
- make a HAM build: just a new frequency list, a bool to say 'never do encryption' and use hte callsign as that node's unique id. -from Girts
- don't forward redundant pings or ping responses to the phone, it just wastes phone battery
- don't send location packets if we haven't moved significantly
- scrub default radio config settings for bandwidth/range/speed

View File

@@ -20,6 +20,4 @@ make
* todo run hello world on hardware (check for bl604 vs bl602 first)
* build/run in the crummy arduino environment
* build in platformio
https://lupyuen.github.io/articles/lorawan2
* build in platformio

View File

@@ -0,0 +1,7 @@
* install python
* install git (including git-bash)
* install platformio
* install vscode
* install https://sourceforge.net/projects/mingw-w64/ (for windows gcc/g++) - you'll need to add the bin directory to your PATH

View File

@@ -9,28 +9,18 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = tbeam
;default_envs = tbeam
;default_envs = tbeam0.7
;default_envs = heltec-v1
;default_envs = heltec-v2.0
;default_envs = heltec-v2.1
;default_envs = tlora-v1
;default_envs = tlora-v1
;default_envs = tlora_v1_3
;default_envs = tlora-v2
;default_envs = tlora-v2-1-1.6
;default_envs = lora-relay-v1 # nrf board
;default_envs = t-echo
default_envs = t-echo
;default_envs = nrf52840dk-geeksville
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
;default_envs = rak4631
;default_envs = rak4630
;default_envs = meshtastic-diy-v1
;default_envs = meshtastic-diy-v1.1
; board specific config can be moved to the respective 'variants' file.
; See https://docs.platformio.org/en/latest/projectconf/section_platformio.html#extra-configs
extra_configs = variants/*/platformio.ini
[common]
; common is not currently used
@@ -77,24 +67,20 @@ debug_tool = jlink
; monitor adapter_khz 10000
lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#d90231dedbb2f52bd7a32fb8ed8edec52cf4a8cb ; ESP8266_SSD1306
https://github.com/meshtastic/OneButton.git#3bcba9492d01e2a8a86f46700ab16f96dd2cf1f5 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
https://github.com/meshtastic/arduino-fsm.git
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
https://github.com/meshtastic/RadioLib.git#80ed10d689a0568782c5bd152906b0f97d2bce93
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
Wire ; explicitly needed here because the AXP202 library forgets to add it
SPI
https://github.com/geeksville/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
PubSubClient
; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck
check_skip_packages = yes
; Common settings for conventional (non Portduino) Arduino targets
; Common settings for conventional (non Portduino) Ardino targets
[arduino_base]
framework = arduino
@@ -107,17 +93,6 @@ build_flags = ${env.build_flags} -Os
src_filter = ${env.src_filter} -<portduino/>
; Common libs for environmental measurements (not included in native / portduino)
[environmental]
lib_deps =
adafruit/DHT sensor library@^1.4.1
adafruit/Adafruit Unified Sensor@^1.1.4
paulstoffregen/OneWire@^2.3.5
robtillaart/DS18B20@^0.1.11
adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BME680 Library@^2.0.1
adafruit/Adafruit MCP9808 Library@^2.0.0
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base
@@ -126,33 +101,23 @@ src_filter =
${arduino_base.src_filter} -<nrf52/>
upload_speed = 921600
debug_init_break = tbreak setup
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
build_flags =
${arduino_base.build_flags} -Wall -Wextra -Isrc/esp32 -Isrc/esp32-mfix-esp32-psram-cache-issue -lnimble -std=c++11
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
-DAXP_DEBUG_PORT=Serial
lib_deps =
${arduino_base.lib_deps}
${environmental.lib_deps}
https://github.com/meshtastic/esp32_https_server.git
h2zero/NimBLE-Arduino@1.3.6
tobozo/ESP32-targz@^1.1.4
arduino-libraries/NTPClient#531eff39d9fbc831f3d03f706a161739203fbe2a
adafruit/DHT sensor library@^1.4.1
adafruit/Adafruit Unified Sensor@^1.1.4
# Hmm - this doesn't work yet
# board_build.ldscript = linker/esp32.extram.bss.ld
lib_ignore =
segger_rtt
ESP32 BLE Arduino
lib_ignore = segger_rtt
platform_packages =
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#4cde0f5d412d2695184f32e8a47e9bea57b45276
; leave this commented out to avoid breaking Windows
;upload_port = /dev/ttyUSB0
upload_port = /dev/ttyUSB0
;monitor_port = /dev/ttyUSB0
;upload_port = /dev/cu.SLAB_USBtoUART
@@ -169,6 +134,62 @@ board_build.partitions = partition-table.csv
; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
; The 1.0 release of the TBEAM board
[env:tbeam]
extends = esp32_base
board = ttgo-t-beam
lib_deps =
${esp32_base.lib_deps}
build_flags =
${esp32_base.build_flags} -D TBEAM_V10
; The original TBEAM board without the AXP power chip and a few other changes
; Note: I've heard reports this didn't work. Disabled until someone with a 0.7 can test and debug.
[env:tbeam0.7]
extends = esp32_base
board = ttgo-t-beam
build_flags =
${esp32_base.build_flags} -D TBEAM_V07
[env:heltec-v2.0]
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32_V2
build_flags =
${esp32_base.build_flags} -D HELTEC_V2_0
[env:heltec-v2.1]
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32_V2
build_flags =
${esp32_base.build_flags} -D HELTEC_V2_1
[env:tlora-v1]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TLORA_V1
; note: the platformio definition for lora32-v2 seems stale, it is missing a pins_arduino.h file, therefore I don't think it works
[env:tlora_v1_3]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TLORA_V1_3
[env:tlora-v2]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TLORA_V2
[env:tlora-v2-1-1.6]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TLORA_V2_1_16
; The Heltec Cubecell plus
; IMPORTANT NOTE: This target doesn't yet work and probably won't ever work. I'm keeping it around for now.
; For more details see my post in the forum.
@@ -238,17 +259,42 @@ extends = nrf52_base
build_flags = ${nrf52_base.build_flags}
lib_deps =
${arduino_base.lib_deps}
${environmental.lib_deps}
Adafruit nRFCrypto
# Adafruit TinyUSB Arduino
# add Adafruit nRFCrypto platform IO automated scan is broken
[env:lora_isp4520]
extends = nrf52_base
board = lora_isp4520
# add our variants files to the include and src paths
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_isp4520
# No screen and GPS on the board. We still need RTC.cpp for the RTC clock.
src_filter = ${nrf52_base.src_filter} +<../variants/lora_isp4520> -<graphics> -<gps> +<gps/GPS.cpp> +<gps/RTC.cpp>
lib_ignore = ${nrf52_base.lib_ignore}
ESP8266_SSD1306
SparkFun Ublox Arduino Library
AXP202X_Library
TinyGPSPlus
upload_protocol = jlink
monitor_port = /dev/ttyUSB0
; The NRF52840-dk development board
; Note: By default no lora device is created for this build - it uses a simulated interface
[env:nrf52840dk]
extends = nrf52840_base
board = nrf52840_dk
; The NRF52840-dk development board, but @geeksville's board - which has a busted oscilliator
[env:nrf52840dk-geeksville]
extends = nrf52840_base
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
[env:feather_nrf52832]
extends = nrf52_base
@@ -264,4 +310,153 @@ monitor_port = /dev/ttyUSB0
monitor_speed = 115200
# For experimenting with RAM sizes
# board_build.ldscript = linker/nrf52840_s140_sim832.ld
# board_build.ldscript = linker/nrf52840_s140_sim832.ld
; The very slick RAK wireless RAK 4631 / 4630 board
[env:rak4631]
extends = nrf52840_base
board = wiscore_rak4631
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/WisCore_RAK4631_Board
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4631_Board>
debug_tool = jlink
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
;upload_protocol = jlink
; Note, this board is not yet supported! It will not work without futher development.
; THIS IS UNTESTED (I don't have this board), but other developers can use it as a starting point
[env:rak4600]
extends = nrf52_base
board = wiscore_rak4600
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52_base.build_flags} -Ivariants/WisCore_RAK4600_Board
src_filter = ${nrf52_base.src_filter} +<../variants/WisCore_RAK4600_Board>
lib_deps =
${arduino_base.lib_deps}
; The PPR board
[env:ppr]
extends = nrf52_base
board = ppr
lib_deps =
${arduino_base.lib_deps}
UC1701
; The PPR board
[env:ppr1]
extends = nrf52_base
board = ppr1
build_flags = ${nrf52_base.build_flags} -Ivariants/ppr1
src_filter = ${nrf52_base.src_filter} +<../variants/ppr1>
lib_deps =
${arduino_base.lib_deps}
; First prototype eink/nrf52840/sx1262 device
[env:t-echo]
extends = nrf52840_base
board = t-echo
debug_tool = jlink
upload_protocol = jlink
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library - NOTE: WE NOT LONGER USE TFT_eSPI, it was for an earlier version of the TTGO eink screens
# -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling.
build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo
src_filter = ${nrf52_base.src_filter} +<../variants/t-echo>
lib_deps =
${nrf52840_base.lib_deps}
https://github.com/geeksville/GxEPD2.git
adafruit/Adafruit BusIO
;upload_protocol = fs
; First prototype eink/nrf52840/sx1262 device (removed from build because didn't ship in quantity)
;[env:eink0.1]
;extends = nrf52840_base
;board = eink0.1
;# add our variants files to the include and src paths
;# define build flags for the TFT_eSPI library
;build_flags = ${nrf52_base.build_flags} -Ivariants/eink0.1
; -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
;src_filter = ${nrf52_base.src_filter} +<../variants/eink0.1>
;lib_deps =
; ${nrf52840_base.lib_deps}
; https://github.com/geeksville/EPD_Libraries.git
; TFT_eSPI
; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus
[env:lora-relay-v1]
extends = nrf52840_base
board = lora-relay-v1
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v1
-DUSER_SETUP_LOADED
-DTFT_WIDTH=80
-DTFT_HEIGHT=160
-DST7735_GREENTAB160x80
-DST7735_DRIVER
-DTFT_CS=ST7735_CS
-DTFT_DC=ST7735_RS
-DTFT_RST=ST7735_RESET
-DSPI_FREQUENCY=27000000
src_filter = ${nrf52_base.src_filter} +<../variants/lora_relay_v1>
lib_deps =
${nrf52840_base.lib_deps}
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
TFT_eSPI
; The https://github.com/BigCorvus/LoRa-BLE-Relay-v2 board by @BigCorvus
[env:lora-relay-v2]
extends = nrf52840_base
board = lora-relay-v2
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v2
-DUSER_SETUP_LOADED
-DTFT_WIDTH=80
-DTFT_HEIGHT=160
-DST7735_GREENTAB160x80
-DST7735_DRIVER
-DTFT_CS=ST7735_CS
-DTFT_DC=ST7735_RS
-DTFT_RST=ST7735_RESET
-DSPI_FREQUENCY=27000000
-DTFT_WR=ST7735_SDA
-DTFT_SCLK=ST7735_SCK
src_filter = ${nrf52_base.src_filter} +<../variants/lora_relay_v2>
lib_deps =
${nrf52840_base.lib_deps}
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
TFT_eSPI
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[env:native]
platform = https://github.com/geeksville/platform-native.git
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
build_flags = ${arduino_base.build_flags} -O0
framework = arduino
board = cross_platform
lib_deps =
${arduino_base.lib_deps}
rweather/Crypto
; The Portduino based sim environment on top of a linux OS and touching linux hardware devices
[env:linux]
platform = https://github.com/geeksville/platform-native.git
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
build_flags = ${arduino_base.build_flags} -O0 -lgpiod
framework = arduino
board = linux_hardware
lib_deps =
${arduino_base.lib_deps}
rweather/Crypto
; The GenieBlocks LORA prototype board
; note: @geeksville disabled because genieblocks_lora is not checked into the boards directory, please send in a PR to add it ;-)
;[env:genieblocks_lora]
;extends = esp32_base
;board = genieblocks_lora
;build_flags =
; ${esp32_base.build_flags} -D GENIEBLOCKS

2
proto

Submodule proto updated: 2930129e8e...f5b3d0643b

1
src/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
main.ino.cpp

View File

@@ -1,61 +0,0 @@
// DEBUG LED
#ifndef LED_INVERTED
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
#endif
// -----------------------------------------------------------------------------
// DEBUG
// -----------------------------------------------------------------------------
#ifdef CONSOLE_MAX_BAUD
#define SERIAL_BAUD CONSOLE_MAX_BAUD
#else
#define SERIAL_BAUD 921600 // Serial debug baud rate
#endif
#include "SerialConsole.h"
#define DEBUG_PORT (*console) // Serial debug port
// What platforms should use SEGGER?
#ifdef NRF52_SERIES
// Always include the SEGGER code on NRF52 - because useful for debugging
#include "SEGGER_RTT.h"
// The channel we send stdout data to
#define SEGGER_STDOUT_CH 0
// Debug printing to segger console
#define SEGGER_MSG(...) SEGGER_RTT_printf(SEGGER_STDOUT_CH, __VA_ARGS__)
// 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
// 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
#define USE_SEGGER
#endif
#else
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
#endif
#ifdef USE_SEGGER
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
#ifdef DEBUG_PORT
#define DEBUG_MSG(...) DEBUG_PORT.logDebug(__VA_ARGS__)
#else
#define DEBUG_MSG(...)
#endif
#endif
// -----------------------------------------------------------------------------
// AXP192 (Rev1-specific options)
// -----------------------------------------------------------------------------
#define GPS_POWER_CTRL_CH 3
#define LORA_POWER_CTRL_CH 2
// Default Bluetooth PIN
#define defaultBLEPin 123456

View File

@@ -1,11 +1,8 @@
#pragma once
#include "Status.h"
#include "configuration.h"
#include "NodeDB.h"
#include <Arduino.h>
extern NodeDB nodeDB;
namespace meshtastic
{
@@ -19,39 +16,28 @@ class GPSStatus : public Status
bool hasLock = false; // default to false, until we complete our first read
bool isConnected = false; // Do we have a GPS we are talking to
Position p = Position_init_default;
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
int32_t altitude = 0;
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs
// scaling before use)
uint32_t heading = 0;
uint32_t numSatellites = 0;
public:
GPSStatus() { statusType = STATUS_TYPE_GPS; }
// proposed for deprecation
GPSStatus(bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop,
uint32_t heading, uint32_t numSatellites)
: Status()
{
this->hasLock = hasLock;
this->isConnected = isConnected;
this->p.latitude_i = latitude;
this->p.longitude_i = longitude;
this->p.altitude = altitude;
this->p.PDOP = dop;
this->p.ground_track = heading;
this->p.sats_in_view = numSatellites;
this->latitude = latitude;
this->longitude = longitude;
this->altitude = altitude;
this->dop = dop;
this->heading = heading;
this->numSatellites = numSatellites;
}
// preferred method
GPSStatus(bool hasLock, bool isConnected, const Position& pos)
: Status()
{
this->hasLock = hasLock;
this->isConnected = isConnected;
// all-in-one struct copy
this->p = pos;
}
GPSStatus(const GPSStatus &);
GPSStatus &operator=(const GPSStatus &);
@@ -61,91 +47,45 @@ class GPSStatus : public Status
bool getIsConnected() const { return isConnected; }
int32_t getLatitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed latitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
return node->position.latitude_i;
} else {
return p.latitude_i;
}
}
int32_t getLatitude() const { return latitude; }
int32_t getLongitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed longitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
return node->position.longitude_i;
} else {
return p.longitude_i;
}
}
int32_t getLongitude() const { return longitude; }
int32_t getAltitude() const {
if (radioConfig.preferences.fixed_position){
#if GPS_EXTRAVERBOSE
DEBUG_MSG("WARNING: Using fixed altitude\n");
#endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
return node->position.altitude;
} else {
return p.altitude;
}
}
int32_t getAltitude() const { return altitude; }
uint32_t getDOP() const { return p.PDOP; }
uint32_t getDOP() const { return dop; }
uint32_t getHeading() const { return p.ground_track; }
uint32_t getHeading() const { return heading; }
uint32_t getNumSatellites() const { return p.sats_in_view; }
uint32_t getNumSatellites() const { return numSatellites; }
bool matches(const GPSStatus *newStatus) const
{
#if GPS_EXTRAVERBOSE
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n",
newStatus->p.pos_timestamp, p.pos_timestamp);
#endif
return (newStatus->hasLock != hasLock ||
newStatus->isConnected != isConnected ||
newStatus->p.latitude_i != p.latitude_i ||
newStatus->p.longitude_i != p.longitude_i ||
newStatus->p.altitude != p.altitude ||
newStatus->p.altitude_hae != p.altitude_hae ||
newStatus->p.PDOP != p.PDOP ||
newStatus->p.ground_track != p.ground_track ||
newStatus->p.sats_in_view != p.sats_in_view);
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->latitude != latitude ||
newStatus->longitude != longitude || newStatus->altitude != altitude || newStatus->dop != dop ||
newStatus->heading != heading || newStatus->numSatellites != numSatellites);
}
int updateStatus(const GPSStatus *newStatus)
{
// Only update the status if values have actually changed
bool isDirty = matches(newStatus);
if (isDirty && p.pos_timestamp &&
(newStatus->p.pos_timestamp == p.pos_timestamp)) {
// We can NEVER be in two locations at the same time! (also PR #886)
DEBUG_MSG("BUG!! positional timestamp unchanged from prev solution\n");
bool isDirty;
{
isDirty = matches(newStatus);
initialized = true;
hasLock = newStatus->hasLock;
isConnected = newStatus->isConnected;
latitude = newStatus->latitude;
longitude = newStatus->longitude;
altitude = newStatus->altitude;
dop = newStatus->dop;
heading = newStatus->heading;
numSatellites = newStatus->numSatellites;
}
initialized = true;
hasLock = newStatus->hasLock;
isConnected = newStatus->isConnected;
p = newStatus->p;
if (isDirty) {
if (hasLock) {
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
DEBUG_MSG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, sats=%d\n",
p.pos_timestamp,
p.latitude_i * 1e-7, p.longitude_i * 1e-7,
p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
p.sats_in_view);
} else
if (hasLock)
DEBUG_MSG("New GPS pos lat=%f, lon=%f, alt=%d, pdop=%f, heading=%f, sats=%d\n", latitude * 1e-7, longitude * 1e-7,
altitude, dop * 1e-2, heading * 1e-5, numSatellites);
else
DEBUG_MSG("No GPS lock\n");
onNewStatus.notifyObservers(this);
}
@@ -155,4 +95,4 @@ class GPSStatus : public Status
} // namespace meshtastic
extern meshtastic::GPSStatus *gpsStatus;
extern meshtastic::GPSStatus *gpsStatus;

View File

@@ -47,7 +47,7 @@ template <class Callback, class T> class CallbackObserver : public Observer<T>
CallbackObserver(Callback *_objPtr, ObserverCallback _method) : objPtr(_objPtr), method(_method) {}
protected:
virtual int onNotify(T arg) override { return (objPtr->*method)(arg); }
virtual int onNotify(T arg) { return (objPtr->*method)(arg); }
};
/**
@@ -104,4 +104,4 @@ template <class T> void Observer<T>::observe(Observable<T> *o)
observed = o;
o->addObserver(this);
}
}

View File

@@ -75,7 +75,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
*
* FIXME - use a lipo lookup table, the current % full is super wrong
*/
virtual int getBattPercentage() override
virtual int getBattPercentage()
{
float v = getBattVoltage();
@@ -94,16 +94,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
/**
* The raw voltage of the batteryin millivolts or NAN if unknown
*/
virtual float getBattVoltage() override
virtual float getBattVoltage()
{
#ifndef ADC_MULTIPLIER
#define ADC_MULTIPLIER 2.0
#endif
// Override variant or default ADC_MULTIPLIER if we have the override pref
float operativeAdcMultiplier = radioConfig.preferences.adc_multiplier_override > 0 ?
radioConfig.preferences.adc_multiplier_override :
ADC_MULTIPLIER;
#ifdef BATTERY_PIN
// Do not call analogRead() often.
@@ -113,7 +109,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
uint32_t raw = analogRead(BATTERY_PIN);
float scaled;
#ifndef VBAT_RAW_TO_SCALED
scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw;
scaled = 1000.0 * ADC_MULTIPLIER * (AREF_VOLTAGE / 1024.0) * raw;
#else
scaled = VBAT_RAW_TO_SCALED(raw); //defined in variant.h
#endif
@@ -131,15 +127,15 @@ class AnalogBatteryLevel : public HasBatteryLevel
/**
* return true if there is a battery installed in this unit
*/
virtual bool isBatteryConnect() override { return getBattPercentage() != -1; }
virtual bool isBatteryConnect() { return getBattPercentage() != -1; }
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
virtual bool isVBUSPlug() override { return getBattVoltage() > chargingVolt; }
virtual bool isVBUSPlug() { return getBattVoltage() > chargingVolt; }
/// Assume charging if we have a battery and external power is connected.
/// we can't be smart enough to say 'full'?
virtual bool isChargeing() override { return isBatteryConnect() && isVBUSPlug(); }
virtual bool isChargeing() { return isBatteryConnect() && isVBUSPlug(); }
private:
/// If we see a battery voltage higher than physics allows - assume charger is pumping
@@ -153,10 +149,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
AnalogBatteryLevel analogLevel;
Power::Power() : OSThread("Power") {
statusHandler = {};
low_voltage_counter = 0;
}
Power::Power() : OSThread("Power") {}
bool Power::analogInit()
{
@@ -199,7 +192,6 @@ bool Power::setup()
found = analogInit();
}
enabled = found;
low_voltage_counter = 0;
return found;
}
@@ -239,35 +231,20 @@ void Power::readPowerStatus()
}
// Notify any status instances that are observing us
const PowerStatus powerStatus2 =
const PowerStatus powerStatus =
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse,
batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus2);
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus.getHasUSB(),
powerStatus.getIsCharging(), powerStatus.getBatteryVoltageMv(), powerStatus.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus);
// If we have a battery at all and it is less than 10% full, force deep sleep if we have more than 3 low readings in a row
// Supect fluctuating voltage on the RAK4631 to force it to deep sleep even if battery is at 85% after only a few days
#ifdef NRF52_SERIES
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()){
if (batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS){
low_voltage_counter++;
if (low_voltage_counter>3)
powerFSM.trigger(EVENT_LOW_BATTERY);
} else {
low_voltage_counter = 0;
}
}
#else
// If we have a battery at all and it is less than 10% full, force deep sleep
if (powerStatus2.getHasBattery() && !powerStatus2.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
powerFSM.trigger(EVENT_LOW_BATTERY);
#endif
} else {
// No power sensing on this board - tell everyone else we have no idea what is happening
const PowerStatus powerStatus3 = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
newStatus.notifyObservers(&powerStatus3);
const PowerStatus powerStatus = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
newStatus.notifyObservers(&powerStatus);
}
}

View File

@@ -1,8 +1,8 @@
#include "configuration.h"
#include "PowerFSM.h"
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "configuration.h"
#include "graphics/Screen.h"
#include "main.h"
#include "sleep.h"
@@ -11,11 +11,6 @@
/// Should we behave as if we have AC power now?
static bool isPowered()
{
// Completely circumvents the battery / power sensing logic and assumes constant power source
if (radioConfig.preferences.is_always_powered) {
return true;
}
bool isRouter = radioConfig.preferences.is_router;
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
@@ -37,14 +32,6 @@ static void sdsEnter()
doDeepSleep(getPref_sds_secs() * 1000LL);
}
extern Power *power;
static void shutdownEnter()
{
DEBUG_MSG("Enter state: SHUTDOWN\n");
power->shutdown();
}
#include "error.h"
static uint32_t secsSlept;
@@ -63,6 +50,7 @@ static void lsIdle()
// DEBUG_MSG("lsIdle begin ls_secs=%u\n", getPref_ls_secs());
#ifndef NO_ESP32
esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED;
// Do we have more sleeping to do?
if (secsSlept < getPref_ls_secs()) {
@@ -72,14 +60,14 @@ static void lsIdle()
// If some other service would stall sleep, don't let sleep happen yet
if (doPreflightSleep()) {
setLed(false); // Never leave led on while in light sleep
esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL);
wakeCause = doLightSleep(sleepTime * 1000LL);
switch (wakeCause2) {
switch (wakeCause) {
case ESP_SLEEP_WAKEUP_TIMER:
// Normal case: timer expired, we should just go back to sleep ASAP
setLed(true); // briefly turn on led
wakeCause2 = doLightSleep(1); // leave led on for 1ms
wakeCause = doLightSleep(1); // leave led on for 1ms
secsSlept += sleepTime;
// DEBUG_MSG("sleeping, flash led!\n");
@@ -93,7 +81,7 @@ static void lsIdle()
default:
// We woke for some other reason (button press, device interrupt)
// uint64_t status = esp_sleep_get_ext1_wakeup_status();
DEBUG_MSG("wakeCause2 %d\n", wakeCause2);
DEBUG_MSG("wakeCause %d\n", wakeCause);
#ifdef BUTTON_PIN
bool pressed = !digitalRead(BUTTON_PIN);
@@ -220,12 +208,10 @@ static void screenPress()
screen->onPress();
}
static void bootEnter()
{
static void bootEnter() {
DEBUG_MSG("Enter state: BOOT\n");
}
State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN");
State stateSDS(sdsEnter, NULL, NULL, "SDS");
State stateLS(lsEnter, lsIdle, lsExit, "LS");
State stateNB(nbEnter, NULL, NULL, "NB");
@@ -248,10 +234,8 @@ void PowerFSM_setup()
// if we are a router node, we go to NB (no need for bluetooth) otherwise we go to DARK (so we can send message to phone)
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
// We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from
// light sleep we _always_ transition to NB or dark and
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL,
"Received packet, exiting light sleep");
// We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from light sleep we _always_ transition to NB or dark and
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, exiting light sleep");
powerFSM.add_transition(&stateNB, &stateNB, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, resetting win wake");
// Handle press events - note: we ignore button presses when in API mode
@@ -271,14 +255,6 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateON, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateSERIAL, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
// Handle being told to power off
powerFSM.add_transition(&stateBOOT, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown");
powerFSM.add_transition(&stateLS, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown");
powerFSM.add_transition(&stateNB, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown");
powerFSM.add_transition(&stateDARK, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown");
powerFSM.add_transition(&stateON, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown");
powerFSM.add_transition(&stateSERIAL, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
@@ -336,23 +312,15 @@ void PowerFSM_setup()
#ifndef NRF52_SERIES
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
// See: https://github.com/meshtastic/Meshtastic-device/issues/1071
if (isRouter || radioConfig.preferences.is_power_saving) {
// I don't think this transition is correct, turning off for now - @geeksville
// powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
meshSds = getPref_mesh_sds_timeout_secs();
} else {
meshSds = UINT32_MAX;
}
// I don't think this transition is correct, turning off for now - @geeksville
// powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
meshSds = getPref_mesh_sds_timeout_secs();
#else
lowPowerState = &stateDARK;
meshSds = UINT32_MAX; // Workaround for now: Don't go into deep sleep on the RAK4631
meshSds = UINT32_MAX; //Workaround for now: Don't go into deep sleep on the RAK4631
#endif
if (meshSds != UINT32_MAX)

View File

@@ -19,7 +19,6 @@
#define EVENT_POWER_CONNECTED 13
#define EVENT_POWER_DISCONNECTED 14
#define EVENT_FIRMWARE_UPDATE 15 // We just received a new firmware update packet from the phone
#define EVENT_SHUTDOWN 16 //force a full shutdown now (not just sleep)
extern Fsm powerFSM;
extern State statePOWER, stateSERIAL;

View File

@@ -1,7 +0,0 @@
// TODO refactor this out with better radio configuration system
#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

View File

@@ -22,7 +22,7 @@ class RedirectablePrint : public Print
volatile bool inDebugPrint = false;
public:
explicit RedirectablePrint(Print *_dest) : dest(_dest) {}
RedirectablePrint(Print *_dest) : dest(_dest) {}
/**
* Set a new destination
@@ -56,4 +56,4 @@ class NoopPrint : public Print
/**
* A printer that doesn't go anywhere
*/
extern NoopPrint noopPrint;
extern NoopPrint noopPrint;

View File

@@ -15,9 +15,9 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
* we override this to notice when we've received a protobuf over the serial stream. Then we shunt off
* debug serial output.
*/
virtual bool handleToRadio(const uint8_t *buf, size_t len) override;
virtual bool handleToRadio(const uint8_t *buf, size_t len);
virtual size_t write(uint8_t c) override
virtual size_t write(uint8_t c)
{
if (c == '\n') // prefix any newlines with carriage return
RedirectablePrint::write('\r');
@@ -27,7 +27,7 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
protected:
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override;
virtual bool checkIsConnected();
};
// A simple wrapper to allow non class aware code write to the console

View File

@@ -1,187 +1,107 @@
#include "airtime.h"
#include "NodeDB.h"
#include "configuration.h"
#include "airtime.h"
AirTime *airTime = NULL;
#define periodsToLog 48
AirTime *airTime;
uint32_t secondsPerPeriod = 3600;
uint32_t lastMillis = 0;
uint32_t secSinceBoot = 0;
// AirTime at;
// Don't read out of this directly. Use the helper functions.
struct airtimeStruct {
uint32_t periodTX[periodsToLog]; // AirTime transmitted
uint32_t periodRX[periodsToLog]; // AirTime received and repeated (Only valid mesh packets)
uint32_t periodRX_ALL[periodsToLog]; // AirTime received regardless of valid mesh packet. Could include noise.
uint8_t lastPeriodIndex;
} airtimes;
void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
{
if (reportType == TX_LOG) {
DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms);
this->airtimes.periodTX[0] = this->airtimes.periodTX[0] + airtime_ms;
myNodeInfo.air_period_tx[0] = myNodeInfo.air_period_tx[0] + airtime_ms;
this->utilizationTX[this->getPeriodUtilHour()] = this->utilizationTX[this->getPeriodUtilHour()] + airtime_ms;
airtimes.periodTX[0] = airtimes.periodTX[0] + airtime_ms;
} else if (reportType == RX_LOG) {
DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms);
this->airtimes.periodRX[0] = this->airtimes.periodRX[0] + airtime_ms;
myNodeInfo.air_period_rx[0] = myNodeInfo.air_period_rx[0] + airtime_ms;
airtimes.periodRX[0] = airtimes.periodRX[0] + airtime_ms;
} else if (reportType == RX_ALL_LOG) {
DEBUG_MSG("AirTime - Packet received (noise?) : %ums\n", airtime_ms);
this->airtimes.periodRX_ALL[0] = this->airtimes.periodRX_ALL[0] + airtime_ms;
airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + airtime_ms;
} else {
DEBUG_MSG("AirTime - Unknown report time. This should never happen!!\n");
}
// Log all airtime type for channel utilization
this->channelUtilization[this->getPeriodUtilMinute()] = channelUtilization[this->getPeriodUtilMinute()] + airtime_ms;
}
uint8_t AirTime::currentPeriodIndex()
uint8_t currentPeriodIndex()
{
return ((getSecondsSinceBoot() / SECONDS_PER_PERIOD) % PERIODS_TO_LOG);
return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog);
}
uint8_t AirTime::getPeriodUtilMinute() {
return (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS;
}
uint8_t AirTime::getPeriodUtilHour() {
return (getSecondsSinceBoot() / 60) % MINUTES_IN_HOUR;
}
void AirTime::airtimeRotatePeriod()
void airtimeRotatePeriod()
{
if (this->airtimes.lastPeriodIndex != this->currentPeriodIndex()) {
DEBUG_MSG("Rotating airtimes to a new period = %u\n", this->currentPeriodIndex());
if (airtimes.lastPeriodIndex != currentPeriodIndex()) {
DEBUG_MSG("Rotating airtimes to a new period = %u\n", currentPeriodIndex());
for (int i = PERIODS_TO_LOG - 2; i >= 0; --i) {
this->airtimes.periodTX[i + 1] = this->airtimes.periodTX[i];
this->airtimes.periodRX[i + 1] = this->airtimes.periodRX[i];
this->airtimes.periodRX_ALL[i + 1] = this->airtimes.periodRX_ALL[i];
myNodeInfo.air_period_tx[i + 1] = this->airtimes.periodTX[i];
myNodeInfo.air_period_rx[i + 1] = this->airtimes.periodRX[i];
for (int i = periodsToLog - 2; i >= 0; --i) {
airtimes.periodTX[i + 1] = airtimes.periodTX[i];
airtimes.periodRX[i + 1] = airtimes.periodRX[i];
airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i];
}
airtimes.periodTX[0] = 0;
airtimes.periodRX[0] = 0;
airtimes.periodRX_ALL[0] = 0;
this->airtimes.periodTX[0] = 0;
this->airtimes.periodRX[0] = 0;
this->airtimes.periodRX_ALL[0] = 0;
myNodeInfo.air_period_tx[0] = 0;
myNodeInfo.air_period_rx[0] = 0;
this->airtimes.lastPeriodIndex = this->currentPeriodIndex();
airtimes.lastPeriodIndex = currentPeriodIndex();
}
}
uint32_t *AirTime::airtimeReport(reportTypes reportType)
uint32_t *airtimeReport(reportTypes reportType)
{
if (reportType == TX_LOG) {
return this->airtimes.periodTX;
return airtimes.periodTX;
} else if (reportType == RX_LOG) {
return this->airtimes.periodRX;
return airtimes.periodRX;
} else if (reportType == RX_ALL_LOG) {
return this->airtimes.periodRX_ALL;
return airtimes.periodRX_ALL;
}
return 0;
}
uint8_t AirTime::getPeriodsToLog()
uint8_t getPeriodsToLog()
{
return PERIODS_TO_LOG;
return periodsToLog;
}
uint32_t AirTime::getSecondsPerPeriod()
uint32_t getSecondsPerPeriod()
{
return SECONDS_PER_PERIOD;
return secondsPerPeriod;
}
uint32_t AirTime::getSecondsSinceBoot()
uint32_t getSecondsSinceBoot()
{
return this->secSinceBoot;
return secSinceBoot;
}
float AirTime::channelUtilizationPercent()
{
uint32_t sum = 0;
for (uint32_t i = 0; i < CHANNEL_UTILIZATION_PERIODS; i++) {
sum += this->channelUtilization[i];
// DEBUG_MSG("ChanUtilArray %u %u\n", i, this->channelUtilization[i]);
}
return (float(sum) / float(CHANNEL_UTILIZATION_PERIODS * 10 * 1000)) * 100;
}
float AirTime::utilizationTXPercent()
{
uint32_t sum = 0;
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
sum += this->utilizationTX[i];
}
return (float(sum) / float(MS_IN_HOUR)) * 100;
}
AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) {
}
AirTime::AirTime() : concurrency::OSThread("AirTime") {}
int32_t AirTime::runOnce()
{
//DEBUG_MSG("AirTime::runOnce()\n");
airtimeRotatePeriod();
secSinceBoot++;
uint8_t utilPeriod = this->getPeriodUtilMinute();
uint8_t utilPeriodTX = this->getPeriodUtilHour();
/*
This actually doesn't need to be run once per second but we currently use it for the
secSinceBoot counter.
if (firstTime) {
// Init utilizationTX window to all 0
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
this->utilizationTX[i] = 0;
}
// Init channelUtilization window to all 0
for (uint32_t i = 0; i < CHANNEL_UTILIZATION_PERIODS; i++) {
this->channelUtilization[i] = 0;
}
// Init airtime windows to all 0
for (int i = 0; i < PERIODS_TO_LOG; i++) {
this->airtimes.periodTX[i] = 0;
this->airtimes.periodRX[i] = 0;
this->airtimes.periodRX_ALL[i] = 0;
// myNodeInfo.air_period_tx[i] = 0;
// myNodeInfo.air_period_rx[i] = 0;
}
firstTime = false;
lastUtilPeriod = utilPeriod;
} else {
this->airtimeRotatePeriod();
// Reset the channelUtilization window when we roll over
if (lastUtilPeriod != utilPeriod) {
lastUtilPeriod = utilPeriod;
this->channelUtilization[utilPeriod] = 0;
}
if (lastUtilPeriodTX != utilPeriodTX) {
lastUtilPeriodTX = utilPeriodTX;
this->utilizationTX[utilPeriodTX] = 0;
}
// Update channel_utilization every second.
myNodeInfo.channel_utilization = airTime->channelUtilizationPercent();
// Update channel_utilization every second.
myNodeInfo.air_util_tx = airTime->utilizationTXPercent();
}
/*
DEBUG_MSG("utilPeriodTX %d TX Airtime %3.2f%\n", utilPeriodTX, airTime->utilizationTXPercent());
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
DEBUG_MSG(
"%d,", this->utilizationTX[i]
);
}
DEBUG_MSG("\n");
*/
If we have a better counter of how long the device has been online (and not millis())
then we can change this to something less frequent. Maybe once ever 5 seconds?
*/
return (1000 * 1);
}
}

View File

@@ -23,21 +23,21 @@
RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel.
*/
#define CHANNEL_UTILIZATION_PERIODS 6
#define SECONDS_PER_PERIOD 3600
#define PERIODS_TO_LOG 24
#define MINUTES_IN_HOUR 60
#define SECONDS_IN_MINUTE 60
#define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000)
enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG };
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
void airtimeRotatePeriod();
uint8_t currentPeriodIndex();
uint8_t getPeriodsToLog();
uint32_t getSecondsSinceBoot();
uint32_t *airtimeReport(reportTypes reportType);
uint32_t getSecondsPerPeriod();
class AirTime : private concurrency::OSThread
{
@@ -45,38 +45,9 @@ class AirTime : private concurrency::OSThread
AirTime();
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
float channelUtilizationPercent();
float utilizationTXPercent();
float UtilizationPercentTX();
uint32_t channelUtilization[CHANNEL_UTILIZATION_PERIODS] = {0};
uint32_t utilizationTX[MINUTES_IN_HOUR] = {0};
void airtimeRotatePeriod();
uint8_t getPeriodsToLog();
uint32_t getSecondsPerPeriod();
uint32_t getSecondsSinceBoot();
uint32_t *airtimeReport(reportTypes reportType);
private:
bool firstTime = true;
uint8_t lastUtilPeriod = 0;
uint8_t lastUtilPeriodTX = 0;
uint32_t secSinceBoot = 0;
struct airtimeStruct {
uint32_t periodTX[PERIODS_TO_LOG]; // AirTime transmitted
uint32_t periodRX[PERIODS_TO_LOG]; // AirTime received and repeated (Only valid mesh packets)
uint32_t periodRX_ALL[PERIODS_TO_LOG]; // AirTime received regardless of valid mesh packet. Could include noise.
uint8_t lastPeriodIndex;
} airtimes;
uint8_t getPeriodUtilMinute();
uint8_t getPeriodUtilHour();
uint8_t currentPeriodIndex();
protected:
virtual int32_t runOnce() override;
};
extern AirTime *airTime;
extern AirTime *airTime;

View File

@@ -13,5 +13,4 @@ enum class Cmd {
STOP_BLUETOOTH_PIN_SCREEN,
STOP_BOOT_SCREEN,
PRINT,
START_SHUTDOWN_SCREEN,
};

View File

@@ -7,8 +7,9 @@
namespace concurrency
{
BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS() : semaphore(xSemaphoreCreateBinary())
BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS()
{
semaphore = xSemaphoreCreateBinary();
assert(semaphore);
}
@@ -37,4 +38,4 @@ IRAM_ATTR void BinarySemaphoreFreeRTOS::giveFromISR(BaseType_t *pxHigherPriority
} // namespace concurrency
#endif
#endif

View File

@@ -6,8 +6,9 @@ namespace concurrency
{
#ifdef HAS_FREE_RTOS
Lock::Lock() : handle(xSemaphoreCreateBinary())
Lock::Lock()
{
handle = xSemaphoreCreateBinary();
assert(handle);
assert(xSemaphoreGive(handle));
}

View File

@@ -10,7 +10,7 @@ namespace concurrency {
class LockGuard
{
public:
explicit LockGuard(Lock *lock);
LockGuard(Lock *lock);
~LockGuard();
LockGuard(const LockGuard &) = delete;

View File

@@ -39,7 +39,7 @@ class NotifiedWorkerThread : public OSThread
virtual void onNotify(uint32_t notification) = 0;
/// just calls checkNotification()
virtual int32_t runOnce() override;
virtual int32_t runOnce();
/// Sometimes we might want to check notifications independently of when our thread was getting woken up (i.e. if we are about to change
/// radio transmit/receive modes we want to handle any pending interrupts first). You can call this method and if any notifications are currently

View File

@@ -18,7 +18,7 @@ class Periodic : public OSThread
Periodic(const char *name, int32_t (*_callback)()) : OSThread(name), callback(_callback) {}
protected:
int32_t runOnce() override { return callback(); }
int32_t runOnce() { return callback(); }
};
} // namespace concurrency

View File

@@ -45,6 +45,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// If we are using the JTAG port for debugging, some pins must be left free for that (and things like GPS have to be disabled)
// we don't support jtag on the ttgo - access to gpio 12 is a PITA
#ifdef ARDUINO_HELTEC_WIFI_LORA_32_V2
//#define USE_JTAG
#endif
#define REQUIRE_RADIO true // If true, we will fail to start if the radio is not found
/// Convert a preprocessor name into a quoted string
@@ -80,9 +84,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BUTTON_PIN_ALT PIN_BUTTON2
#endif
#ifdef PIN_BUTTON_TOUCH
#define BUTTON_PIN_TOUCH PIN_BUTTON_TOUCH
#endif
// FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets)
#elif defined(CubeCell_BoardPlus)
//
// Standard definitions for CubeCell targets
//
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
#define LED_PIN -1 // FIXME totally bogus
#define BUTTON_PIN -1
#else
@@ -153,59 +165,251 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TBEAM
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
#define I2C_SDA 21
#define I2C_SCL 22
#define BUTTON_PIN 38 // The middle button GPIO on the T-Beam
#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed
#define LED_INVERTED 1
#define LED_PIN 4 // Newer tbeams (1.1) have an extra led on GPIO4
// 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
// 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
// Leave undefined to disable our PMU IRQ handler. DO NOT ENABLE THIS because the pmuirq can cause sperious interrupts
// and waking from light sleep
// #define PMU_IRQ 35
#define AXP192_SLAVE_ADDRESS 0x34
#elif defined(TBEAM_V07)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TBEAM0p7
#elif defined(DIY_V1)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_DIY_V1
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
#elif defined(RAK_11200)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_RAK11200
#define I2C_SDA 21
#define I2C_SCL 22
#define BUTTON_PIN 39
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 23
#define LORA_DIO1 33 // Not really used
#define LORA_DIO2 32 // Not really used
// This board has different GPS pins than all other boards
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 12
#define GPS_TX_PIN 15
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
// Tested on Neo6m module.
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 37
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#endif
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#ifndef USE_JTAG
#define LORA_RESET 14
#endif
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
#define ADC_MULTIPLIER 3.2
#ifdef HELTEC_V2_0
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_HELTEC_V2_0
#define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#endif
#ifdef HELTEC_V2_1
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_HELTEC_V2_1
#define BATTERY_PIN 37 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#endif
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32)
#define HW_VENDOR HardwareModel_HELTEC_V1
#elif defined(TLORA_V1)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TLORA_V1
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 37
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
// #define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 2 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define BUTTON_NEED_PULLUP
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(TLORA_V2)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TLORA_V2
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 13 // per @eugene
#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_SCL 22
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN \
0 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
// between this pin and ground
#define BUTTON_NEED_PULLUP
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(TLORA_V1_3)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_TLORA_V1_1p3
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 13 // per @eugene
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 36
#define BUTTON_NEED_PULLUP
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#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
#define HW_VENDOR HardwareModel_TLORA_V2_1_1p6
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 15 // per @der_bear on the forum, 36 is incorrect for this board type and 15 is a better pick
#define GPS_TX_PIN 13
#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_SCL 22
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 12 // If defined, this will be used for user button presses,
#define BUTTON_NEED_PULLUP
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(GENIEBLOCKS)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_GENIEBLOCKS
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 5
#define GPS_TX_PIN 18
#define GPS_RESET_N 10
#define GPS_EXTINT 23 // On MAX-M8 module pin name is EXTINT. On L70 module pin name is STANDBY.
#elif defined(PRIVATE_HW)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR HardwareModel_PRIVATE_HW
#define BATTERY_PIN 39 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define BATTERY_EN_PIN 14 // Voltage voltage divider enable pin connected to mosfet
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 2
#define LED_PIN 12 // If defined we will blink this LED
//#define BUTTON_PIN 36 // If defined, this will be used for user button presses (ToDo problem on that line on debug screen -->
// Long press start!) #define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs input only pins. These pins dont have internal
// pull-ups or pull-down resistors.
#define USE_RF95
#define LORA_DIO0 38 // a No connect on the SX1262 module
#define LORA_RESET 9
#define RF95_SCK 22
#define RF95_MISO 19
#define RF95_MOSI 13
#define RF95_NSS 21
#endif
@@ -238,8 +442,100 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define HW_VENDOR HardwareModel_PORTDUINO
#define USE_SIM_RADIO
// Pine64 uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
// not found then probe for SX1262. Currently the RF95 code is disabled because I think the RF95 module won't need to ship.
// #define USE_RF95
#define USE_SX1262
// Fake SPI device selections
#define RF95_SCK 5
#define RF95_MISO 19
#define RF95_MOSI 27
#define RF95_NSS RADIOLIB_NC // the ch341f spi controller does CS for us
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 33 // SX1262 IRQ, called DIO0 on pinelora schematic, pin 7 on ch341f "ack" - FIXME, enable hwints in linux
#define LORA_DIO2 32 // SX1262 BUSY, actually connected to "DIO5" on pinelora schematic, pin 8 on ch341f "slct"
#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 20 // CS0 on pinelora schematic, hooked to gpio D0 on ch341f
#define SX1262_DIO1 LORA_DIO1
#define SX1262_BUSY LORA_DIO2
#define SX1262_RESET LORA_RESET
// HOPE RFM90 does not have a TCXO therefore not SX1262_E22
#endif
#include "variant.h"
#include "RF95Configuration.h"
#include "DebugConfiguration.h"
#endif
// DEBUG LED
#ifndef LED_INVERTED
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
#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
// -----------------------------------------------------------------------------
#ifdef CONSOLE_MAX_BAUD
#define SERIAL_BAUD CONSOLE_MAX_BAUD
#else
#define SERIAL_BAUD 921600 // Serial debug baud rate
#endif
#include "SerialConsole.h"
#define DEBUG_PORT (*console) // Serial debug port
// What platforms should use SEGGER?
#ifdef NRF52_SERIES
// Always include the SEGGER code on NRF52 - because useful for debugging
#include "SEGGER_RTT.h"
// The channel we send stdout data to
#define SEGGER_STDOUT_CH 0
// Debug printing to segger console
#define SEGGER_MSG(...) SEGGER_RTT_printf(SEGGER_STDOUT_CH, __VA_ARGS__)
// 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
// 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
#define USE_SEGGER
#endif
#else
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
#endif
#ifdef USE_SEGGER
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
#ifdef DEBUG_PORT
#define DEBUG_MSG(...) DEBUG_PORT.logDebug(__VA_ARGS__)
#else
#define DEBUG_MSG(...)
#endif
#endif
// -----------------------------------------------------------------------------
// AXP192 (Rev1-specific options)
// -----------------------------------------------------------------------------
#define GPS_POWER_CTRL_CH 3
#define LORA_POWER_CTRL_CH 2
// Default Bluetooth PIN
#define defaultBLEPin 123456

View File

@@ -58,7 +58,7 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
return 0;
}
#define MAX_BLOCKSIZE_FOR_BT 512
#define MAX_BLOCKSIZE 512
/// Handle writes to data
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
@@ -66,7 +66,7 @@ int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
concurrency::LockGuard g(updateLock);
static uint8_t
data[MAX_BLOCKSIZE_FOR_BT]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
uint16_t len = 0;

View File

@@ -32,7 +32,7 @@ class ESP32CryptoEngine : public CryptoEngine
* @param bytes a _static_ buffer that will remain valid for the life of this crypto instance (i.e. this class will cache the
* provided pointer)
*/
virtual void setKey(const CryptoKey &k) override
virtual void setKey(const CryptoKey &k)
{
CryptoEngine::setKey(k);
@@ -47,7 +47,7 @@ class ESP32CryptoEngine : public CryptoEngine
*
* @param bytes is updated in place
*/
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
{
if (key.length > 0) {
uint8_t stream_block[16];
@@ -66,7 +66,7 @@ class ESP32CryptoEngine : public CryptoEngine
}
}
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
{
// DEBUG_MSG("ESP32 decrypt!\n");

View File

@@ -14,9 +14,9 @@
*/
class SimpleAllocator
{
uint8_t bytes[POOL_SIZE] = {};
uint8_t bytes[POOL_SIZE];
uint32_t nextFree = 0;
uint32_t nextFree;
public:
SimpleAllocator();
@@ -37,6 +37,6 @@ void *operator new(size_t size, SimpleAllocator &p);
*/
class AllocatorScope {
public:
explicit AllocatorScope(SimpleAllocator &a);
AllocatorScope(SimpleAllocator &a);
~AllocatorScope();
};

View File

@@ -43,8 +43,8 @@ void esp32Setup()
nvs_stats_t nvs_stats;
auto res = nvs_get_stats(NULL, &nvs_stats);
assert(res == ESP_OK);
DEBUG_MSG("NVS: UsedEntries %d, FreeEntries %d, AllEntries %d, NameSpaces %d\n", nvs_stats.used_entries, nvs_stats.free_entries,
nvs_stats.total_entries, nvs_stats.namespace_count);
DEBUG_MSG("NVS: UsedEntries %d, FreeEntries %d, AllEntries %d\n", nvs_stats.used_entries, nvs_stats.free_entries,
nvs_stats.total_entries);
DEBUG_MSG("Setup Preferences in Flash Storage\n");

View File

@@ -11,10 +11,10 @@ class Air530GPS : public NMEAGPS
{
protected:
/// If possible force the GPS into sleep/low power mode
virtual void sleep() override;
virtual void sleep();
/// wake the GPS into normal operation mode
virtual void wake() override;
virtual void wake();
private:
/// Send a NMEA cmd with checksum

View File

@@ -80,8 +80,6 @@ GPS::~GPS()
notifyDeepSleepObserver.unobserve();
}
bool GPS::hasLock() { return hasValidLocation; }
// Allow defining the polarity of the WAKE output. default is active high
#ifndef GPS_WAKE_ACTIVE
#define GPS_WAKE_ACTIVE 1
@@ -202,13 +200,11 @@ void GPS::publishUpdate()
if (shouldPublish) {
shouldPublish = false;
// In debug logs, identify position by @timestamp:stage (stage 2 = publish)
DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n",
p.pos_timestamp, hasValidLocation, hasLock());
DEBUG_MSG("publishing GPS lock=%d\n", hasLock());
// Notify any status instances that are observing us
const meshtastic::GPSStatus status =
meshtastic::GPSStatus(hasValidLocation, isConnected(), p);
meshtastic::GPSStatus(hasLock(), isConnected(), latitude, longitude, altitude, dop, heading, numSatellites);
newStatus.notifyObservers(&status);
}
}
@@ -246,7 +242,6 @@ int32_t GPS::runOnce()
bool gotLoc = lookForLocation();
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
DEBUG_MSG("hasValidLocation RISING EDGE\n");
hasValidLocation = true;
shouldPublish = true;
}
@@ -263,10 +258,6 @@ int32_t GPS::runOnce()
if (tooLong) {
// we didn't get a location during this ack window, therefore declare loss of lock
if (hasValidLocation) {
DEBUG_MSG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc);
}
p = Position_init_default;
hasValidLocation = false;
}
@@ -334,11 +325,6 @@ GPS *createGps()
#ifdef NO_GPS
return nullptr;
#else
#ifdef GPS_ALTITUDE_HAE
DEBUG_MSG("Using HAE altitude model\n");
#else
DEBUG_MSG("Using MSL altitude model\n");
#endif
// If we don't have bidirectional comms, we can't even try talking to UBLOX
#ifdef GPS_TX_PIN
// Init GPS - first try ublox

View File

@@ -17,10 +17,6 @@ class GPS : private concurrency::OSThread
private:
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastWhileActiveMsec = 0;
/**
* hasValidLocation - indicates that the position variables contain a complete
* GPS location, valid and fresh (< gps_update_interval + gps_attempt_time)
*/
bool hasValidLocation = false; // default to false, until we complete our first read
bool isAwake = false; // true if we want a location right now
@@ -43,7 +39,11 @@ class GPS : private concurrency::OSThread
/** If !0 we will attempt to connect to the GPS over I2C */
static uint8_t i2cAddress;
Position p = Position_init_default;
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
int32_t altitude = 0;
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs
// scaling before use)
uint32_t heading = 0; // Heading of motion, in degrees * 10^-5
GPS() : concurrency::OSThread("GPS") {}
@@ -57,8 +57,8 @@ class GPS : private concurrency::OSThread
*/
virtual bool setup();
/// Returns true if we have acquired GPS lock.
virtual bool hasLock();
/// Returns ture if we have acquired GPS lock.
bool hasLock() const { return hasValidLocation; }
/// Return true if we are connected to a GPS
bool isConnected() const { return hasGPS; }
@@ -145,7 +145,7 @@ class GPS : private concurrency::OSThread
*/
void publishUpdate();
virtual int32_t runOnce() override;
virtual int32_t runOnce();
};
// Creates an instance of the GPS class.

View File

@@ -1,450 +0,0 @@
#include "GeoCoord.h"
GeoCoord::GeoCoord() {
_dirty = true;
}
GeoCoord::GeoCoord (int32_t lat, int32_t lon, int32_t alt) : _latitude(lat), _longitude(lon), _altitude(alt) {
GeoCoord::setCoords();
}
GeoCoord::GeoCoord (float lat, float lon, int32_t alt) : _altitude(alt) {
// Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000
_latitude = int32_t(lat * 1e+7);
_longitude = int32_t(lon * 1e+7);
GeoCoord::setCoords();
}
GeoCoord::GeoCoord(double lat, double lon, int32_t alt): _altitude(alt) {
// Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000
_latitude = int32_t(lat * 1e+7);
_longitude = int32_t(lon * 1e+7);
GeoCoord::setCoords();
}
// Initialize all the coordinate systems
void GeoCoord::setCoords() {
double lat = _latitude * 1e-7;
double lon = _longitude * 1e-7;
GeoCoord::latLongToDMS(lat, lon, _dms);
GeoCoord::latLongToUTM(lat, lon, _utm);
GeoCoord::latLongToMGRS(lat, lon, _mgrs);
GeoCoord::latLongToOSGR(lat, lon, _osgr);
GeoCoord::latLongToOLC(lat, lon, _olc);
_dirty = false;
}
void GeoCoord::updateCoords(int32_t lat, int32_t lon, int32_t alt) {
// If marked dirty or new coordiantes
if(_dirty || _latitude != lat || _longitude != lon || _altitude != alt) {
_dirty = true;
_latitude = lat;
_longitude = lon;
_altitude = alt;
setCoords();
}
}
void GeoCoord::updateCoords(const double lat, const double lon, const int32_t alt) {
int32_t iLat = lat * 1e+7;
int32_t iLon = lon * 1e+7;
// If marked dirty or new coordiantes
if(_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
_dirty = true;
_latitude = iLat;
_longitude = iLon;
_altitude = alt;
setCoords();
}
}
void GeoCoord::updateCoords(const float lat, const float lon, const int32_t alt) {
int32_t iLat = lat * 1e+7;
int32_t iLon = lon * 1e+7;
// If marked dirty or new coordiantes
if(_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
_dirty = true;
_latitude = iLat;
_longitude = iLon;
_altitude = alt;
setCoords();
}
}
/**
* Converts lat long coordinates from decimal degrees to degrees minutes seconds format.
* DD°MM'SS"C DDD°MM'SS"C
*/
void GeoCoord::latLongToDMS(const double lat, const double lon, DMS &dms) {
if (lat < 0) dms.latCP = 'S';
else dms.latCP = 'N';
double latDeg = lat;
if (lat < 0)
latDeg = latDeg * -1;
dms.latDeg = floor(latDeg);
double latMin = (latDeg - dms.latDeg) * 60;
dms.latMin = floor(latMin);
dms.latSec = (latMin - dms.latMin) * 60;
if (lon < 0) dms.lonCP = 'W';
else dms.lonCP = 'E';
double lonDeg = lon;
if (lon < 0)
lonDeg = lonDeg * -1;
dms.lonDeg = floor(lonDeg);
double lonMin = (lonDeg - dms.lonDeg) * 60;
dms.lonMin = floor(lonMin);
dms.lonSec = (lonMin - dms.lonMin) * 60;
}
/**
* Converts lat long coordinates to UTM.
* based on this: https://github.com/walvok/LatLonToUTM/blob/master/latlon_utm.ino
*/
void GeoCoord::latLongToUTM(const double lat, const double lon, UTM &utm) {
const std::string latBands = "CDEFGHJKLMNPQRSTUVWXX";
utm.zone = int((lon + 180)/6 + 1);
utm.band = latBands[int(lat/8 + 10)];
double a = 6378137; // WGS84 - equatorial radius
double k0 = 0.9996; // UTM point scale on the central meridian
double eccSquared = 0.00669438; // eccentricity squared
double lonTemp = (lon + 180) - int((lon + 180)/360) * 360 - 180; //Make sure the longitude is between -180.00 .. 179.9
double latRad = toRadians(lat);
double lonRad = toRadians(lonTemp);
// Special Zones for Norway and Svalbard
if( lat >= 56.0 && lat < 64.0 && lonTemp >= 3.0 && lonTemp < 12.0 ) // Norway
utm.zone = 32;
if( lat >= 72.0 && lat < 84.0 ) { // Svalbard
if ( lonTemp >= 0.0 && lonTemp < 9.0 ) utm.zone = 31;
else if( lonTemp >= 9.0 && lonTemp < 21.0 ) utm.zone = 33;
else if( lonTemp >= 21.0 && lonTemp < 33.0 ) utm.zone = 35;
else if( lonTemp >= 33.0 && lonTemp < 42.0 ) utm.zone = 37;
}
double lonOrigin = (utm.zone - 1)*6 - 180 + 3; // puts origin in middle of zone
double lonOriginRad = toRadians(lonOrigin);
double eccPrimeSquared = (eccSquared)/(1 - eccSquared);
double N = a/sqrt(1 - eccSquared*sin(latRad)*sin(latRad));
double T = tan(latRad)*tan(latRad);
double C = eccPrimeSquared*cos(latRad)*cos(latRad);
double A = cos(latRad)*(lonRad - lonOriginRad);
double M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64 - 5*eccSquared*eccSquared*eccSquared/256)*latRad
- (3*eccSquared/8 + 3*eccSquared*eccSquared/32 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*latRad)
+ (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*latRad)
- (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*latRad));
utm.easting = (double)(k0*N*(A+(1-T+C)*pow(A, 3)/6 + (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120)
+ 500000.0);
utm.northing = (double)(k0*(M+N*tan(latRad)*(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24
+ (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720)));
if(lat < 0)
utm.northing += 10000000.0; //10000000 meter offset for southern hemisphere
}
// Converts lat long coordinates to an MGRS.
void GeoCoord::latLongToMGRS(const double lat, const double lon, MGRS &mgrs) {
const std::string e100kLetters[3] = { "ABCDEFGH", "JKLMNPQR", "STUVWXYZ" };
const std::string n100kLetters[2] = { "ABCDEFGHJKLMNPQRSTUV", "FGHJKLMNPQRSTUVABCDE" };
UTM utm;
latLongToUTM(lat, lon, utm);
mgrs.zone = utm.zone;
mgrs.band = utm.band;
double col = floor(utm.easting / 100000);
mgrs.east100k = e100kLetters[(mgrs.zone - 1) % 3][col - 1];
double row = (int32_t)floor(utm.northing / 100000.0) % 20;
mgrs.north100k = n100kLetters[(mgrs.zone-1)%2][row];
mgrs.easting = (int32_t)utm.easting % 100000;
mgrs.northing = (int32_t)utm.northing % 100000;
}
/**
* Converts lat long coordinates to Ordnance Survey Grid Reference (UK National Grid Ref).
* Based on: https://www.movable-type.co.uk/scripts/latlong-os-gridref.html
*/
void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr) {
const char letter[] = "ABCDEFGHJKLMNOPQRSTUVWXYZ"; // No 'I' in OSGR
double a = 6377563.396; // Airy 1830 semi-major axis
double b = 6356256.909; // Airy 1830 semi-minor axis
double f0 = 0.9996012717; // National Grid point scale factor on the central meridian
double phi0 = toRadians(49);
double lambda0 = toRadians(-2);
double n0 = -100000;
double e0 = 400000;
double e2 = 1 - (b*b)/(a*a); // eccentricity squared
double n = (a - b)/(a + b);
double osgb_Latitude;
double osgb_Longitude;
convertWGS84ToOSGB36(lat, lon, osgb_Latitude, osgb_Longitude);
double phi = osgb_Latitude; // already in radians
double lambda = osgb_Longitude; // already in radians
double v = a * f0 / sqrt(1 - e2 * sin(phi) * sin(phi));
double rho = a * f0 * (1 - e2) / pow(1 - e2 * sin(phi) * sin(phi), 1.5);
double eta2 = v / rho - 1;
double mA = (1 + n + (5/4)*n*n + (5/4)*n*n*n) * (phi - phi0);
double mB = (3*n + 3*n*n + (21/8)*n*n*n) * sin(phi - phi0) * cos(phi + phi0);
// loss of precision in mC & mD due to floating point rounding can cause innaccuracy of northing by a few meters
double mC = (15/8*n*n + 15/8*n*n*n) * sin(2*(phi - phi0)) * cos(2*(phi + phi0));
double mD = (35/24)*n*n*n * sin(3*(phi - phi0)) * cos(3*(phi + phi0));
double m = b*f0*(mA - mB + mC - mD);
double cos3Phi = cos(phi)*cos(phi)*cos(phi);
double cos5Phi = cos3Phi*cos(phi)*cos(phi);
double tan2Phi = tan(phi)*tan(phi);
double tan4Phi = tan2Phi*tan2Phi;
double I = m + n0;
double II = (v/2)*sin(phi)*cos(phi);
double III = (v/24)*sin(phi)*cos3Phi*(5 - tan2Phi + 9*eta2);
double IIIA = (v/720)*sin(phi)*cos5Phi*(61 - 58*tan2Phi + tan4Phi);
double IV = v*cos(phi);
double V = (v/6)*cos3Phi*(v/rho - tan2Phi);
double VI = (v/120)*cos5Phi*(5 - 18*tan2Phi + tan4Phi + 14*eta2 - 58*tan2Phi*eta2);
double deltaLambda = lambda - lambda0;
double deltaLambda2 = deltaLambda*deltaLambda;
double northing = I + II*deltaLambda2 + III*deltaLambda2*deltaLambda2 + IIIA*deltaLambda2*deltaLambda2*deltaLambda2;
double easting = e0 + IV*deltaLambda + V*deltaLambda2*deltaLambda + VI*deltaLambda2*deltaLambda2*deltaLambda;
if (easting < 0 || easting > 700000 || northing < 0 || northing > 1300000) // Check if out of boundaries
osgr = { 'I', 'I', 0, 0 };
else {
uint32_t e100k = floor(easting / 100000);
uint32_t n100k = floor(northing / 100000);
int8_t l1 = (19 - n100k) - (19 - n100k) % 5 + floor((e100k + 10) / 5);
int8_t l2 = (19 - n100k) * 5 % 25 + e100k % 5;
osgr.e100k = letter[l1];
osgr.n100k = letter[l2];
osgr.easting = floor((int)easting % 100000);
osgr.northing = floor((int)northing % 100000);
}
}
/**
* Converts lat long coordinates to Open Location Code.
* Based on: https://github.com/google/open-location-code/blob/main/c/src/olc.c
*/
void GeoCoord::latLongToOLC(double lat, double lon, OLC &olc) {
char tempCode[] = "1234567890abc";
const char kAlphabet[] = "23456789CFGHJMPQRVWX";
double latitude;
double longitude = lon;
double latitude_degrees = std::min(90.0, std::max(-90.0, lat));
if (latitude_degrees < 90) // Check latitude less than lat max
latitude = latitude_degrees;
else {
double precision;
if (OLC_CODE_LEN <= 10)
precision = pow_neg(20, floor((OLC_CODE_LEN / -2) + 2));
else
precision = pow_neg(20, -3) / pow(5, OLC_CODE_LEN - 10);
latitude = latitude_degrees - precision / 2;
}
while (longitude < -180) // Normalize longitude
longitude += 360;
while (longitude >= 180)
longitude -= 360;
int64_t lat_val = 90 * 2.5e7;
int64_t lng_val = 180 * 8.192e6;
lat_val += latitude * 2.5e7;
lng_val += longitude * 8.192e6;
size_t pos = OLC_CODE_LEN;
if (OLC_CODE_LEN > 10) { // Compute grid part of code if needed
for (size_t i = 0; i < 5; i++) {
int lat_digit = lat_val % 5;
int lng_digit = lng_val % 4;
int ndx = lat_digit * 4 + lng_digit;
tempCode[pos--] = kAlphabet[ndx];
lat_val /= 5;
lng_val /= 4;
}
} else {
lat_val /= pow(5, 5);
lng_val /= pow(4, 5);
}
pos = 10;
for (size_t i = 0; i < 5; i++) { // Compute pair section of code
int lat_ndx = lat_val % 20;
int lng_ndx = lng_val % 20;
tempCode[pos--] = kAlphabet[lng_ndx];
tempCode[pos--] = kAlphabet[lat_ndx];
lat_val /= 20;
lng_val /= 20;
if (i == 0)
tempCode[pos--] = '+';
}
if (OLC_CODE_LEN < 9) { // Add padding if needed
for (size_t i = OLC_CODE_LEN; i < 9; i++)
tempCode[i] = '0';
tempCode[9] = '+';
}
size_t char_count = OLC_CODE_LEN;
if (10 > char_count) {
char_count = 10;
}
for (size_t i = 0; i < char_count; i++) {
olc.code[i] = tempCode[i];
}
olc.code[char_count] = '\0';
}
// Converts the coordinate in WGS84 datum to the OSGB36 datum.
void GeoCoord::convertWGS84ToOSGB36(const double lat, const double lon, double &osgb_Latitude, double &osgb_Longitude) {
// Convert lat long to cartesian
double phi = toRadians(lat);
double lambda = toRadians(lon);
double h = 0.0; // No OSTN height data used, some loss of accuracy (up to 5m)
double wgsA = 6378137; // WGS84 datum semi major axis
double wgsF = 1 / 298.257223563; // WGS84 datum flattening
double ecc = 2*wgsF - wgsF*wgsF;
double vee = wgsA / sqrt(1 - ecc * pow(sin(phi), 2));
double wgsX = (vee + h) * cos(phi) * cos(lambda);
double wgsY = (vee + h) * cos(phi) * sin(lambda);
double wgsZ = ((1 - ecc) * vee + h) * sin(phi);
// 7-parameter Helmert transform
double tx = -446.448; // x shift in meters
double ty = 125.157; // y shift in meters
double tz = -542.060; // z shift in meters
double s = 20.4894/1e6 + 1; // scale normalized parts per million to (s + 1)
double rx = toRadians(-0.1502/3600); // x rotation normalize arcseconds to radians
double ry = toRadians(-0.2470/3600); // y rotation normalize arcseconds to radians
double rz = toRadians(-0.8421/3600); // z rotation normalize arcseconds to radians
double osgbX = tx + wgsX*s - wgsY*rz + wgsZ*ry;
double osgbY = ty + wgsX*rz + wgsY*s - wgsZ*rx;
double osgbZ = tz - wgsX*ry + wgsY*rx + wgsZ*s;
// Convert cartesian to lat long
double airyA = 6377563.396; // Airy1830 datum semi major axis
double airyB = 6356256.909; // Airy1830 datum semi minor axis
double airyF = 1/ 299.3249646; // Airy1830 datum flattening
double airyEcc = 2*airyF - airyF*airyF;
double airyEcc2 = airyEcc / (1 - airyEcc);
double p = sqrt(osgbX*osgbX + osgbY*osgbY);
double R = sqrt(p*p + osgbZ*osgbZ);
double tanBeta = (airyB*osgbZ) / (airyA*p) * (1 + airyEcc2*airyB/R);
double sinBeta = tanBeta / sqrt(1 + tanBeta*tanBeta);
double cosBeta = sinBeta / tanBeta;
osgb_Latitude = atan2(osgbZ + airyEcc2*airyB*sinBeta*sinBeta*sinBeta, p - airyEcc*airyA*cosBeta*cosBeta*cosBeta); // leave in radians
osgb_Longitude = atan2(osgbY, osgbX); // leave in radians
//osgb height = p*cos(osgb.latitude) + osgbZ*sin(osgb.latitude) -
//(airyA*airyA/(airyA / sqrt(1 - airyEcc*sin(osgb.latitude)*sin(osgb.latitude)))); // Not used, no OSTN data
}
/// Ported from my old java code, returns distance in meters along the globe
/// surface (by magic?)
float GeoCoord::latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b)
{
double pk = (180 / 3.14169);
double a1 = lat_a / pk;
double a2 = lng_a / pk;
double b1 = lat_b / pk;
double b2 = lng_b / pk;
double cos_b1 = cos(b1);
double cos_a1 = cos(a1);
double t1 = cos_a1 * cos(a2) * cos_b1 * cos(b2);
double t2 = cos_a1 * sin(a2) * cos_b1 * sin(b2);
double t3 = sin(a1) * sin(b1);
double tt = acos(t1 + t2 + t3);
if (std::isnan(tt))
tt = 0.0; // Must have been the same point?
return (float)(6366000 * tt);
}
/**
* Computes the bearing in degrees between two points on Earth. Ported from my
* old Gaggle android app.
*
* @param lat1
* Latitude of the first point
* @param lon1
* Longitude of the first point
* @param lat2
* Latitude of the second point
* @param lon2
* Longitude of the second point
* @return Bearing between the two points in radians. A value of 0 means due
* north.
*/
float GeoCoord::bearing(double lat1, double lon1, double lat2, double lon2)
{
double lat1Rad = toRadians(lat1);
double lat2Rad = toRadians(lat2);
double deltaLonRad = toRadians(lon2 - lon1);
double y = sin(deltaLonRad) * cos(lat2Rad);
double x = cos(lat1Rad) * sin(lat2Rad) - (sin(lat1Rad) * cos(lat2Rad) * cos(deltaLonRad));
return atan2(y, x);
}
/**
* Ported from http://www.edwilliams.org/avform147.htm#Intro
* @brief Convert from meters to range in radians on a great circle
* @param range_meters
* The range in meters
* @return range in radians on a great circle
*/
float GeoCoord::rangeMetersToRadians(double range_meters) {
// 1 nm is 1852 meters
double distance_nm = range_meters * 1852;
return (PI / (180 * 60)) *distance_nm;
}
/**
* Ported from http://www.edwilliams.org/avform147.htm#Intro
* @brief Convert from radians to range in meters on a great circle
* @param range_radians
* The range in radians
* @return Range in meters on a great circle
*/
float GeoCoord::rangeRadiansToMeters(double range_radians) {
double distance_nm = ((180 * 60) / PI) * range_radians;
// 1 meter is 0.000539957 nm
return distance_nm * 0.000539957;
}
// Find distance from point to passed in point
int32_t GeoCoord::distanceTo(const GeoCoord& pointB) {
return latLongToMeter(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7, pointB.getLongitude() * 1e-7);
}
// Find bearing from point to passed in point
int32_t GeoCoord::bearingTo(const GeoCoord& pointB) {
return bearing(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7, pointB.getLongitude() * 1e-7);
}
/**
* Create a new point bassed on the passed in poin
* Ported from http://www.edwilliams.org/avform147.htm#LL
* @param bearing
* The bearing in raidans
* @param range_meters
* range in meters
* @return GeoCoord object of point at bearing and range from initial point
*/
std::shared_ptr<GeoCoord> GeoCoord::pointAtDistance(double bearing, double range_meters) {
double range_radians = rangeMetersToRadians(range_meters);
double lat1 = this->getLatitude() * 1e-7;
double lon1 = this->getLongitude() * 1e-7;
double lat = asin(sin(lat1) * cos(range_radians) + cos(lat1) * sin(range_radians) * cos(bearing));
double dlon = atan2(sin(bearing) * sin(range_radians) * cos(lat1), cos(range_radians) - sin(lat1) * sin(lat));
double lon = fmod(lon1 - dlon + PI, 2 * PI) - PI;
return std::make_shared<GeoCoord>(double(lat), double(lon), this->getAltitude());
}

View File

@@ -1,164 +0,0 @@
#pragma once
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdint>
#include <math.h>
#include <stdint.h>
#include <stdexcept>
#include <memory>
#define PI 3.1415926535897932384626433832795
#define OLC_CODE_LEN 11
// Helper functions
// Raises a number to an exponent, handling negative exponents.
static inline double pow_neg(double base, double exponent) {
if (exponent == 0) {
return 1;
} else if (exponent > 0) {
return pow(base, exponent);
}
return 1 / pow(base, -exponent);
}
static inline double toRadians(double deg)
{
return deg * PI / 180;
}
static inline double toDegrees(double r)
{
return r * 180 / PI;
}
// GeoCoord structs/classes
// A struct to hold the data for a DMS coordinate.
struct DMS
{
uint8_t latDeg;
uint8_t latMin;
uint32_t latSec;
char latCP;
uint8_t lonDeg;
uint8_t lonMin;
uint32_t lonSec;
char lonCP;
};
// A struct to hold the data for a UTM coordinate, this is also used when creating an MGRS coordinate.
struct UTM
{
uint8_t zone;
char band;
uint32_t easting;
uint32_t northing;
};
// A struct to hold the data for a MGRS coordinate.
struct MGRS
{
uint8_t zone;
char band;
char east100k;
char north100k;
uint32_t easting;
uint32_t northing;
};
// A struct to hold the data for a OSGR coordiante
struct OSGR {
char e100k;
char n100k;
uint32_t easting;
uint32_t northing;
};
// A struct to hold the data for a OLC coordinate
struct OLC {
char code[OLC_CODE_LEN + 1]; // +1 for null termination
};
class GeoCoord {
private:
int32_t _latitude = 0;
int32_t _longitude = 0;
int32_t _altitude = 0;
DMS _dms = {};
UTM _utm = {};
MGRS _mgrs = {};
OSGR _osgr = {};
OLC _olc = {};
bool _dirty = true;
void setCoords();
public:
GeoCoord();
GeoCoord(int32_t lat, int32_t lon, int32_t alt);
GeoCoord(double lat, double lon, int32_t alt);
GeoCoord(float lat, float lon, int32_t alt);
void updateCoords(const int32_t lat, const int32_t lon, const int32_t alt);
void updateCoords(const double lat, const double lon, const int32_t alt);
void updateCoords(const float lat, const float lon, const int32_t alt);
// Conversions
static void latLongToDMS(const double lat, const double lon, DMS &dms);
static void latLongToUTM(const double lat, const double lon, UTM &utm);
static void latLongToMGRS(const double lat, const double lon, MGRS &mgrs);
static void latLongToOSGR(const double lat, const double lon, OSGR &osgr);
static void latLongToOLC(const double lat, const double lon, OLC &olc);
static void convertWGS84ToOSGB36(const double lat, const double lon, double &osgb_Latitude, double &osgb_Longitude);
static float latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b);
static float bearing(double lat1, double lon1, double lat2, double lon2);
static float rangeRadiansToMeters(double range_radians);
static float rangeMetersToRadians(double range_meters);
// Point to point conversions
int32_t distanceTo(const GeoCoord& pointB);
int32_t bearingTo(const GeoCoord& pointB);
std::shared_ptr<GeoCoord> pointAtDistance(double bearing, double range);
// Lat lon alt getters
int32_t getLatitude() const { return _latitude; }
int32_t getLongitude() const { return _longitude; }
int32_t getAltitude() const { return _altitude; }
// DMS getters
uint8_t getDMSLatDeg() const { return _dms.latDeg; }
uint8_t getDMSLatMin() const { return _dms.latMin; }
uint32_t getDMSLatSec() const { return _dms.latSec; }
char getDMSLatCP() const { return _dms.latCP; }
uint8_t getDMSLonDeg() const { return _dms.lonDeg; }
uint8_t getDMSLonMin() const { return _dms.lonMin; }
uint32_t getDMSLonSec() const { return _dms.lonSec; }
char getDMSLonCP() const { return _dms.lonCP; }
// UTM getters
uint8_t getUTMZone() const { return _utm.zone; }
char getUTMBand() const { return _utm.band; }
uint32_t getUTMEasting() const { return _utm.easting; }
uint32_t getUTMNorthing() const { return _utm.northing; }
// MGRS getters
uint8_t getMGRSZone() const { return _mgrs.zone; }
char getMGRSBand() const { return _mgrs.band; }
char getMGRSEast100k() const { return _mgrs.east100k; }
char getMGRSNorth100k() const { return _mgrs.north100k; }
uint32_t getMGRSEasting() const { return _mgrs.easting; }
uint32_t getMGRSNorthing() const { return _mgrs.northing; }
// OSGR getters
char getOSGRE100k() const { return _osgr.e100k; }
char getOSGRN100k() const { return _osgr.n100k; }
uint32_t getOSGREasting() const { return _osgr.easting; }
uint32_t getOSGRNorthing() const { return _osgr.northing; }
// OLC getter
void getOLCCode(char* code) { strncpy(code, _olc.code, OLC_CODE_LEN + 1); } // +1 for null termination
};

View File

@@ -2,12 +2,6 @@
#include "NMEAGPS.h"
#include "RTC.h"
#include <TinyGPS++.h>
// GPS solutions older than this will be rejected - see TinyGPSDatum::age()
#define GPS_SOL_EXPIRY_MS 300 // in millis
#define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc)
static int32_t toDegInt(RawDegrees d)
{
int32_t degMult = 10000000; // 1e7
@@ -27,17 +21,6 @@ bool NMEAGPS::setupGPS()
pinMode(PIN_GPS_PPS, INPUT);
#endif
// Currently disabled per issue #525 (TinyGPS++ crash bug)
// when fixed upstream, can be un-disabled to enable 3D FixType and PDOP
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// see NMEAGPS.h
gsafixtype.begin(reader, NMEA_MSG_GXGSA, 2);
gsapdop.begin(reader, NMEA_MSG_GXGSA, 15);
DEBUG_MSG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n");
#else
DEBUG_MSG("GxGSA NOT available\n");
#endif
return true;
}
@@ -65,7 +48,7 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
t.tm_year = d.year() - 1900;
t.tm_isdst = false;
DEBUG_MSG("NMEA GPS time %d\n", t.tm_sec);
perhapsSetRTC(RTCQualityGPS, t);
return true;
@@ -81,140 +64,47 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
*/
bool NMEAGPS::lookForLocation()
{
// By default, TinyGPS++ does not parse GPGSA lines, which give us
// the 2D/3D fixType (see NMEAGPS.h)
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
fixQual = reader.fixQuality();
bool foundLocation = false;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
fixType = atoi(gsafixtype.value()); // will set to zero if no data
DEBUG_MSG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
#endif
// uint8_t fixtype = reader.fixQuality();
// hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
// check if GPS has an acceptable lock
if (! hasLock())
return false;
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d\n",
reader.location.age(),
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
gsafixtype.age(),
#else
0,
#endif
reader.date.age(), reader.time.age());
#endif // GPS_EXTRAVERBOSE
// check if a complete GPS solution set is available for reading
// tinyGPSDatum::age() also includes isValid() test
// FIXME
if (! ((reader.location.age() < GPS_SOL_EXPIRY_MS) &&
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
(gsafixtype.age() < GPS_SOL_EXPIRY_MS) &&
#endif
(reader.time.age() < GPS_SOL_EXPIRY_MS) &&
(reader.date.age() < GPS_SOL_EXPIRY_MS)))
{
DEBUG_MSG("SOME data is TOO OLD\n");
return false;
}
// Is this a new point or are we re-reading the previous one?
if (! reader.location.isUpdated())
return false;
// We know the solution is fresh and valid, so just read the data
auto loc = reader.location.value();
// Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus
// Bail out EARLY to avoid overwriting previous good data (like #857)
if(toDegInt(loc.lat) == 0) {
DEBUG_MSG("Ignoring bogus NMEA position\n");
return false;
}
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
// Dilution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
p.HDOP = reader.hdop.value();
p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value());
DEBUG_MSG("PDOP=%d, HDOP=%d\n", dop, reader.hdop.value());
#else
// FIXME! naive PDOP emulation (assumes VDOP==HDOP)
// correct formula is PDOP = SQRT(HDOP^2 + VDOP^2)
p.HDOP = reader.hdop.value();
p.PDOP = 1.41 * reader.hdop.value();
#endif
// Discard incomplete or erroneous readings
if (reader.hdop.value() == 0)
return false;
p.latitude_i = toDegInt(loc.lat);
p.longitude_i = toDegInt(loc.lng);
p.alt_geoid_sep = reader.geoidHeight.meters();
p.altitude_hae = reader.altitude.meters() + p.alt_geoid_sep;
p.altitude = reader.altitude.meters();
p.fix_quality = fixQual;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
p.fix_type = fixType;
#endif
// positional timestamp
struct tm t;
t.tm_sec = reader.time.second();
t.tm_min = reader.time.minute();
t.tm_hour = reader.time.hour();
t.tm_mday = reader.date.day();
t.tm_mon = reader.date.month() - 1;
t.tm_year = reader.date.year() - 1900;
t.tm_isdst = false;
p.pos_timestamp = mktime(&t);
// Nice to have, if available
if (reader.satellites.isUpdated()) {
p.sats_in_view = reader.satellites.value();
setNumSatellites(reader.satellites.value());
}
if (reader.course.isUpdated() && reader.course.isValid()) {
if (reader.course.value() < 36000) { // sanity check
p.ground_track = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
} else {
DEBUG_MSG("BOGUS course.value() REJECTED: %d\n",
reader.course.value());
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
if (reader.hdop.isUpdated()) {
dop = reader.hdop.value();
}
if (reader.course.isUpdated()) {
heading = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
}
if (reader.altitude.isUpdated())
altitude = reader.altitude.meters();
if (reader.location.isUpdated()) {
auto loc = reader.location.value();
latitude = toDegInt(loc.lat);
longitude = toDegInt(loc.lng);
// Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus
if(longitude == 0)
DEBUG_MSG("Ignoring bogus NMEA position\n");
else {
foundLocation = true;
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude,
dop * 1e-2, heading * 1e-5);
}
}
/*
// REDUNDANT?
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, dop=%g, heading=%f\n",
latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2,
heading * 1e-5);
*/
return true;
return foundLocation;
}
bool NMEAGPS::hasLock()
{
// Using GPGGA fix quality indicator
if (fixQual >= 1 && fixQual <= 5) {
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// Use GPGSA fix type 2D/3D (better) if available
if (fixType == 3 || fixType == 0) // zero means "no data received"
#endif
return true;
}
return false;
}
bool NMEAGPS::whileIdle()
{
bool isValid = false;

View File

@@ -12,25 +12,16 @@
class NMEAGPS : public GPS
{
TinyGPSPlus reader;
uint8_t fixQual = 0; // fix quality from GPGGA
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
// via optional feature "custom fields", currently disabled (bug #525)
TinyGPSCustom gsafixtype; // custom extract fix type from GPGSA
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
uint8_t fixType = 0; // fix type from GPGSA
#endif
public:
virtual bool setupGPS() override;
virtual bool setupGPS();
protected:
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle() override;
virtual bool whileIdle();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
@@ -38,7 +29,7 @@ class NMEAGPS : public GPS
*
* @return true if we've acquired a time
*/
virtual bool lookForTime() override;
virtual bool lookForTime();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
@@ -46,7 +37,5 @@ class NMEAGPS : public GPS
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation() override;
virtual bool hasLock() override;
virtual bool lookForLocation();
};

View File

@@ -11,11 +11,8 @@ enum RTCQuality {
/// Some other node gave us a time we can use
RTCQualityFromNet = 1,
/// Our time is based on NTP
RTCQualityNTP= 2,
/// Our time is based on our own GPS
RTCQualityGPS = 3
RTCQualityGPS = 2
};
RTCQuality getRTCQuality();

View File

@@ -5,15 +5,6 @@
#include "sleep.h"
#include <assert.h>
// if gps_update_interval below this value, do not powercycle the GPS
#define UBLOX_POWEROFF_THRESHOLD 90
#define PDOP_INVALID 9999
// #define UBX_MODE_NMEA
extern RadioConfig radioConfig;
UBloxGPS::UBloxGPS() {}
bool UBloxGPS::tryConnect()
@@ -50,22 +41,12 @@ bool UBloxGPS::setupGPS()
delay(500);
if (isConnected()) {
#ifdef UBX_MODE_NMEA
DEBUG_MSG("Connected to UBLOX GPS, downgrading to NMEA mode\n");
DEBUG_MSG("- GPS errors below are related and safe to ignore\n");
#else
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
#endif
if (!setUBXMode())
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
#ifdef UBX_MODE_NMEA
return false;
#else
return true;
#endif
} else {
return false;
}
@@ -73,17 +54,6 @@ bool UBloxGPS::setupGPS()
bool UBloxGPS::setUBXMode()
{
#ifdef UBX_MODE_NMEA
if (_serial_gps) {
ublox.setUART1Output(COM_TYPE_NMEA, 1000);
}
if (i2cAddress) {
ublox.setI2COutput(COM_TYPE_NMEA, 1000);
}
return false; // pretend initialization failed to force NMEA mode
#endif
if (_serial_gps) {
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
return false;
@@ -141,17 +111,19 @@ bool UBloxGPS::factoryReset()
/** Idle processing while GPS is looking for lock */
void UBloxGPS::whileActive()
{
ublox.flushPVT(); // reset ALL freshness flags first
ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
// Ask for a new position fix - hopefully it will have results ready by next time
// the order here is important, because we only check for has latitude when reading
ublox.getSIV(maxWait());
ublox.getPDOP(maxWait());
ublox.getP(maxWait());
//ublox.getSIV(maxWait()); // redundant with getPDOP below
ublox.getPDOP(maxWait()); // will trigger getSOL on NEO6, getP on others
ublox.getP(maxWait()); // will trigger getPosLLH on NEO6, getP on others
// the fixType flag will be checked and updated in lookForLocation()
// Update fixtype
if (ublox.moduleQueried.fixType) {
fixType = ublox.getFixType(0);
// DEBUG_MSG("GPS fix type %d, numSats %d\n", fixType, numSatellites);
}
}
/**
@@ -192,110 +164,33 @@ bool UBloxGPS::lookForLocation()
{
bool foundLocation = false;
// check if a complete GPS solution set is available for reading
// (some of these, like lat/lon are redundant and can be removed)
if ( ! (ublox.moduleQueried.fixType &&
ublox.moduleQueried.latitude &&
ublox.moduleQueried.longitude &&
ublox.moduleQueried.altitude &&
ublox.moduleQueried.pDOP &&
ublox.moduleQueried.SIV &&
ublox.moduleQueried.gpsDay))
{
// Not ready? No problem! We'll try again later.
return false;
}
if (ublox.moduleQueried.SIV)
setNumSatellites(ublox.getSIV(0));
fixType = ublox.getFixType();
#ifdef UBLOX_EXTRAVERBOSE
DEBUG_MSG("FixType=%d\n", fixType);
#endif
if (ublox.moduleQueried.pDOP)
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
// we only notify if position has changed due to a new fix
if ((fixType >= 3 && fixType <= 4)) {
if (ublox.moduleQueried.latitude) // rd fixes only
{
latitude = ublox.getLatitude(0);
longitude = ublox.getLongitude(0);
altitude = ublox.getAltitudeMSL(0) / 1000; // in mm convert to meters
// check if GPS has an acceptable lock
if (! hasLock()) {
ublox.flushPVT(); // reset ALL freshness flags
return false;
}
// Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
// don't read it here - it will generate an ignored getPVT command on the 6ms
// heading = ublox.getHeading(0);
// read lat/lon/alt/dop data into temporary variables to avoid
// overwriting global variables with potentially invalid data
int32_t tmp_dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
int32_t tmp_lat = ublox.getLatitude(0);
int32_t tmp_lon = ublox.getLongitude(0);
int32_t tmp_alt_msl = ublox.getAltitudeMSL(0);
int32_t tmp_alt_hae = ublox.getAltitude(0);
int32_t max_dop = PDOP_INVALID;
if (radioConfig.preferences.gps_max_dop)
max_dop = radioConfig.preferences.gps_max_dop * 100; // scaling
// Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
// don't read it here - it will generate an ignored getPVT command on the 6ms
// heading = ublox.getHeading(0);
// read positional timestamp
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;
time_t tmp_ts = mktime(&t);
// FIXME - can opportunistically attempt to set RTC from GPS timestamp?
// 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!
// FIXME - NULL ISLAND is a real location on Earth!
foundLocation = (tmp_lat != 0) && (tmp_lon != 0) &&
(tmp_lat <= 900000000) && (tmp_lat >= -900000000) &&
(tmp_dop < max_dop);
// only if entire dataset is valid, update globals from temp vars
if (foundLocation) {
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
p.longitude_i = tmp_lon;
p.latitude_i = tmp_lat;
if (fixType > 2) {
// if fix is 2d, ignore altitude data
p.altitude = tmp_alt_msl / 1000;
p.altitude_hae = tmp_alt_hae / 1000;
p.alt_geoid_sep = (tmp_alt_hae - tmp_alt_msl) / 1000;
} else {
#ifdef GPS_EXTRAVERBOSE
DEBUG_MSG("no altitude data (fixType=%d)\n", fixType);
#endif
// clean up old values in case it's a 3d-2d fix transition
p.altitude = p.altitude_hae = p.alt_geoid_sep = 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!
foundLocation = (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000);
}
p.pos_timestamp = tmp_ts;
p.PDOP = tmp_dop;
p.fix_type = fixType;
p.sats_in_view = ublox.getSIV(0);
// In debug logs, identify position by @timestamp:stage (stage 1 = birth)
DEBUG_MSG("lookForLocation() new pos@%x:1\n", tmp_ts);
} else {
// INVALID solution - should never happen
DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n",
tmp_lat, tmp_lon, tmp_alt_hae, tmp_dop);
}
ublox.flushPVT(); // reset ALL freshness flags at the end
return foundLocation;
}
bool UBloxGPS::hasLock()
{
if (radioConfig.preferences.gps_accept_2d)
return (fixType >= 2 && fixType <= 4);
else
return (fixType >= 3 && fixType <= 4);
}
bool UBloxGPS::whileIdle()
{
// if using i2c or serial look too see if any chars are ready
@@ -306,20 +201,15 @@ bool UBloxGPS::whileIdle()
/// Note: ublox doesn't need a wake method, because as soon as we send chars to the GPS it will wake up
void UBloxGPS::sleep()
{
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
// Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
ublox.powerOff();
// setGPSPower(false);
}
// Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
ublox.powerOff();
// setGPSPower(false);
}
void UBloxGPS::wake()
{
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
fixType = 0; // assume we have no fix yet
}
fixType = 0; // assume we hace no fix yet
// this is idempotent
setGPSPower(true);
// Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff()

View File

@@ -22,22 +22,22 @@ class UBloxGPS : public GPS
*
* @return true for success
*/
bool factoryReset() override;
bool factoryReset();
protected:
/**
* Returns true if we succeeded
*/
virtual bool setupGPS() override;
virtual bool setupGPS();
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle() override;
virtual bool whileIdle();
/** Idle processing while GPS is looking for lock */
virtual void whileActive() override;
virtual void whileActive();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
@@ -45,7 +45,7 @@ class UBloxGPS : public GPS
*
* @return true if we've acquired a time
*/
virtual bool lookForTime() override;
virtual bool lookForTime();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
@@ -53,12 +53,11 @@ class UBloxGPS : public GPS
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation() override;
virtual bool hasLock() override;
virtual bool lookForLocation();
/// If possible force the GPS into sleep/low power mode
virtual void sleep() override;
virtual void wake() override;
virtual void sleep();
virtual void wake();
private:
/// Attempt to connect to our GPS, returns false if no gps is present

Some files were not shown because too many files have changed in this diff Show More