Compare commits

..

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

21 changed files with 10532 additions and 364 deletions

4
.github/FUNDING.yml vendored Normal file
View file

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

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

6
.gitignore vendored
View file

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

View file

@ -2,10 +2,6 @@
// 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,6 +1,3 @@
# 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.
@ -10,8 +7,19 @@ 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,43 +1,41 @@
{ {
"callsign":"NOCALL-7",
"debug": false, "debug": false,
"beacons": [ "enhance_precision": true,
{ "beacon":
"callsign": "DJ2CS-2", {
"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,4 +1,5 @@
[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+
@ -10,7 +11,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.6 peterus/APRS-Decoder-Lib @ 0.0.5
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
@ -19,5 +20,11 @@ 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

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,16 +7,12 @@
#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);
@ -24,9 +20,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);
@ -38,26 +34,12 @@ 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);
@ -76,10 +58,10 @@ void setup() {
#endif #endif
delay(500); delay(500);
logPrintlnI("LoRa APRS Tracker booting..."); logPrintlnI("LoRa APRS Tracker by OE5BPA (Peter Buchegger)");
setup_display(); setup_display();
show_display("LoRa APRS Tracker", "is booting", "please wait", 3000); show_display("OE5BPA", "LoRa APRS Tracker", "by Peter Buchegger", 2000);
load_config(); load_config();
setup_gps(); setup_gps();
@ -94,18 +76,13 @@ 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) {
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(), 2000); show_display("INFO", "Smart Beacon is " + getSmartBeaconState(), 1000);
logPrintlnI("setup done..."); logPrintlnI("setup done...");
delay(500); delay(500);
} }
@ -141,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;
} }
} }
@ -164,7 +141,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();
@ -172,15 +149,9 @@ 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);
@ -196,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;
} }
} }
@ -206,20 +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 {
@ -263,23 +232,23 @@ 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 - Cur.: " + batteryChargeCurrent + "mA"; aprsmsg += " - _Bat.: " + batteryVoltage + "V - Cur.: " + batteryChargeCurrent + "mA";
} }
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();
logPrintlnD(data); logPrintlnD(data);
show_display("<< TX >>", data); show_display("<< TX >>", data);
@ -298,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;
@ -313,16 +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, 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 (Config.smart_beacon.active) {
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 <=
@ -334,7 +302,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(BeaconMan.getCurrentBeaconConfig()->smart_beacon.slow_rate, BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_speed * BeaconMan.getCurrentBeaconConfig()->smart_beacon.fast_rate / curr_speed) * 1000; txInterval = min(Config.smart_beacon.slow_rate, Config.smart_beacon.fast_speed * Config.smart_beacon.fast_rate / curr_speed) * 1000;
} }
} }
} }
@ -342,15 +310,13 @@ 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();
BeaconMan.loadConfig(Config.beacons); if (Config.callsign == "NOCALL-10") {
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 "
@ -491,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

@ -33,41 +33,28 @@ 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.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;
@ -94,32 +81,22 @@ void ConfigurationManagement::writeConfiguration(Configuration conf) {
} }
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

@ -33,18 +33,6 @@ 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,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

@ -11,7 +11,14 @@
#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,16 +44,6 @@ 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);
@ -80,7 +70,3 @@ double PowerManagement::getBatteryChargeDischargeCurrent() {
bool PowerManagement::isBatteryConnect() { bool PowerManagement::isBatteryConnect() {
return axp.isBatteryConnect(); return axp.isBatteryConnect();
} }
bool PowerManagement::isChargeing() {
return axp.isChargeing();
}

View file

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

10269
test/cumberland_01.nmea Normal file

File diff suppressed because it is too large Load diff

21
test/send_nmea.py Executable file
View file

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