Compare commits

...

38 commits

Author SHA1 Message Date
0276526d02 Test json 2022-08-02 23:05:47 +02:00
2aec9ad798 Fix gitignore 2022-08-02 23:05:29 +02:00
9e1d0e92c4 Update gitignore 2022-08-02 23:03:50 +02:00
9eb93880f4 Use only one version 2022-08-02 22:52:51 +02:00
34bff528b6 Change some messages 2022-08-02 22:40:32 +02:00
0e8f8324bc Update readme because of fork 2022-08-02 22:32:22 +02:00
e990c84098 Clean up 2022-08-02 22:30:13 +02:00
Peter Buchegger
780ad4ed6e
Merge pull request #66 from dahuafschmied/master
colon as time separator, more space between date and time
2022-07-06 11:34:33 +02:00
dahuafschmied
906b3d7c5c Update LoRa_APRS_Tracker.cpp 2022-07-03 15:22:14 +02:00
dahuafschmied
93d606fe0b colon as time separator, more space between date and time
for better readability
2022-06-30 23:34:22 +02:00
Peter Buchegger
c78da085d5
Merge pull request #63 from lora-aprs/decoder-lib-update
update decoder lib
2022-05-25 22:28:10 +02:00
Peter Buchegger
241dda2898 update decoder lib 2022-05-13 21:46:38 +02:00
Peter Buchegger
ea6ba8ca73
Merge pull request #62 from lora-aprs/sbias-master
Sbias master
2022-05-13 21:38:02 +02:00
Peter Buchegger
c19402f967 Merge branch 'master' of https://github.com/sbias/LoRa_APRS_Tracker into sbias-master 2022-05-13 20:32:38 +02:00
Peter Buchegger
c1f0e0576e
Merge pull request #61 from lora-aprs/refactor-github-build
fix wrong cpp file in script
2022-05-13 12:20:37 +02:00
Peter Buchegger
c02aab8403 fix wrong cpp file in script 2022-05-13 12:18:26 +02:00
Peter Buchegger
9cf7d58d2a
Merge pull request #60 from lora-aprs/refactor-github-build
refactor scripts and version
2022-05-13 11:23:31 +02:00
Peter Buchegger
287cf5e3da add issue templates 2022-05-13 11:09:39 +02:00
Peter Buchegger
89155cf8d1 version update 2022-05-13 10:35:53 +02:00
Peter Buchegger
129c7c6457 refactor scripts and version 2022-05-13 10:21:16 +02:00
Peter Buchegger
0c95ed4e2c
Merge pull request #59 from kornherp/display_toggle
add monitor turn-on/off on doubleclick
2022-05-10 23:10:34 +02:00
Peter Buchegger
2d04389266
Update LoRa_APRS_Tracker.cpp 2022-05-10 22:55:09 +02:00
Peter Buchegger
296f89bd46
Update display.cpp 2022-05-10 22:53:04 +02:00
Peter Buchegger
94ae1e2b7b
Update main.yml 2022-05-10 22:49:46 +02:00
Peter Buchegger
d523e01c92
Update display.cpp 2022-05-10 22:46:17 +02:00
Peter Buchegger
feaf0ebbad
Update LoRa_APRS_Tracker.cpp 2022-05-10 22:44:13 +02:00
Peter Kornherr
5cde231e8c add monitor turn-on/off on doubleclick 2022-05-09 22:04:32 +02:00
Peter Buchegger
fe2612526b
remove destination call digipeating as we can set the path 2022-01-15 23:47:29 +01:00
Peter Buchegger
64cfd3a0be
Merge pull request #47 from tekk/alternative-messages
Added support for multiple alternative messages/callsigns
2021-12-19 23:44:42 +01:00
Peter Buchegger
2dc2cb202a ignore vscode file and set t-beam v1 as default 2021-12-19 23:41:30 +01:00
Peter Buchegger
7120010a83 update tracker config 2021-12-19 23:41:10 +01:00
Peter Buchegger
e35de077e8
Merge branch 'master' into alternative-messages 2021-12-19 22:29:51 +01:00
Peter Buchegger
a87c3ddb76 add path 2021-12-19 22:27:29 +01:00
Peter Buchegger
f69a05eb08 add a path to the beacon 2021-12-19 21:51:56 +01:00
Tekk
6f2fd7e959 Fixed tracker.json indent 2021-12-04 08:16:31 +01:00
Tekk
df89fab51e Cleanup code 2021-12-04 04:27:24 +01:00
Tekk
0c59659da3 Added support for multiple alternative messages/callsigns 2021-12-04 04:06:38 +01:00
Sascha Bias
5623096732 handle change-led in in process-loop 2021-09-11 11:52:16 +02:00
21 changed files with 364 additions and 10532 deletions

4
.github/FUNDING.yml vendored
View file

@ -1,4 +0,0 @@
# These are supported funding model platforms
github: ['peterus']
custom: ['paypal.me/peterus07']

View file

@ -1,69 +0,0 @@
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

6
.gitignore vendored
View file

@ -1,5 +1,3 @@
.pio .pio
.vscode/.browse.c_cpp.db* .vscode
.vscode/c_cpp_properties.json /data/tracker.json
.vscode/launch.json
.vscode/ipch

View file

@ -1,7 +1,11 @@
{ {
// 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,3 +1,6 @@
# Fork
Fork off https://github.com/lora-aprs/LoRa_APRS_Tracker for my own usage.
# 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.
@ -7,19 +10,8 @@ Try it out and be part of the APRS network.
## Supported boards ## Supported boards
You can use one of the Lora32 boards:
* TTGO T-Beam V0.7 (433MHz SX1278)
* TTGO T-Beam V1 (433MHz SX1278) * TTGO T-Beam V1 (433MHz SX1278)
This boards cost around 30 Euros, they are very cheap but perfect for an LoRa iGate.
Keep in minde: you need a 433MHz version!
## Compiling and configuration
**There is a german [quick start](https://www.lora-aprs.info/docs/LoRa_APRS_iGate/quick-start-guide/) page! Take a look ;)**
**There is a french [quick start](http://www.f5kmy.fr/spip.php?article509) page! Take a look ;)**
### How to compile ### How to compile

View file

@ -1,41 +1,43 @@
{ {
"callsign":"NOCALL-7",
"debug": false, "debug": false,
"enhance_precision": true, "beacons": [
"beacon": {
{ "callsign": "DJ2CS-2",
"message":"LoRa Tracker", "path": "WIDE1-1",
"timeout": 1, "message": "LoRa Tracker",
"button_tx": false, "timeout": 1,
"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
}, },
"smart_beacon": "lora": {
{ "frequency_rx": 433775000,
"active":true, "frequency_tx": 433775000,
"turn_min":25, "power": 20,
"slow_rate":300, "spreading_factor": 12,
"slow_speed":10, "signal_bandwidth": 125000,
"fast_rate":60, "coding_rate4": 5
"fast_speed":100,
"min_tx_dist":100,
"min_bcn":5
}, },
"lora": "ptt_output": {
{ "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,5 +1,4 @@
[env:ttgo_tbeam]
[env]
platform = espressif32 @ 3.0.0 platform = espressif32 @ 3.0.0
framework = arduino framework = arduino
lib_ldf_mode = deep+ lib_ldf_mode = deep+
@ -11,7 +10,7 @@ lib_deps =
bblanchon/ArduinoJson @ 6.17.0 bblanchon/ArduinoJson @ 6.17.0
lewisxhe/AXP202X_Library @ 1.1.2 lewisxhe/AXP202X_Library @ 1.1.2
sandeepmistry/LoRa @ 0.7.2 sandeepmistry/LoRa @ 0.7.2
peterus/APRS-Decoder-Lib @ 0.0.5 peterus/APRS-Decoder-Lib @ 0.0.6
mikalhart/TinyGPSPlus @ 1.0.2 mikalhart/TinyGPSPlus @ 1.0.2
paulstoffregen/Time @ 1.6 paulstoffregen/Time @ 1.6
shaggydog/OneButton @ 1.5.0 shaggydog/OneButton @ 1.5.0
@ -20,11 +19,5 @@ 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-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
[env:ttgo-t-beam-v0_7]
board = ttgo-t-beam
build_flags = -Werror -Wall -DTTGO_T_Beam_V0_7

49
scripts/check_version.py Executable file
View file

@ -0,0 +1,49 @@
#!/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)

21
scripts/create_version_tag.py Executable file
View file

@ -0,0 +1,21 @@
#!/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}")

23
src/BeaconManager.cpp Normal file
View file

@ -0,0 +1,23 @@
#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();
}
}

20
src/BeaconManager.h Normal file
View file

@ -0,0 +1,20 @@
#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,12 +7,16 @@
#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 "22.19.0"
Configuration Config; Configuration Config;
BeaconManager BeaconMan;
PowerManagement powerManagement; PowerManagement powerManagement;
OneButton userButton = OneButton(BUTTON_PIN, true, true); OneButton userButton = OneButton(BUTTON_PIN, true, true);
@ -20,9 +24,9 @@ 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);
@ -34,12 +38,26 @@ 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);
@ -58,10 +76,10 @@ void setup() {
#endif #endif
delay(500); delay(500);
logPrintlnI("LoRa APRS Tracker by OE5BPA (Peter Buchegger)"); logPrintlnI("LoRa APRS Tracker booting...");
setup_display(); setup_display();
show_display("OE5BPA", "LoRa APRS Tracker", "by Peter Buchegger", 2000); show_display("LoRa APRS Tracker", "is booting", "please wait", 3000);
load_config(); load_config();
setup_gps(); setup_gps();
@ -76,13 +94,18 @@ void setup() {
WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_OFF);
btStop(); btStop();
if (Config.beacon.button_tx) { if (Config.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) {
userButton.attachLongPressStart(handle_next_beacon);
}
userButton.attachDoubleClick(toggle_display);
logPrintlnI("Smart Beacon is " + getSmartBeaconState()); logPrintlnI("Smart Beacon is " + getSmartBeaconState());
show_display("INFO", "Smart Beacon is " + getSmartBeaconState(), 1000); show_display("INFO", "Smart Beacon is " + getSmartBeaconState(), 2000);
logPrintlnI("setup done..."); logPrintlnI("setup done...");
delay(500); delay(500);
} }
@ -118,13 +141,13 @@ void loop() {
if (gps_loc_update && nextBeaconTimeStamp <= now()) { if (gps_loc_update && nextBeaconTimeStamp <= now()) {
send_update = true; send_update = true;
if (Config.smart_beacon.active) { if (BeaconMan.getCurrentBeaconConfig()->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 (Config.beacon.timeout * rate_limit_message_text > 30) { if (BeaconMan.getCurrentBeaconConfig()->timeout * rate_limit_message_text > 30) {
rate_limit_message_text = 0; rate_limit_message_text = 0;
} }
} }
@ -141,7 +164,7 @@ void loop() {
static bool BatteryIsConnected = false; static bool BatteryIsConnected = false;
static String batteryVoltage = ""; static String batteryVoltage = "";
static String batteryChargeCurrent = ""; static String batteryChargeCurrent = "";
#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();
@ -149,9 +172,15 @@ void loop() {
batteryVoltage = String(powerManagement.getBatteryVoltage(), 2); batteryVoltage = String(powerManagement.getBatteryVoltage(), 2);
batteryChargeCurrent = String(powerManagement.getBatteryChargeDischargeCurrent(), 0); batteryChargeCurrent = String(powerManagement.getBatteryChargeDischargeCurrent(), 0);
} }
#endif
if (!send_update && gps_loc_update && Config.smart_beacon.active) {
if (powerManagement.isChargeing()) {
powerManagement.enableChgLed();
} else {
powerManagement.disableChgLed();
}
if (!send_update && gps_loc_update && BeaconMan.getCurrentBeaconConfig()->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);
@ -167,9 +196,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 > Config.smart_beacon.min_bcn * 1000) { if (lastTx > BeaconMan.getCurrentBeaconConfig()->smart_beacon.min_bcn * 1000) {
// Check for heading more than 25 degrees // Check for heading more than 25 degrees
if (headingDelta > Config.smart_beacon.turn_min && lastTxdistance > Config.smart_beacon.min_tx_dist) { if (headingDelta > BeaconMan.getCurrentBeaconConfig()->smart_beacon.turn_min && lastTxdistance > BeaconMan.getCurrentBeaconConfig()->smart_beacon.min_tx_dist) {
send_update = true; send_update = true;
} }
} }
@ -177,18 +206,20 @@ 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(Config.callsign); msg.setSource(BeaconMan.getCurrentBeaconConfig()->callsign);
msg.setDestination("APLT00-1"); msg.setPath(BeaconMan.getCurrentBeaconConfig()->path);
msg.setDestination("APLT00");
if (!Config.enhance_precision) { if (!BeaconMan.getCurrentBeaconConfig()->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 {
@ -232,23 +263,23 @@ void loop() {
} }
String aprsmsg; String aprsmsg;
aprsmsg = "!" + lat + Config.beacon.overlay + lng + Config.beacon.symbol + course_and_speed + alt; aprsmsg = "!" + lat + BeaconMan.getCurrentBeaconConfig()->overlay + lng + BeaconMan.getCurrentBeaconConfig()->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 += Config.beacon.message; aprsmsg += BeaconMan.getCurrentBeaconConfig()->message;
} }
if (BatteryIsConnected) { if (BatteryIsConnected) {
aprsmsg += " - _Bat.: " + batteryVoltage + "V - Cur.: " + batteryChargeCurrent + "mA"; aprsmsg += " - _Bat.: " + batteryVoltage + "V - Cur.: " + batteryChargeCurrent + "mA";
} }
if (Config.enhance_precision) { if (BeaconMan.getCurrentBeaconConfig()->enhance_precision) {
aprsmsg += " " + dao; aprsmsg += " " + dao;
} }
msg.getAPRSBody()->setData(aprsmsg); msg.getBody()->setData(aprsmsg);
String data = msg.encode(); String data = msg.encode();
logPrintlnD(data); logPrintlnD(data);
show_display("<< TX >>", data); show_display("<< TX >>", data);
@ -267,7 +298,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 (Config.smart_beacon.active) { if (BeaconMan.getCurrentBeaconConfig()->smart_beacon.active) {
lastTxLat = gps.location.lat(); lastTxLat = gps.location.lat();
lastTxLng = gps.location.lng(); lastTxLng = gps.location.lng();
previousHeading = currentHeading; previousHeading = currentHeading;
@ -282,15 +313,16 @@ 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()));
if (Config.smart_beacon.active) { show_display(BeaconMan.getCurrentBeaconConfig()->callsign, 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()));
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 < Config.smart_beacon.slow_speed) { if (curr_speed < BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_speed) {
txInterval = Config.smart_beacon.slow_rate * 1000; txInterval = BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_rate * 1000;
} else if (curr_speed > Config.smart_beacon.fast_speed) { } else if (curr_speed > BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_speed) {
txInterval = Config.smart_beacon.fast_rate * 1000; txInterval = BeaconMan.getCurrentBeaconConfig()->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 <=
@ -302,7 +334,7 @@ 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.
*/ */
txInterval = min(Config.smart_beacon.slow_rate, Config.smart_beacon.fast_speed * Config.smart_beacon.fast_rate / curr_speed) * 1000; txInterval = min(BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_rate, BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_speed * BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_rate / curr_speed) * 1000;
} }
} }
} }
@ -310,13 +342,15 @@ void loop() {
if ((Config.debug == false) && (millis() > 5000 && gps.charsProcessed() < 10)) { if ((Config.debug == false) && (millis() > 5000 && gps.charsProcessed() < 10)) {
logPrintlnE("No GPS frames detected! Try to reset the GPS Chip with this " logPrintlnE("No GPS frames detected! Try to reset the GPS Chip with this "
"firmware: https://github.com/lora-aprs/TTGO-T-Beam_GPS-reset"); "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();
if (Config.callsign == "NOCALL-10") { BeaconMan.loadConfig(Config.beacons);
if (BeaconMan.getCurrentBeaconConfig()->callsign == "NOCALL-10") {
logPrintlnE("You have to change your settings in 'data/tracker.json' and " logPrintlnE("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 " show_display("ERROR", "You have to change your settings in 'data/tracker.json' and "
@ -457,11 +491,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 (Config.smart_beacon.active) { if (BeaconMan.getCurrentBeaconConfig()->smart_beacon.active) {
return "On"; return "On";
} }
return "Off"; return "Off";

View file

@ -33,28 +33,41 @@ Configuration ConfigurationManagement::readConfiguration() {
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.smart_beacon.active = data["smart_beacon"]["active"] | false; conf.debug = data["debug"] | false;
conf.smart_beacon.turn_min = data["smart_beacon"]["turn_min"] | 25;
conf.smart_beacon.slow_rate = data["smart_beacon"]["slow_rate"] | 300; JsonArray beacons = data["beacons"].as<JsonArray>();
conf.smart_beacon.slow_speed = data["smart_beacon"]["slow_speed"] | 10; for (JsonVariant v : beacons) {
conf.smart_beacon.fast_rate = data["smart_beacon"]["fast_rate"] | 60; Configuration::Beacon beacon;
conf.smart_beacon.fast_speed = data["smart_beacon"]["fast_speed"] | 100;
conf.smart_beacon.min_tx_dist = data["smart_beacon"]["min_tx_dist"] | 100; if (v.containsKey("callsign"))
conf.smart_beacon.min_bcn = data["smart_beacon"]["min_bcn"] | 5; beacon.callsign = v["callsign"].as<String>();
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;
@ -81,22 +94,32 @@ void ConfigurationManagement::writeConfiguration(Configuration conf) {
} }
DynamicJsonDocument data(2048); DynamicJsonDocument data(2048);
data["callsign"] = conf.callsign; JsonArray beacons = data.createNestedArray("beacons");
data["debug"] = conf.debug; for (Configuration::Beacon beacon : conf.beacons) {
data["enhance_precision"] = conf.enhance_precision; JsonObject v = beacons.createNestedObject();
data["beacon"]["message"] = conf.beacon.message; v["callsign"] = beacon.callsign;
data["beacon"]["timeout"] = conf.beacon.timeout; v["path"] = beacon.path;
data["beacon"]["symbol"] = conf.beacon.symbol; v["message"] = beacon.message;
data["beacon"]["overlay"] = conf.beacon.overlay; v["timeout"] = beacon.timeout;
data["beacon"]["button_tx"] = conf.beacon.button_tx; v["symbol"] = beacon.symbol;
data["smart_beacon"]["active"] = conf.smart_beacon.active; v["overlay"] = beacon.overlay;
data["smart_beacon"]["turn_min"] = conf.smart_beacon.turn_min;
data["smart_beacon"]["slow_rate"] = conf.smart_beacon.slow_rate; v["smart_beacon"]["active"] = beacon.smart_beacon.active;
data["smart_beacon"]["slow_speed"] = conf.smart_beacon.slow_speed; v["smart_beacon"]["turn_min"] = beacon.smart_beacon.turn_min;
data["smart_beacon"]["fast_rate"] = conf.smart_beacon.fast_rate; v["smart_beacon"]["slow_rate"] = beacon.smart_beacon.slow_rate;
data["smart_beacon"]["fast_speed"] = conf.smart_beacon.fast_speed; v["smart_beacon"]["slow_speed"] = beacon.smart_beacon.slow_speed;
data["smart_beacon"]["min_tx_dist"] = conf.smart_beacon.min_tx_dist; v["smart_beacon"]["fast_rate"] = beacon.smart_beacon.fast_rate;
data["smart_beacon"]["min_bcn"] = conf.smart_beacon.min_bcn; v["smart_beacon"]["fast_speed"] = beacon.smart_beacon.fast_speed;
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,6 +1,7 @@
#ifndef CONFIGURATION_H_ #ifndef CONFIGURATION_H_
#define CONFIGURATION_H_ #define CONFIGURATION_H_
#include <iterator>
#include <list> #include <list>
#include <Arduino.h> #include <Arduino.h>
@ -9,29 +10,32 @@ class Configuration {
public: public:
class Beacon { class Beacon {
public: public:
Beacon() : message("LoRa Tracker, Info: github.com/lora-aprs/LoRa_APRS_Tracker"), timeout(1), symbol("["), overlay("/"), button_tx(false) { 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;
};
Beacon() : callsign("NOCALL-10"), path("WIDE1-1"), message("LoRa Tracker"), timeout(1), symbol("["), overlay("/"), enhance_precision(true) {
} }
String message; String callsign;
int timeout; String path;
String symbol; String message;
String overlay; int timeout;
bool button_tx; String symbol;
}; String overlay;
Smart_Beacon smart_beacon;
class Smart_Beacon { bool enhance_precision;
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 {
@ -59,15 +63,23 @@ public:
bool reverse; bool reverse;
}; };
Configuration() : callsign("NOCALL-10"), debug(false), enhance_precision(true){}; class Button {
public:
Button() : tx(false), alt_message(false) {
}
String callsign; bool tx;
bool debug; int alt_message;
bool enhance_precision; };
Beacon beacon;
Smart_Beacon smart_beacon; Configuration() : debug(false) {
LoRa lora; }
PTT ptt;
bool debug;
std::list<Beacon> beacons;
LoRa lora;
PTT ptt;
Button button;
}; };
class ConfigurationManagement { class ConfigurationManagement {

View file

@ -33,6 +33,18 @@ void setup_display() {
display.display(); display.display();
} }
// cppcheck-suppress unusedFunction
void display_toggle(bool toggle) {
logPrintI("Toggling display: ");
if (toggle) {
logPrintlnI("On");
display.ssd1306_command(SSD1306_DISPLAYON);
} else {
logPrintlnI("Off");
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,6 +3,7 @@
#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

@ -11,14 +11,7 @@
#define BUTTON_PIN 38 // The middle button GPIO on the T-Beam #define BUTTON_PIN 38 // The middle button GPIO on the T-Beam
#ifdef TTGO_T_Beam_V0_7
#define GPS_RX 15
#define GPS_TX 12
#endif
#ifdef TTGO_T_Beam_V1_0
#define GPS_RX 12 #define GPS_RX 12
#define GPS_TX 34 #define GPS_TX 34
#endif
#endif #endif

View file

@ -44,6 +44,16 @@ void PowerManagement::decativateOLED() {
axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF);
} }
// cppcheck-suppress unusedFunction
void PowerManagement::disableChgLed() {
axp.setChgLEDMode(AXP20X_LED_OFF);
}
// cppcheck-suppress unusedFunction
void PowerManagement::enableChgLed() {
axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL);
}
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void PowerManagement::activateMeasurement() { void PowerManagement::activateMeasurement() {
axp.adc1Enable(AXP202_BATT_CUR_ADC1 | AXP202_BATT_VOL_ADC1, true); axp.adc1Enable(AXP202_BATT_CUR_ADC1 | AXP202_BATT_VOL_ADC1, true);
@ -70,3 +80,7 @@ double PowerManagement::getBatteryChargeDischargeCurrent() {
bool PowerManagement::isBatteryConnect() { bool PowerManagement::isBatteryConnect() {
return axp.isBatteryConnect(); return axp.isBatteryConnect();
} }
bool PowerManagement::isChargeing() {
return axp.isChargeing();
}

View file

@ -18,6 +18,9 @@ public:
void activateOLED(); void activateOLED();
void decativateOLED(); void decativateOLED();
void enableChgLed();
void disableChgLed();
void activateMeasurement(); void activateMeasurement();
void deactivateMeasurement(); void deactivateMeasurement();
@ -25,6 +28,7 @@ public:
double getBatteryChargeDischargeCurrent(); double getBatteryChargeDischargeCurrent();
bool isBatteryConnect(); bool isBatteryConnect();
bool isChargeing();
private: private:
AXP20X_Class axp; AXP20X_Class axp;

File diff suppressed because it is too large Load diff

View file

@ -1,21 +0,0 @@
#!/bin/python
import time
import sys
import serial
f = open(sys.argv[1], "r")
ser = serial.Serial(sys.argv[2], 115200, timeout=0)
sleep_count = 0
for x in f:
s = ser.read(100)
if s:
print(s.decode(), end='')
sleep_count = sleep_count + 1
ser.write(x.encode())
if sleep_count > 2:
time.sleep(1)
sleep_count = 0
ser.close()
f.close()