Compare commits

..

No commits in common. "master" and "v21.43.0" have entirely different histories.

25 changed files with 296 additions and 907 deletions

View file

@ -12,7 +12,7 @@ AlignOperands: Align
AlignTrailingComments: true AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: false AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Never AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false
@ -24,8 +24,8 @@ AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: false BinPackArguments: true
BinPackParameters: false BinPackParameters: true
BraceWrapping: BraceWrapping:
AfterCaseLabel: false AfterCaseLabel: false
AfterClass: false AfterClass: false
@ -54,7 +54,7 @@ BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true BreakStringLiterals: true
ColumnLimit: 200 ColumnLimit: 500
CommentPragmas: '^ IWYU pragma:' CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerAllOnOneLineOrOnePerLine: false

View file

@ -1,35 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: peterus
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS:
- PlatformIO Version:
- Firmware Version:
**Board name:**
-
**Additional context**
Add any other context about the problem here.

View file

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: peterus
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View file

@ -1,61 +0,0 @@
name: Integreation Tests
on:
push:
branches:
- '*'
- '!master'
pull_request:
branches:
- master
merge_group:
jobs:
build:
name: Compile Firmware
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
- name: Install PlatformIO
run: python -m pip install --upgrade pip platformio
- name: Run PlatformIO CI
run: platformio run
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: firmware
path: .pio/build/*/firmware.bin
formatting-check:
name: Formatting Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Run clang-format style check for C/C++ programs.
uses: jidicula/clang-format-action@v4.6.2
with:
clang-format-version: '11'
check-path: src
cppcheck:
name: Run cppcheck
runs-on: ubuntu-latest
env:
CPPCHECK_ARGS: --enable=all --std=c++14 --inline-suppr src
steps:
- name: checkout code
uses: actions/checkout@v2
- run: docker pull facthunder/cppcheck:latest
- name: Run cppcheck and print result
run: docker run --rm -v ${PWD}:/src facthunder/cppcheck:latest /bin/bash -c "cppcheck $CPPCHECK_ARGS"
- name: Run cppcheck and create html
run: docker run --rm -v ${PWD}:/src facthunder/cppcheck:latest /bin/bash -c "cppcheck --xml $CPPCHECK_ARGS 2> report.xml && cppcheck-htmlreport --file=report.xml --report-dir=output"
- name: Upload report
uses: actions/upload-artifact@v1
with:
name: Cppcheck Report
path: output

View file

@ -1,19 +0,0 @@
name: PlatformIO Dependabot
on:
workflow_dispatch:
schedule:
# Runs every day at 00:00
- cron: '0 0 * * *'
jobs:
dependabot:
runs-on: ubuntu-latest
name: run PlatformIO Dependabot
steps:
- name: Checkout
uses: actions/checkout@v3
- name: run PlatformIO Dependabot
uses: peterus/platformio_dependabot@v1
with:
github_token: ${{ secrets.DEPENDABOT_PAT }}

69
.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,69 @@
name: check and build
on: [push, pull_request]
jobs:
PlatformIO-Check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Cache pip
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: ${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v2
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Set up Python
uses: actions/setup-python@v2
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: Run PlatformIO Check
run: platformio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high
PlatformIO-Build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Cache pip
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: ${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v2
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Set up Python
uses: actions/setup-python@v2
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: Run PlatformIO CI
run: platformio run
- uses: actions/upload-artifact@v2
with:
name: firmware
path: .pio/build/*/firmware.bin
formatting-check:
name: Formatting Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Run clang-format style check for C/C++ programs.
uses: jidicula/clang-format-action@v3.2.0
with:
clang-format-version: '11'
check-path: src

View file

@ -1,39 +0,0 @@
name: Create new release
on:
workflow_dispatch:
jobs:
version_check:
name: Version Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v2
- run: pip install GitPython
- name: check version
run: ./scripts/check_version.py
create_release:
needs: version_check
name: Create new release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: sudo apt-get install python3-setuptools python3-wheel
- run: pip3 install platformio
- run: echo "$HOME/.local/bin" >> $GITHUB_PATH
- run: platformio run
- run: echo "VERSION=$(./scripts/create_version_tag.py)" >> $GITHUB_ENV
- uses: ncipollo/release-action@v1
with:
tag: ${{ env.VERSION }}
commit: master
generateReleaseNotes: true
artifacts: ".pio/build/lora_board/firmware.bin,data/is-cfg.json"
owner: ${{ secrets.OWNER }}
token: ${{ secrets.PAT }}

View file

@ -1,19 +0,0 @@
name: tweet-release
on:
release:
types: [published]
jobs:
tweet:
runs-on: ubuntu-latest
steps:
- uses: Eomm/why-don-t-you-tweet@v1
if: ${{ !github.event.repository.private }}
with:
tweet-message: "New ${{ github.event.repository.name }} release ${{ github.event.release.tag_name }}! ${{ github.event.release.html_url }} #LoRa #APRS #HAM #hamradio #Tracker"
env:
TWITTER_CONSUMER_API_KEY: ${{ secrets.TWITTER_CONSUMER_API_KEY }}
TWITTER_CONSUMER_API_SECRET: ${{ secrets.TWITTER_CONSUMER_API_SECRET }}
TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}

1
.gitignore vendored
View file

@ -3,4 +3,3 @@
.vscode/c_cpp_properties.json .vscode/c_cpp_properties.json
.vscode/launch.json .vscode/launch.json
.vscode/ipch .vscode/ipch
.vscode/settings.json

View file

@ -1,11 +1,7 @@
{ {
// See http://go.microsoft.com/fwlink/?LinkId=827846 // See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format // for the documentation about the extensions.json format
"recommendations": [ "recommendations": [
"platformio.platformio-ide", "platformio.platformio-ide"
"xaver.clang-format" ]
], }
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

View file

@ -1,14 +1,3 @@
# Status update September 2025
Over the past year, my focus has shifted to other projects, and Ive decided its time to close the chapter on this one. I will no longer provide updates or support, and the repository will be archived.
This project has been a fun journey, and Id like to thank everyone who used, contributed, or shared feedback along the way. Your interest and support kept it alive far longer than I originally expected.
If youre looking for a great alternative, I recommend [CA2RXU LoRa APRS Tracker/Station](https://github.com/richonguzman/LoRa_APRS_Tracker).
73,
OE5BPA
# LoRa APRS Tracker # LoRa APRS Tracker
The LoRa APRS Tracker will work with very cheep hardware which you can buy from amazon, ebay or aliexpress. The LoRa APRS Tracker will work with very cheep hardware which you can buy from amazon, ebay or aliexpress.
@ -21,8 +10,7 @@ Try it out and be part of the APRS network.
You can use one of the Lora32 boards: You can use one of the Lora32 boards:
* TTGO T-Beam V0.7 (433MHz SX1278) * TTGO T-Beam V0.7 (433MHz SX1278)
* TTGO T-Beam V1.0 and V1.1 (433MHz SX1278) * TTGO T-Beam V1 (433MHz SX1278)
* TTGO T-Beam V1.2 AXP2101 (433MHz SX1278)
This boards cost around 30 Euros, they are very cheap but perfect for an LoRa iGate. This boards cost around 30 Euros, they are very cheap but perfect for an LoRa iGate.
Keep in minde: you need a 433MHz version! Keep in minde: you need a 433MHz version!
@ -42,7 +30,6 @@ The best success is to use PlatformIO (and it is the only platform where I can s
* When installed click 'the ant head' on the left and choose import the project on the right. * When installed click 'the ant head' on the left and choose import the project on the right.
* Just open the folder and you can compile the Firmware. * Just open the folder and you can compile the Firmware.
### Configuration ### Configuration
* You can find all nessesary settings to change for your configuration in **data/tracker.json**. * You can find all nessesary settings to change for your configuration in **data/tracker.json**.
@ -50,23 +37,6 @@ The best success is to use PlatformIO (and it is the only platform where I can s
* To upload it to your board you have to do this via **Upload File System image** in PlatformIO! * To upload it to your board you have to do this via **Upload File System image** in PlatformIO!
* To find the 'Upload File System image' click the PlatformIO symbol (the little alien) on the left side, choos your configuration, click on 'Platform' and search for 'Upload File System image'. * To find the 'Upload File System image' click the PlatformIO symbol (the little alien) on the left side, choos your configuration, click on 'Platform' and search for 'Upload File System image'.
#### Step on console
You may not need to use PlatformIO because compilation and configuration can be done via console.
```
# switch to virtual env, for example using pipenv
pipenv shell
# install platformio
pipenv install platformio
# upload to board
pio run -t upload
```
## LoRa iGate ## LoRa iGate
Look at my other project: a [LoRa iGate](https://github.com/peterus/LoRa_APRS_iGate) Look at my other project: a [LoRa iGate](https://github.com/peterus/LoRa_APRS_iGate)

View file

@ -1,43 +1,41 @@
{ {
"callsign":"NOCALL-7",
"debug": false, "debug": false,
"beacons": [ "enhance_precision": true,
{ "beacon":
"callsign": "NOCALL-7", {
"path": "WIDE1-1", "message":"LoRa Tracker",
"message": "LoRa Tracker", "timeout": 1,
"timeout": 1, "button_tx": false,
"symbol": "[", "symbol": "[",
"overlay": "/", "overlay": "/"
"smart_beacon": {
"active": true,
"turn_min": 25,
"slow_rate": 300,
"slow_speed": 10,
"fast_rate": 60,
"fast_speed": 100,
"min_tx_dist": 100,
"min_bcn": 5
},
"enhance_precision": true
}
],
"button": {
"tx": true,
"alt_message": true
}, },
"lora": { "smart_beacon":
"frequency_rx": 433775000, {
"frequency_tx": 433775000, "active":true,
"power": 20, "turn_min":25,
"spreading_factor": 12, "slow_rate":300,
"signal_bandwidth": 125000, "slow_speed":10,
"coding_rate4": 5 "fast_rate":60,
"fast_speed":100,
"min_tx_dist":100,
"min_bcn":5
}, },
"ptt_output": { "lora":
"active": false, {
"frequency_rx":433775000,
"frequency_tx":433775000,
"power":20,
"spreading_factor":12,
"signal_bandwidth":125000,
"coding_rate4":5
},
"ptt_output":
{
"active":false,
"io_pin": 4, "io_pin": 4,
"start_delay": 0, "start_delay": 0,
"end_delay": 0, "end_delay": 0,
"reverse": false "reverse":false
} }
} }

View file

@ -1,32 +1,26 @@
[platformio]
default_envs = ttgo-t-beam-v1
[env] [env]
platform = espressif32 @ 6.7.0 platform = espressif32 @ 3.0.0
framework = arduino framework = arduino
lib_ldf_mode = deep+ lib_ldf_mode = deep+
monitor_speed = 115200 monitor_speed = 115200
monitor_filters = esp32_exception_decoder monitor_filters = esp32_exception_decoder
lib_deps = lib_deps =
adafruit/Adafruit GFX Library @ 1.11.9 adafruit/Adafruit GFX Library @ 1.7.5
adafruit/Adafruit SSD1306 @ 2.5.10 adafruit/Adafruit SSD1306 @ 2.4.0
bblanchon/ArduinoJson @ 7.0.4 bblanchon/ArduinoJson @ 6.17.0
lewisxhe/XPowersLib @ 0.2.4 lewisxhe/AXP202X_Library @ 1.1.2
sandeepmistry/LoRa @ 0.8.0 sandeepmistry/LoRa @ 0.7.2
peterus/APRS-Decoder-Lib @ 0.0.6 peterus/APRS-Decoder-Lib @ 0.0.5
mikalhart/TinyGPSPlus @ 1.1.0 mikalhart/TinyGPSPlus @ 1.0.2
paulstoffregen/Time @ 1.6 paulstoffregen/Time @ 1.6
shaggydog/OneButton @ 1.5.0 shaggydog/OneButton @ 1.5.0
peterus/esp-logger @ 1.0.0 peterus/esp-logger @ 0.0.1
check_tool = cppcheck check_tool = cppcheck
check_flags = check_flags =
cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK
check_skip_packages = yes check_skip_packages = yes
[env:ttgo-t-beam-AXP2101-v1_2]
board = ttgo-t-beam
build_flags = -Werror -Wall -DTTGO_T_Beam_V1_2
[env:ttgo-t-beam-v1] [env:ttgo-t-beam-v1]
board = ttgo-t-beam board = ttgo-t-beam
build_flags = -Werror -Wall -DTTGO_T_Beam_V1_0 build_flags = -Werror -Wall -DTTGO_T_Beam_V1_0

View file

@ -1,49 +0,0 @@
#!/usr/bin/env python3
import git
from datetime import date
today = date.today()
current_year = int(str(today.isocalendar()[0])[2:])
current_week = int(today.isocalendar()[1])
version = None
with open("src/LoRa_APRS_Tracker.cpp") as f:
for line in f:
if line.startswith("#define VERSION"):
version = line.strip().split(" ")[-1].replace('"', "")
version_split = version.split(".")
version_year = int(version_split[0])
version_week = int(version_split[1])
version_vers = int(version_split[2])
print(f"[INFO] firmware version year: {version_year}")
print(f"[INFO] firmware version week: {version_week}")
print(f"[INFO] firmware version version: {version_vers}")
print(f"[INFO] -> {version}")
print(f"[INFO] current year: {current_year}")
print(f"[INFO] current week: {current_week}")
print(f"[INFO] -> {current_year}.{current_week}.x")
error = False
if version_year != current_year:
print("[ERROR] firmware version is not current year!")
error = True
if version_week != current_week:
print("[ERROR] firmware version is not current week!")
error = True
repo = git.Repo('.')
print(f"[INFO] found {len(repo.tags)} tags in repo")
if f"v{version}" in repo.tags:
print("[ERROR] tag with this version is already existing")
error = True
if error:
print("[ERROR] check/update VERSION define in src/LoRa_APRS_iGate.cpp to fix this issue")
exit(error)

View file

@ -1,21 +0,0 @@
#!/usr/bin/env python3
from datetime import date
today = date.today()
current_year = int(str(today.isocalendar()[0])[2:])
current_week = int(today.isocalendar()[1])
version = None
with open("src/LoRa_APRS_Tracker.cpp") as f:
for line in f:
if line.startswith("#define VERSION"):
version = line.strip().split(" ")[-1].replace('"', "")
version_split = version.split(".")
version_year = int(version_split[0])
version_week = int(version_split[1])
version_vers = int(version_split[2])
print(f"v{version_year}.{version_week}.{version_vers}")

View file

@ -1,23 +0,0 @@
#include "BeaconManager.h"
BeaconManager::BeaconManager() : _currentBeaconConfig(_beacon_config.end()) {
}
// cppcheck-suppress unusedFunction
void BeaconManager::loadConfig(const std::list<Configuration::Beacon> &beacon_config) {
_beacon_config = beacon_config;
_currentBeaconConfig = _beacon_config.begin();
}
// cppcheck-suppress unusedFunction
std::list<Configuration::Beacon>::iterator BeaconManager::getCurrentBeaconConfig() const {
return _currentBeaconConfig;
}
// cppcheck-suppress unusedFunction
void BeaconManager::loadNextBeacon() {
++_currentBeaconConfig;
if (_currentBeaconConfig == _beacon_config.end()) {
_currentBeaconConfig = _beacon_config.begin();
}
}

View file

@ -1,20 +0,0 @@
#ifndef BEACON_MANAGER_H_
#define BEACON_MANAGER_H_
#include "configuration.h"
class BeaconManager {
public:
BeaconManager();
void loadConfig(const std::list<Configuration::Beacon> &beacon_config);
std::list<Configuration::Beacon>::iterator getCurrentBeaconConfig() const;
void loadNextBeacon();
private:
std::list<Configuration::Beacon> _beacon_config;
std::list<Configuration::Beacon>::iterator _currentBeaconConfig;
};
#endif

View file

@ -7,35 +7,22 @@
#include <WiFi.h> #include <WiFi.h>
#include <logger.h> #include <logger.h>
#include "BeaconManager.h"
#include "configuration.h" #include "configuration.h"
#include "display.h" #include "display.h"
#include "pins.h" #include "pins.h"
#include "power_management.h" #include "power_management.h"
#define VERSION "23.36.01"
logging::Logger logger;
Configuration Config; Configuration Config;
BeaconManager BeaconMan;
#ifdef TTGO_T_Beam_V1_0 PowerManagement powerManagement;
AXP192 axp; OneButton userButton = OneButton(BUTTON_PIN, true, true);
PowerManagement *powerManagement = &axp;
#endif
#ifdef TTGO_T_Beam_V1_2
AXP2101 axp;
PowerManagement *powerManagement = &axp;
#endif
OneButton userButton = OneButton(BUTTON_PIN, true, true);
HardwareSerial ss(1); HardwareSerial ss(1);
TinyGPSPlus gps; TinyGPSPlus gps;
void setup_gps();
void load_config(); void load_config();
void setup_lora(); void setup_lora();
void setup_gps();
String create_lat_aprs(RawDegrees lat); String create_lat_aprs(RawDegrees lat);
String create_long_aprs(RawDegrees lng); String create_long_aprs(RawDegrees lng);
@ -47,49 +34,34 @@ String createTimeString(time_t t);
String getSmartBeaconState(); String getSmartBeaconState();
String padding(unsigned int number, unsigned int width); String padding(unsigned int number, unsigned int width);
static bool send_update = true; static bool send_update = true;
static bool display_toggle_value = true;
static void handle_tx_click() { static void handle_tx_click() {
send_update = true; send_update = true;
} }
static void handle_next_beacon() {
BeaconMan.loadNextBeacon();
show_display(BeaconMan.getCurrentBeaconConfig()->callsign, BeaconMan.getCurrentBeaconConfig()->message, 2000);
}
static void toggle_display() {
display_toggle_value = !display_toggle_value;
display_toggle(display_toggle_value);
if (display_toggle_value) {
setup_display();
}
}
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
#if defined(TTGO_T_Beam_V1_0) || defined(TTGO_T_Beam_V1_2) #ifdef TTGO_T_Beam_V1_0
Wire.begin(SDA, SCL); Wire.begin(SDA, SCL);
if (powerManagement->begin(Wire)) { if (!powerManagement.begin(Wire)) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "PMU", "init done!"); logPrintlnI("AXP192 init done!");
} else { } else {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "PMU", "init failed!"); logPrintlnE("AXP192 init failed!");
} }
powerManagement->activateLoRa(); powerManagement.activateLoRa();
powerManagement->activateOLED(); powerManagement.activateOLED();
powerManagement->activateGPS(); powerManagement.activateGPS();
powerManagement->activateMeasurement(); powerManagement.activateMeasurement();
#endif #endif
delay(500); delay(500);
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Main", "LoRa APRS Tracker by OE5BPA (Peter Buchegger)"); logPrintlnI("LoRa APRS Tracker by OE5BPA (Peter Buchegger)");
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Main", "Version: " VERSION);
setup_display(); setup_display();
show_display("OE5BPA", "LoRa APRS Tracker", "by Peter Buchegger", "Version: " VERSION, 2000); show_display("OE5BPA", "LoRa APRS Tracker", "by Peter Buchegger", 2000);
load_config(); load_config();
setup_gps(); setup_gps();
@ -104,19 +76,14 @@ void setup() {
WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_OFF);
btStop(); btStop();
if (Config.button.tx) { if (Config.beacon.button_tx) {
// attach TX action to user button (defined by BUTTON_PIN) // attach TX action to user button (defined by BUTTON_PIN)
userButton.attachClick(handle_tx_click); userButton.attachClick(handle_tx_click);
} }
if (Config.button.alt_message) { logPrintlnI("Smart Beacon is " + getSmartBeaconState());
userButton.attachLongPressStart(handle_next_beacon);
}
userButton.attachDoubleClick(toggle_display);
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Main", "Smart Beacon is: %s", getSmartBeaconState());
show_display("INFO", "Smart Beacon is " + getSmartBeaconState(), 1000); show_display("INFO", "Smart Beacon is " + getSmartBeaconState(), 1000);
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Main", "setup done..."); logPrintlnI("setup done...");
delay(500); delay(500);
} }
@ -138,20 +105,9 @@ void loop() {
} }
} }
bool gps_time_update = gps.time.isUpdated(); bool gps_time_update = gps.time.isUpdated();
bool gps_loc_update = gps.location.isUpdated(); bool gps_loc_update = gps.location.isUpdated();
static bool gps_loc_update_valid = false; static time_t nextBeaconTimeStamp = -1;
static time_t nextBeaconTimeStamp = -1;
if (gps_loc_update != gps_loc_update_valid) {
gps_loc_update_valid = gps_loc_update;
if (gps_loc_update) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Loop", "GPS fix state went to VALID");
} else {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "Loop", "GPS fix state went to INVALID");
}
}
static double currentHeading = 0; static double currentHeading = 0;
static double previousHeading = 0; static double previousHeading = 0;
@ -162,13 +118,13 @@ void loop() {
if (gps_loc_update && nextBeaconTimeStamp <= now()) { if (gps_loc_update && nextBeaconTimeStamp <= now()) {
send_update = true; send_update = true;
if (BeaconMan.getCurrentBeaconConfig()->smart_beacon.active) { if (Config.smart_beacon.active) {
currentHeading = gps.course.deg(); currentHeading = gps.course.deg();
// enforce message text on slowest Config.smart_beacon.slow_rate // enforce message text on slowest Config.smart_beacon.slow_rate
rate_limit_message_text = 0; rate_limit_message_text = 0;
} else { } else {
// enforce message text every n's Config.beacon.timeout frame // enforce message text every n's Config.beacon.timeout frame
if (BeaconMan.getCurrentBeaconConfig()->timeout * rate_limit_message_text > 30) { if (Config.beacon.timeout * rate_limit_message_text > 30) {
rate_limit_message_text = 0; rate_limit_message_text = 0;
} }
} }
@ -185,18 +141,17 @@ void loop() {
static bool BatteryIsConnected = false; static bool BatteryIsConnected = false;
static String batteryVoltage = ""; static String batteryVoltage = "";
static String batteryChargeCurrent = ""; static String batteryChargeCurrent = "";
#if defined(TTGO_T_Beam_V1_0) || defined(TTGO_T_Beam_V1_2) #ifdef TTGO_T_Beam_V1_0
static unsigned int rate_limit_check_battery = 0; static unsigned int rate_limit_check_battery = 0;
if (!(rate_limit_check_battery++ % 60)) { if (!(rate_limit_check_battery++ % 60))
BatteryIsConnected = powerManagement->isBatteryConnect(); BatteryIsConnected = powerManagement.isBatteryConnect();
}
if (BatteryIsConnected) { if (BatteryIsConnected) {
batteryVoltage = String(powerManagement->getBatteryVoltage(), 2); batteryVoltage = String(powerManagement.getBatteryVoltage(), 2);
batteryChargeCurrent = String(powerManagement->getBatteryChargeDischargeCurrent(), 0); batteryChargeCurrent = String(powerManagement.getBatteryChargeDischargeCurrent(), 0);
} }
#endif #endif
if (!send_update && gps_loc_update && BeaconMan.getCurrentBeaconConfig()->smart_beacon.active) { if (!send_update && gps_loc_update && Config.smart_beacon.active) {
uint32_t lastTx = millis() - lastTxTime; uint32_t lastTx = millis() - lastTxTime;
currentHeading = gps.course.deg(); currentHeading = gps.course.deg();
lastTxdistance = TinyGPSPlus::distanceBetween(gps.location.lat(), gps.location.lng(), lastTxLat, lastTxLng); lastTxdistance = TinyGPSPlus::distanceBetween(gps.location.lat(), gps.location.lng(), lastTxLat, lastTxLng);
@ -212,9 +167,9 @@ void loop() {
// Get headings and heading delta // Get headings and heading delta
double headingDelta = abs(previousHeading - currentHeading); double headingDelta = abs(previousHeading - currentHeading);
if (lastTx > BeaconMan.getCurrentBeaconConfig()->smart_beacon.min_bcn * 1000) { if (lastTx > Config.smart_beacon.min_bcn * 1000) {
// Check for heading more than 25 degrees // Check for heading more than 25 degrees
if (headingDelta > BeaconMan.getCurrentBeaconConfig()->smart_beacon.turn_min && lastTxdistance > BeaconMan.getCurrentBeaconConfig()->smart_beacon.min_tx_dist) { if (headingDelta > Config.smart_beacon.turn_min && lastTxdistance > Config.smart_beacon.min_tx_dist) {
send_update = true; send_update = true;
} }
} }
@ -222,21 +177,18 @@ void loop() {
} }
if (send_update && gps_loc_update) { if (send_update && gps_loc_update) {
send_update = false; send_update = false;
nextBeaconTimeStamp = now() + (Config.smart_beacon.active ? Config.smart_beacon.slow_rate : (Config.beacon.timeout * SECS_PER_MIN));
nextBeaconTimeStamp =
now() + (BeaconMan.getCurrentBeaconConfig()->smart_beacon.active ? BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_rate : (BeaconMan.getCurrentBeaconConfig()->timeout * SECS_PER_MIN));
APRSMessage msg; APRSMessage msg;
String lat; String lat;
String lng; String lng;
String dao; String dao;
msg.setSource(BeaconMan.getCurrentBeaconConfig()->callsign); msg.setSource(Config.callsign);
msg.setPath(BeaconMan.getCurrentBeaconConfig()->path); msg.setDestination("APLT00-1");
msg.setDestination("APLT00");
if (!BeaconMan.getCurrentBeaconConfig()->enhance_precision) { if (!Config.enhance_precision) {
lat = create_lat_aprs(gps.location.rawLat()); lat = create_lat_aprs(gps.location.rawLat());
lng = create_long_aprs(gps.location.rawLng()); lng = create_long_aprs(gps.location.rawLng());
} else { } else {
@ -280,28 +232,25 @@ void loop() {
} }
String aprsmsg; String aprsmsg;
aprsmsg = "!" + lat + BeaconMan.getCurrentBeaconConfig()->overlay + lng + BeaconMan.getCurrentBeaconConfig()->symbol + course_and_speed + alt; aprsmsg = "!" + lat + Config.beacon.overlay + lng + Config.beacon.symbol + course_and_speed + alt;
// message_text every 10's packet (i.e. if we have beacon rate 1min at high // message_text every 10's packet (i.e. if we have beacon rate 1min at high
// speed -> every 10min). May be enforced above (at expirey of smart beacon // speed -> every 10min). May be enforced above (at expirey of smart beacon
// rate (i.e. every 30min), or every third packet on static rate (i.e. // rate (i.e. every 30min), or every third packet on static rate (i.e.
// static rate 10 -> every third packet) // static rate 10 -> every third packet)
if (!(rate_limit_message_text++ % 10)) { if (!(rate_limit_message_text++ % 10)) {
aprsmsg += BeaconMan.getCurrentBeaconConfig()->message; aprsmsg += Config.beacon.message;
} }
if (BatteryIsConnected) { if (BatteryIsConnected) {
aprsmsg += " - Bat.: " + batteryVoltage + "V"; aprsmsg += " - _Bat.: " + batteryVoltage + "V - Cur.: " + batteryChargeCurrent + "mA";
#ifdef TTGO_T_Beam_V1_0
aprsmsg += " - Cur.: " + batteryChargeCurrent + "mA";
#endif
} }
if (BeaconMan.getCurrentBeaconConfig()->enhance_precision) { if (Config.enhance_precision) {
aprsmsg += " " + dao; aprsmsg += " " + dao;
} }
msg.getBody()->setData(aprsmsg); msg.getAPRSBody()->setData(aprsmsg);
String data = msg.encode(); String data = msg.encode();
logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, "Loop", "%s", data.c_str()); logPrintlnD(data);
show_display("<< TX >>", data); show_display("<< TX >>", data);
if (Config.ptt.active) { if (Config.ptt.active) {
@ -318,7 +267,7 @@ void loop() {
LoRa.write((const uint8_t *)data.c_str(), data.length()); LoRa.write((const uint8_t *)data.c_str(), data.length());
LoRa.endPacket(); LoRa.endPacket();
if (BeaconMan.getCurrentBeaconConfig()->smart_beacon.active) { if (Config.smart_beacon.active) {
lastTxLat = gps.location.lat(); lastTxLat = gps.location.lat();
lastTxLng = gps.location.lng(); lastTxLng = gps.location.lng();
previousHeading = currentHeading; previousHeading = currentHeading;
@ -333,29 +282,15 @@ void loop() {
} }
if (gps_time_update) { if (gps_time_update) {
show_display(Config.callsign, createDateString(now()) + " " + createTimeString(now()), String("Sats: ") + gps.satellites.value() + " HDOP: " + gps.hdop.hdop(), String("Nxt Bcn: ") + (Config.smart_beacon.active ? "~" : "") + createTimeString(nextBeaconTimeStamp), BatteryIsConnected ? (String("Bat: ") + batteryVoltage + "V, " + batteryChargeCurrent + "mA") : "Powered via USB", String("Smart Beacon: " + getSmartBeaconState()));
show_display(BeaconMan.getCurrentBeaconConfig()->callsign, if (Config.smart_beacon.active) {
createDateString(now()) + " " + createTimeString(now()),
String("Sats: ") + gps.satellites.value() + " HDOP: " + gps.hdop.hdop(),
String("Next Bcn: ") + (BeaconMan.getCurrentBeaconConfig()->smart_beacon.active ? "~" : "") + createTimeString(nextBeaconTimeStamp),
BatteryIsConnected ? (String("Bat: ") + batteryVoltage + "V, " + batteryChargeCurrent + "mA") : "Powered via USB",
String("Smart Beacon: " + getSmartBeaconState()));
Serial.println(BeaconMan.getCurrentBeaconConfig()->callsign);
Serial.println(createDateString(now()) + " " + createTimeString(now()));
Serial.println(String("Sats: ") + gps.satellites.value() + " HDOP: " + gps.hdop.hdop());
Serial.println(String("Next Bcn: ") + (BeaconMan.getCurrentBeaconConfig()->smart_beacon.active ? "~" : "") + createTimeString(nextBeaconTimeStamp));
Serial.println(BatteryIsConnected ? (String("Bat: ") + batteryVoltage + "V, " + batteryChargeCurrent + "mA") : "Powered via USB");
Serial.println(String("Smart Beacon: " + getSmartBeaconState()));
Serial.println();
if (BeaconMan.getCurrentBeaconConfig()->smart_beacon.active) {
// Change the Tx internal based on the current speed // Change the Tx internal based on the current speed
int curr_speed = (int)gps.speed.kmph(); int curr_speed = (int)gps.speed.kmph();
if (curr_speed < BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_speed) { if (curr_speed < Config.smart_beacon.slow_speed) {
txInterval = BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_rate * 1000; txInterval = Config.smart_beacon.slow_rate * 1000;
} else if (curr_speed > BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_speed) { } else if (curr_speed > Config.smart_beacon.fast_speed) {
txInterval = BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_rate * 1000; txInterval = Config.smart_beacon.fast_rate * 1000;
} else { } else {
/* Interval inbetween low and high speed /* Interval inbetween low and high speed
min(slow_rate, ..) because: if slow rate is 300s at slow speed <= min(slow_rate, ..) because: if slow rate is 300s at slow speed <=
@ -367,52 +302,41 @@ void loop() {
would lead to decrease of beacon rate in between 5 to 20 km/h. what would lead to decrease of beacon rate in between 5 to 20 km/h. what
is even below the slow speed rate. is even below the slow speed rate.
*/ */
if (curr_speed == 0) { txInterval = min(Config.smart_beacon.slow_rate, Config.smart_beacon.fast_speed * Config.smart_beacon.fast_rate / curr_speed) * 1000;
curr_speed = 1;
}
txInterval = min(BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_rate,
BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_speed * BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_rate / curr_speed) *
1000;
} }
} }
} }
if ((Config.debug == false) && (millis() > 5000 && gps.charsProcessed() < 10)) { if ((Config.debug == false) && (millis() > 5000 && gps.charsProcessed() < 10)) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, logPrintlnE("No GPS frames detected! Try to reset the GPS Chip with this "
"GPS", "firmware: https://github.com/lora-aprs/TTGO-T-Beam_GPS-reset");
"No GPS frames detected! Try to reset the GPS Chip with this "
"firmware: https://github.com/lora-aprs/TTGO-T-Beam_GPS-reset");
show_display("No GPS frames detected!", "Try to reset the GPS Chip", "https://github.com/lora-aprs/TTGO-T-Beam_GPS-reset", 2000);
} }
} }
void load_config() { void load_config() {
ConfigurationManagement confmg("/tracker.json"); ConfigurationManagement confmg("/tracker.json");
Config = confmg.readConfiguration(); Config = confmg.readConfiguration();
BeaconMan.loadConfig(Config.beacons); if (Config.callsign == "NOCALL-10") {
if (BeaconMan.getCurrentBeaconConfig()->callsign == "NOCALL-7") { logPrintlnE("You have to change your settings in 'data/tracker.json' and "
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "upload it via \"Upload File System image\"!");
"Config", show_display("ERROR", "You have to change your settings in 'data/tracker.json' and "
"You have to change your settings in 'data/tracker.json' and " "upload it via \"Upload File System image\"!");
"upload it via \"Upload File System image\"!");
show_display("ERROR",
"You have to change your settings in 'data/tracker.json' and "
"upload it via \"Upload File System image\"!");
while (true) { while (true) {
} }
} }
} }
void setup_lora() { void setup_lora() {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "Set SPI pins!"); logPrintlnI("Set SPI pins!");
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS); SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "Set LoRa pins!"); logPrintlnI("Set LoRa pins!");
LoRa.setPins(LORA_CS, LORA_RST, LORA_IRQ); LoRa.setPins(LORA_CS, LORA_RST, LORA_IRQ);
long freq = Config.lora.frequencyTx; long freq = Config.lora.frequencyTx;
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "frequency: %d", freq); logPrintI("frequency: ");
logPrintlnI(String(freq));
if (!LoRa.begin(freq)) { if (!LoRa.begin(freq)) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "Starting LoRa failed!"); logPrintlnE("Starting LoRa failed!");
show_display("ERROR", "Starting LoRa failed!"); show_display("ERROR", "Starting LoRa failed!");
while (true) { while (true) {
} }
@ -423,7 +347,7 @@ void setup_lora() {
LoRa.enableCrc(); LoRa.enableCrc();
LoRa.setTxPower(Config.lora.power); LoRa.setTxPower(Config.lora.power);
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "LoRa init done!"); logPrintlnI("LoRa init done!");
show_display("INFO", "LoRa init done!", 2000); show_display("INFO", "LoRa init done!", 2000);
} }
@ -533,11 +457,11 @@ String createDateString(time_t t) {
} }
String createTimeString(time_t t) { String createTimeString(time_t t) {
return String(padding(hour(t), 2) + ":" + padding(minute(t), 2) + ":" + padding(second(t), 2)); return String(padding(hour(t), 2) + "." + padding(minute(t), 2) + "." + padding(second(t), 2));
} }
String getSmartBeaconState() { String getSmartBeaconState() {
if (BeaconMan.getCurrentBeaconConfig()->smart_beacon.active) { if (Config.smart_beacon.active) {
return "On"; return "On";
} }
return "Off"; return "Off";

View file

@ -7,14 +7,12 @@
#include "configuration.h" #include "configuration.h"
extern logging::Logger logger;
ConfigurationManagement::ConfigurationManagement(String FilePath) : mFilePath(FilePath) { ConfigurationManagement::ConfigurationManagement(String FilePath) : mFilePath(FilePath) {
if (!SPIFFS.begin(true)) { if (!SPIFFS.begin(true)) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "Configuration", "Mounting SPIFFS was not possible. Trying to format SPIFFS..."); logPrintlnE("Mounting SPIFFS was not possible. Trying to format SPIFFS...");
SPIFFS.format(); SPIFFS.format();
if (!SPIFFS.begin()) { if (!SPIFFS.begin()) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "Configuration", "Formatting SPIFFS was not okay!"); logPrintlnE("Formating SPIFFS was not okay!");
} }
} }
} }
@ -23,53 +21,40 @@ ConfigurationManagement::ConfigurationManagement(String FilePath) : mFilePath(Fi
Configuration ConfigurationManagement::readConfiguration() { Configuration ConfigurationManagement::readConfiguration() {
File file = SPIFFS.open(mFilePath); File file = SPIFFS.open(mFilePath);
if (!file) { if (!file) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "Configuration", "Failed to open file for reading..."); logPrintlnE("Failed to open file for reading...");
return Configuration(); return Configuration();
} }
DynamicJsonDocument data(2048); DynamicJsonDocument data(2048);
DeserializationError error = deserializeJson(data, file); DeserializationError error = deserializeJson(data, file);
if (error) { if (error) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "Configuration", "Failed to read file, using default configuration."); logPrintlnE("Failed to read file, using default configuration.");
} }
file.close(); file.close();
Configuration conf; Configuration conf;
if (data.containsKey("callsign"))
conf.callsign = data["callsign"].as<String>();
conf.debug = data["debug"] | false;
conf.enhance_precision = data["enhance_precision"] | false;
if (data.containsKey("beacon") && data["beacon"].containsKey("message"))
conf.beacon.message = data["beacon"]["message"].as<String>();
conf.beacon.timeout = data["beacon"]["timeout"] | 1;
if (data.containsKey("beacon") && data["beacon"].containsKey("symbol"))
conf.beacon.symbol = data["beacon"]["symbol"].as<String>();
if (data.containsKey("beacon") && data["beacon"].containsKey("overlay"))
conf.beacon.overlay = data["beacon"]["overlay"].as<String>();
if (data.containsKey("beacon") && data["beacon"].containsKey("button_tx"))
conf.beacon.button_tx = data["beacon"]["button_tx"] | false;
conf.debug = data["debug"] | false; conf.smart_beacon.active = data["smart_beacon"]["active"] | false;
conf.smart_beacon.turn_min = data["smart_beacon"]["turn_min"] | 25;
JsonArray beacons = data["beacons"].as<JsonArray>(); conf.smart_beacon.slow_rate = data["smart_beacon"]["slow_rate"] | 300;
for (JsonVariant v : beacons) { conf.smart_beacon.slow_speed = data["smart_beacon"]["slow_speed"] | 10;
Configuration::Beacon beacon; conf.smart_beacon.fast_rate = data["smart_beacon"]["fast_rate"] | 60;
conf.smart_beacon.fast_speed = data["smart_beacon"]["fast_speed"] | 100;
if (v.containsKey("callsign")) conf.smart_beacon.min_tx_dist = data["smart_beacon"]["min_tx_dist"] | 100;
beacon.callsign = v["callsign"].as<String>(); conf.smart_beacon.min_bcn = data["smart_beacon"]["min_bcn"] | 5;
if (v.containsKey("path"))
beacon.path = v["path"].as<String>();
if (v.containsKey("message"))
beacon.message = v["message"].as<String>();
beacon.timeout = v["timeout"] | 1;
if (v.containsKey("symbol"))
beacon.symbol = v["symbol"].as<String>();
if (v.containsKey("overlay"))
beacon.overlay = v["overlay"].as<String>();
beacon.smart_beacon.active = v["smart_beacon"]["active"] | false;
beacon.smart_beacon.turn_min = v["smart_beacon"]["turn_min"] | 25;
beacon.smart_beacon.slow_rate = v["smart_beacon"]["slow_rate"] | 300;
beacon.smart_beacon.slow_speed = v["smart_beacon"]["slow_speed"] | 10;
beacon.smart_beacon.fast_rate = v["smart_beacon"]["fast_rate"] | 60;
beacon.smart_beacon.fast_speed = v["smart_beacon"]["fast_speed"] | 100;
beacon.smart_beacon.min_tx_dist = v["smart_beacon"]["min_tx_dist"] | 100;
beacon.smart_beacon.min_bcn = v["smart_beacon"]["min_bcn"] | 5;
beacon.enhance_precision = v["enhance_precision"] | false;
conf.beacons.push_back(beacon);
}
conf.button.tx = data["button"]["tx"] | false;
conf.button.alt_message = data["button"]["alt_message"] | false;
conf.lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000; conf.lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000;
conf.lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000; conf.lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000;
@ -91,37 +76,27 @@ Configuration ConfigurationManagement::readConfiguration() {
void ConfigurationManagement::writeConfiguration(Configuration conf) { void ConfigurationManagement::writeConfiguration(Configuration conf) {
File file = SPIFFS.open(mFilePath, "w"); File file = SPIFFS.open(mFilePath, "w");
if (!file) { if (!file) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "Configuration", "Failed to open file for writing..."); logPrintlnE("Failed to open file for writing...");
return; return;
} }
DynamicJsonDocument data(2048); DynamicJsonDocument data(2048);
JsonArray beacons = data.createNestedArray("beacons"); data["callsign"] = conf.callsign;
for (Configuration::Beacon beacon : conf.beacons) { data["debug"] = conf.debug;
JsonObject v = beacons.createNestedObject(); data["enhance_precision"] = conf.enhance_precision;
v["callsign"] = beacon.callsign; data["beacon"]["message"] = conf.beacon.message;
v["path"] = beacon.path; data["beacon"]["timeout"] = conf.beacon.timeout;
v["message"] = beacon.message; data["beacon"]["symbol"] = conf.beacon.symbol;
v["timeout"] = beacon.timeout; data["beacon"]["overlay"] = conf.beacon.overlay;
v["symbol"] = beacon.symbol; data["beacon"]["button_tx"] = conf.beacon.button_tx;
v["overlay"] = beacon.overlay; data["smart_beacon"]["active"] = conf.smart_beacon.active;
data["smart_beacon"]["turn_min"] = conf.smart_beacon.turn_min;
v["smart_beacon"]["active"] = beacon.smart_beacon.active; data["smart_beacon"]["slow_rate"] = conf.smart_beacon.slow_rate;
v["smart_beacon"]["turn_min"] = beacon.smart_beacon.turn_min; data["smart_beacon"]["slow_speed"] = conf.smart_beacon.slow_speed;
v["smart_beacon"]["slow_rate"] = beacon.smart_beacon.slow_rate; data["smart_beacon"]["fast_rate"] = conf.smart_beacon.fast_rate;
v["smart_beacon"]["slow_speed"] = beacon.smart_beacon.slow_speed; data["smart_beacon"]["fast_speed"] = conf.smart_beacon.fast_speed;
v["smart_beacon"]["fast_rate"] = beacon.smart_beacon.fast_rate; data["smart_beacon"]["min_tx_dist"] = conf.smart_beacon.min_tx_dist;
v["smart_beacon"]["fast_speed"] = beacon.smart_beacon.fast_speed; data["smart_beacon"]["min_bcn"] = conf.smart_beacon.min_bcn;
v["smart_beacon"]["min_tx_dist"] = beacon.smart_beacon.min_tx_dist;
v["smart_beacon"]["min_bcn"] = beacon.smart_beacon.min_bcn;
v["enhance_precision"] = beacon.enhance_precision;
}
data["debug"] = conf.debug;
data["button"]["tx"] = conf.button.tx;
data["button"]["alt_message"] = conf.button.alt_message;
data["lora"]["frequency_rx"] = conf.lora.frequencyRx; data["lora"]["frequency_rx"] = conf.lora.frequencyRx;
data["lora"]["frequency_tx"] = conf.lora.frequencyTx; data["lora"]["frequency_tx"] = conf.lora.frequencyTx;

View file

@ -1,7 +1,6 @@
#ifndef CONFIGURATION_H_ #ifndef CONFIGURATION_H_
#define CONFIGURATION_H_ #define CONFIGURATION_H_
#include <iterator>
#include <list> #include <list>
#include <Arduino.h> #include <Arduino.h>
@ -10,32 +9,29 @@ class Configuration {
public: public:
class Beacon { class Beacon {
public: public:
class Smart_Beacon { Beacon() : message("LoRa Tracker, Info: github.com/lora-aprs/LoRa_APRS_Tracker"), timeout(1), symbol("["), overlay("/"), button_tx(false) {
public:
Smart_Beacon() : active(false), turn_min(25), slow_rate(300), slow_speed(10), fast_rate(60), fast_speed(100), min_tx_dist(100), min_bcn(5) {
}
bool active;
int turn_min;
int slow_rate;
int slow_speed;
int fast_rate;
int fast_speed;
int min_tx_dist;
int min_bcn;
};
Beacon() : callsign("NOCALL-10"), path("WIDE1-1"), message("LoRa Tracker"), timeout(1), symbol("["), overlay("/"), enhance_precision(true) {
} }
String callsign; String message;
String path; int timeout;
String message; String symbol;
int timeout; String overlay;
String symbol; bool button_tx;
String overlay; };
Smart_Beacon smart_beacon;
bool enhance_precision; class Smart_Beacon {
public:
Smart_Beacon() : active(false), turn_min(25), slow_rate(300), slow_speed(10), fast_rate(60), fast_speed(100), min_tx_dist(100), min_bcn(5) {
}
bool active;
int turn_min;
int slow_rate;
int slow_speed;
int fast_rate;
int fast_speed;
int min_tx_dist;
int min_bcn;
}; };
class LoRa { class LoRa {
@ -63,23 +59,15 @@ public:
bool reverse; bool reverse;
}; };
class Button { Configuration() : callsign("NOCALL-10"), debug(false), enhance_precision(true){};
public:
Button() : tx(false), alt_message(false) {
}
bool tx; String callsign;
int alt_message; bool debug;
}; bool enhance_precision;
Beacon beacon;
Configuration() : debug(false) { Smart_Beacon smart_beacon;
} LoRa lora;
PTT ptt;
bool debug;
std::list<Beacon> beacons;
LoRa lora;
PTT ptt;
Button button;
}; };
class ConfigurationManagement { class ConfigurationManagement {

View file

@ -7,8 +7,6 @@
#include "display.h" #include "display.h"
#include "pins.h" #include "pins.h"
extern logging::Logger logger;
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RST); Adafruit_SSD1306 display(128, 64, &Wire, OLED_RST);
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
@ -20,7 +18,7 @@ void setup_display() {
Wire.begin(OLED_SDA, OLED_SCL); Wire.begin(OLED_SDA, OLED_SCL);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) {
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "SSD1306", "allocation failed!"); logPrintlnE("SSD1306 allocation failed");
while (true) { while (true) {
} }
} }
@ -35,15 +33,6 @@ void setup_display() {
display.display(); display.display();
} }
// cppcheck-suppress unusedFunction
void display_toggle(bool toggle) {
if (toggle) {
display.ssd1306_command(SSD1306_DISPLAYON);
} else {
display.ssd1306_command(SSD1306_DISPLAYOFF);
}
}
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void show_display(String header, int wait) { void show_display(String header, int wait) {
display.clearDisplay(); display.clearDisplay();

View file

@ -3,7 +3,6 @@
#define DISPLAY_H_ #define DISPLAY_H_
void setup_display(); void setup_display();
void display_toggle(bool toggle);
void show_display(String header, int wait = 0); void show_display(String header, int wait = 0);
void show_display(String header, String line1, int wait = 0); void show_display(String header, String line1, int wait = 0);

View file

@ -16,7 +16,7 @@
#define GPS_TX 12 #define GPS_TX 12
#endif #endif
#if defined(TTGO_T_Beam_V1_0) || defined(TTGO_T_Beam_V1_2) #ifdef TTGO_T_Beam_V1_0
#define GPS_RX 12 #define GPS_RX 12
#define GPS_TX 34 #define GPS_TX 34
#endif #endif

View file

@ -1,218 +1,72 @@
#include <XPowersAXP192.tpp>
#include <XPowersAXP2101.tpp>
#include "power_management.h" #include "power_management.h"
AXP192::AXP192() { // cppcheck-suppress uninitMemberVar
PowerManagement::PowerManagement() {
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
bool AXP192::begin(TwoWire &port) { bool PowerManagement::begin(TwoWire &port) {
_pmu = new XPowersAXP192(port); bool result = axp.begin(port, AXP192_SLAVE_ADDRESS);
if (!_pmu->init()) { if (!result) {
delete _pmu; axp.setDCDC1Voltage(3300);
_pmu = 0;
return false;
} }
return result;
// lora radio power channel
_pmu->setPowerChannelVoltage(XPOWERS_LDO2, 3300);
// oled module power channel,
// disable it will cause abnormal communication between boot and AXP power supply,
// do not turn it off
_pmu->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
// gnss module power channel - now turned on in setGpsPower
_pmu->setPowerChannelVoltage(XPOWERS_LDO3, 3300);
// protected oled power source
//_pmu->setProtectedChannel(XPOWERS_DCDC1);
// protected esp32 power source
_pmu->setProtectedChannel(XPOWERS_DCDC3);
// disable not use channel
_pmu->disablePowerOutput(XPOWERS_DCDC2);
// disable all axp chip interrupt
_pmu->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
// Set constant current charging current
_pmu->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_780MA);
// Set up the charging voltage
_pmu->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
_pmu->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
return true;
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void AXP192::activateLoRa() { void PowerManagement::activateLoRa() {
_pmu->enablePowerOutput(XPOWERS_LDO2); axp.setPowerOutPut(AXP192_LDO2, AXP202_ON);
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void AXP192::deactivateLoRa() { void PowerManagement::deactivateLoRa() {
_pmu->disablePowerOutput(XPOWERS_LDO2); axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF);
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void AXP192::activateGPS() { void PowerManagement::activateGPS() {
_pmu->enablePowerOutput(XPOWERS_LDO3); axp.setPowerOutPut(AXP192_LDO3, AXP202_ON);
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void AXP192::deactivateGPS() { void PowerManagement::deactivateGPS() {
_pmu->disablePowerOutput(XPOWERS_LDO3); axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF);
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void AXP192::activateOLED() { void PowerManagement::activateOLED() {
_pmu->enablePowerOutput(XPOWERS_DCDC1); axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void AXP192::deactivateOLED() { void PowerManagement::decativateOLED() {
_pmu->disablePowerOutput(XPOWERS_DCDC1); axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF);
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void AXP192::activateMeasurement() { void PowerManagement::activateMeasurement() {
_pmu->enableBattVoltageMeasure(); axp.adc1Enable(AXP202_BATT_CUR_ADC1 | AXP202_BATT_VOL_ADC1, true);
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void AXP192::deactivateMeasurement() { void PowerManagement::deactivateMeasurement() {
_pmu->disableBattVoltageMeasure(); axp.adc1Enable(AXP202_BATT_CUR_ADC1 | AXP202_BATT_VOL_ADC1, false);
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
double AXP192::getBatteryVoltage() { double PowerManagement::getBatteryVoltage() {
return _pmu->getBattVoltage() / 1000.0; return axp.getBattVoltage() / 1000.0;
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
double AXP192::getBatteryChargeDischargeCurrent() { double PowerManagement::getBatteryChargeDischargeCurrent() {
if (isCharging()) { if (axp.isChargeing()) {
return ((XPowersAXP192 *)_pmu)->getBatteryChargeCurrent(); return axp.getBattChargeCurrent();
} }
return -1.0 * ((XPowersAXP192 *)_pmu)->getBattDischargeCurrent(); return -1.0 * axp.getBattDischargeCurrent();
} }
bool AXP192::isBatteryConnect() { bool PowerManagement::isBatteryConnect() {
return _pmu->isBatteryConnect(); return axp.isBatteryConnect();
}
bool AXP192::isCharging() {
return _pmu->isCharging();
}
AXP2101::AXP2101() {
}
// cppcheck-suppress unusedFunction
bool AXP2101::begin(TwoWire &port) {
_pmu = new XPowersAXP2101(port);
if (!_pmu->init()) {
delete _pmu;
_pmu = 0;
return false;
}
// Unuse power channel
_pmu->disablePowerOutput(XPOWERS_DCDC2);
_pmu->disablePowerOutput(XPOWERS_DCDC3);
_pmu->disablePowerOutput(XPOWERS_DCDC4);
_pmu->disablePowerOutput(XPOWERS_DCDC5);
_pmu->disablePowerOutput(XPOWERS_ALDO1);
_pmu->disablePowerOutput(XPOWERS_ALDO4);
_pmu->disablePowerOutput(XPOWERS_BLDO1);
_pmu->disablePowerOutput(XPOWERS_BLDO2);
_pmu->disablePowerOutput(XPOWERS_DLDO1);
_pmu->disablePowerOutput(XPOWERS_DLDO2);
// GNSS RTC PowerVDD 3300mV
_pmu->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
_pmu->enablePowerOutput(XPOWERS_VBACKUP);
// LoRa VDD 3300mV
_pmu->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
_pmu->enablePowerOutput(XPOWERS_ALDO2);
// GNSS VDD 3300mV
_pmu->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
_pmu->enablePowerOutput(XPOWERS_ALDO3);
// disable all axp chip interrupt
_pmu->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
// Set constant current charging current
_pmu->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_800MA);
// Set up the charging voltage
_pmu->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
_pmu->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
return true;
}
// cppcheck-suppress unusedFunction
void AXP2101::activateLoRa() {
_pmu->enablePowerOutput(XPOWERS_ALDO2);
}
// cppcheck-suppress unusedFunction
void AXP2101::deactivateLoRa() {
_pmu->disablePowerOutput(XPOWERS_ALDO2);
}
// cppcheck-suppress unusedFunction
void AXP2101::activateGPS() {
_pmu->enablePowerOutput(XPOWERS_ALDO3);
}
// cppcheck-suppress unusedFunction
void AXP2101::deactivateGPS() {
_pmu->disablePowerOutput(XPOWERS_ALDO3);
}
// cppcheck-suppress unusedFunction
void AXP2101::activateOLED() {
_pmu->enablePowerOutput(XPOWERS_DCDC1);
}
// cppcheck-suppress unusedFunction
void AXP2101::deactivateOLED() {
_pmu->disablePowerOutput(XPOWERS_DCDC1);
}
// cppcheck-suppress unusedFunction
void AXP2101::activateMeasurement() {
_pmu->enableBattVoltageMeasure();
}
// cppcheck-suppress unusedFunction
void AXP2101::deactivateMeasurement() {
_pmu->disableBattVoltageMeasure();
}
// cppcheck-suppress unusedFunction
double AXP2101::getBatteryVoltage() {
return _pmu->getBattVoltage() / 1000.0;
}
// cppcheck-suppress unusedFunction
double AXP2101::getBatteryChargeDischargeCurrent() {
return 0.0;
}
bool AXP2101::isBatteryConnect() {
return _pmu->isBatteryConnect();
}
bool AXP2101::isCharging() {
return _pmu->isCharging();
} }

View file

@ -1,43 +1,12 @@
#ifndef POWER_MANAGEMENT_H_ #ifndef POWER_MANAGEMENT_H_
#define POWER_MANAGEMENT_H_ #define POWER_MANAGEMENT_H_
#include <Wire.h> #include <Arduino.h>
#include <XPowersLibInterface.hpp> #include <axp20x.h>
class PowerManagement { class PowerManagement {
public: public:
~PowerManagement() { PowerManagement();
}
virtual bool begin(TwoWire &port) = 0;
virtual void activateLoRa() = 0;
virtual void deactivateLoRa() = 0;
virtual void activateGPS() = 0;
virtual void deactivateGPS() = 0;
virtual void activateOLED() = 0;
virtual void deactivateOLED() = 0;
virtual void activateMeasurement() = 0;
virtual void deactivateMeasurement() = 0;
virtual double getBatteryVoltage() = 0;
virtual double getBatteryChargeDischargeCurrent() = 0;
virtual bool isBatteryConnect() = 0;
virtual bool isCharging() = 0;
protected:
XPowersLibInterface *_pmu = 0;
};
class AXP192 : public PowerManagement {
public:
AXP192();
bool begin(TwoWire &port); bool begin(TwoWire &port);
void activateLoRa(); void activateLoRa();
@ -47,10 +16,7 @@ public:
void deactivateGPS(); void deactivateGPS();
void activateOLED(); void activateOLED();
void deactivateOLED(); void decativateOLED();
void enableChgLed();
void disableChgLed();
void activateMeasurement(); void activateMeasurement();
void deactivateMeasurement(); void deactivateMeasurement();
@ -59,35 +25,9 @@ public:
double getBatteryChargeDischargeCurrent(); double getBatteryChargeDischargeCurrent();
bool isBatteryConnect(); bool isBatteryConnect();
bool isCharging();
};
class AXP2101 : public PowerManagement { private:
public: AXP20X_Class axp;
AXP2101();
bool begin(TwoWire &port);
void activateLoRa();
void deactivateLoRa();
void activateGPS();
void deactivateGPS();
void activateOLED();
void deactivateOLED();
void enableChgLed();
void disableChgLed();
void activateMeasurement();
void deactivateMeasurement();
double getBatteryVoltage();
double getBatteryChargeDischargeCurrent();
bool isBatteryConnect();
bool isCharging();
}; };
#endif #endif