aboutsummaryrefslogtreecommitdiffstats
path: root/tracker-stm32/src
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2023-08-15 15:26:40 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2023-08-15 15:26:40 +0200
commit5234c1c79558e6608ffd66305b6d1f27027b4af7 (patch)
tree2588d6ddaf251bd0177b763547781f396611feef /tracker-stm32/src
parent08581bacefb31b3113fa757215f78ab790567b62 (diff)
downloadlora-aprs-hb9egm-5234c1c79558e6608ffd66305b6d1f27027b4af7.tar.gz
lora-aprs-hb9egm-5234c1c79558e6608ffd66305b6d1f27027b4af7.tar.bz2
lora-aprs-hb9egm-5234c1c79558e6608ffd66305b6d1f27027b4af7.zip
Adapt tracker-stm32 to hercules
Diffstat (limited to 'tracker-stm32/src')
-rw-r--r--tracker-stm32/src/main.cpp228
1 files changed, 170 insertions, 58 deletions
diff --git a/tracker-stm32/src/main.cpp b/tracker-stm32/src/main.cpp
index 409c2c1..e452712 100644
--- a/tracker-stm32/src/main.cpp
+++ b/tracker-stm32/src/main.cpp
@@ -1,10 +1,32 @@
// Licence: MIT
+// This file is a bit of a mess, because first it contained aprs434 compressed
+// code running on STM32H7, and now it contains traditional APRS-over-LoRa for STM32F1
#include <Arduino.h>
+#include <SemihostingStream.h>
#include <RadioLib.h>
#include <Wire.h>
#include <TinyGPS++.h>
#include <SD.h>
#include "compression.h"
+#include "utils.h"
+
+// Pin mapping: outputs
+constexpr int LED_STATUSn = PB8;
+constexpr int LED_TXn = PB9;
+constexpr int EN_PA = PB3;
+constexpr int EN_RX = PB4;
+constexpr int LORA_RESET = PB11;
+
+// Pin mapping: inputs
+constexpr int BTN1n = PC13;
+constexpr int BTN2n = PC14;
+constexpr int BTN3n = PC15;
+constexpr int ENCODER_SW_1 = PB12;
+constexpr int ENCODER_SW_2 = PB13;
+constexpr int ENCODER_SW_4 = PB14;
+constexpr int ENCODER_SW_8 = PB15;
+
+constexpr int BAT_MEAS = PA0;
// Date Type Codes defined in aprs434.github.io
constexpr int DATA_TYPE_CODE_GEOLOCATION = 0;
@@ -13,25 +35,27 @@ constexpr int DATA_TYPE_CODE_STATUS_REPORT = 1;
// TODO: read these settings from the SD Card
constexpr char CALLSIGN[] = "HB9EGM";
constexpr int SSID = 7;
+constexpr char CALLSIGN_SSID_PATH[] = "HB9EGM-7>APZEGM";
constexpr int PATH_CODE = 2; // metropolitan mobile
constexpr char SYMBOL_TABLE_IDENTIFIER = '/';
constexpr char SYMBOL_CODE_BICYCLE = 'b';
constexpr char SYMBOL_CODE_FOOT = '[';
-constexpr long REPORT_TX_INTERVAL = 15000;
+constexpr long REPORT_TX_INTERVAL = 181000;
constexpr long TEXT_TX_INTERVAL = 47000;
constexpr char TEXT_REPORT[] = "mpb.li/git/lora-aprs-hb9egm"; // Max length=28
+
#if 0
File myFile;
constexpr int SD_CS = 17;
#endif
-// SX1278 has the following connections:
-// NSS pin: PD14 (Arduino 10)
-// DIO0 pin: PF3 (Arduino 8)
-// RESET pin: PF15 (Arduino 9)
-RFM96 radio = new Module(10, 8, 9);
+// LoRa module has the following connections:
+// NSS pin: PA4
+// DIO0 pin: PB10
+// RESET pin: PB11
+RFM96 radio = new Module(PA4, PB10, PB11);
HardwareSerial serialGNSS(PA10, PA9);
TinyGPSPlus gps;
@@ -40,70 +64,70 @@ long lastGnssPoll = 0;
long lastPositionReport = 0;
long lastTextReport = 0;
-constexpr size_t MAX_REPORT_LEN = 32;
+constexpr size_t MAX_REPORT_LEN = 48;
size_t report_len = 0;
uint8_t report[MAX_REPORT_LEN];
+SemihostingStream sh;
+
static char letterize(int x) {
return (char) x + 65;
}
void setup() {
- Serial.begin(9600);
- pinMode(LED_BUILTIN, OUTPUT);
+ Wire.begin();
+ pinMode(LED_STATUSn, OUTPUT);
#if 0
pinMode(SD_CS, OUTPUT);
if (!SD.begin(SD_CS)) {
- Serial.println("SD init failed!");
+ sh.println("SD init failed!");
return;
}
#endif
- Wire.begin();
-
-
+ sh.print(F("START"));
serialGNSS.begin(9600);
- Serial.print(F("[RFM] Init "));
- int state = radio.begin(433.900);
+ sh.print(F("[RFM] Init "));
+ int state = radio.begin(433.775);
if (state == RADIOLIB_ERR_NONE) {
- Serial.println(F("success!"));
+ sh.println(F("success!"));
} else {
- Serial.print(F("failed, code "));
- Serial.println(state);
+ sh.print(F("failed, code "));
+ sh.println(state);
while (true);
}
if (radio.setBandwidth(125.0) == RADIOLIB_ERR_INVALID_BANDWIDTH) {
- Serial.println(F("Selected bandwidth is invalid for this module!"));
+ sh.println(F("Selected bandwidth is invalid for this module!"));
while (true);
}
if (radio.setSpreadingFactor(12) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) {
- Serial.println(F("Selected spreading factor is invalid for this module!"));
+ sh.println(F("Selected spreading factor is invalid for this module!"));
while (true);
}
if (radio.setCodingRate(5) == RADIOLIB_ERR_INVALID_CODING_RATE) {
- Serial.println(F("Selected coding rate is invalid for this module!"));
+ sh.println(F("Selected coding rate is invalid for this module!"));
while (true);
}
// NOTE: value 0x34 is reserved for LoRaWAN networks and should not be used
if (radio.setSyncWord(0x14) != RADIOLIB_ERR_NONE) {
- Serial.println(F("Unable to set sync word!"));
+ sh.println(F("Unable to set sync word!"));
while (true);
}
- if (radio.setOutputPower(16) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) {
- Serial.println(F("Selected output power is invalid for this module!"));
+ if (radio.setOutputPower(20) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) {
+ sh.println(F("Selected output power is invalid for this module!"));
while (true);
}
if (radio.setPreambleLength(8) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) {
- Serial.println(F("Selected preamble length is invalid for this module!"));
+ sh.println(F("Selected preamble length is invalid for this module!"));
while (true);
}
@@ -113,25 +137,112 @@ void setup() {
static void handle_radio_error(int state)
{
if (state == RADIOLIB_ERR_NONE) {
- Serial.print(F(" RFM OK Datarate: "));
- Serial.print(radio.getDataRate());
- Serial.println(F(" bps"));
+ sh.print(F(" RFM OK Datarate: "));
+ sh.print(radio.getDataRate());
+ sh.println(F(" bps"));
}
else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
- Serial.println(F(" too long!"));
+ sh.println(F(" too long!"));
}
else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
- Serial.println(F(" timeout!"));
+ sh.println(F(" timeout!"));
}
else {
- Serial.print(F(" failed, code "));
- Serial.println(state);
+ sh.print(F(" failed, code "));
+ sh.println(state);
}
}
+void append_position_report()
+{
+ float Tlat, Tlon;
+ float Tspeed=0, Tcourse=0;
+ Tlat = gps.location.lat();
+ Tlon = gps.location.lng();
+ Tcourse = gps.course.deg();
+ Tspeed = gps.speed.knots();
+
+ uint32_t aprs_lat, aprs_lon;
+ aprs_lat = 900000000 - Tlat * 10000000;
+ aprs_lat = aprs_lat / 26 - aprs_lat / 2710 + aprs_lat / 15384615;
+ aprs_lon = 900000000 + Tlon * 10000000 / 2;
+ aprs_lon = aprs_lon / 26 - aprs_lon / 2710 + aprs_lon / 15384615;
+
+ char helper_base91[] = {"0000\0"};
+ int i;
+ ax25_base91enc(helper_base91, 4, aprs_lat);
+ for (i=0; i<4; i++) {
+ report[report_len++] = helper_base91[i];
+ }
+ ax25_base91enc(helper_base91, 4, aprs_lon);
+ for (i=0; i<4; i++) {
+ report[report_len++] = helper_base91[i];
+ }
+
+ report[report_len++] = SYMBOL_CODE_FOOT;
+
+ // Do not encode altitude, only course and speed
+ ax25_base91enc(helper_base91, 1, (uint32_t)Tcourse/4 );
+ report[report_len++] = helper_base91[0];
+ ax25_base91enc(helper_base91, 1, (uint32_t)(log1p(Tspeed)/0.07696));
+ report[report_len++] = helper_base91[0];
+ report[report_len++] = 0x47;
+}
+
+void loop()
+{
+ while (serialGNSS.available() > 0) {
+ gps.encode(serialGNSS.read());
+ }
+
+ const auto now = millis();
+ if (now - lastGnssPoll > 1000) {
+ lastGnssPoll = now;
+
+ const long latitude = gps.location.lat();
+ sh.print(F("Lat "));
+ sh.print(latitude);
+
+ const long longitude = gps.location.lng();
+ sh.print(F(" Lon "));
+ sh.print(longitude);
+
+ const byte SIV = gps.satellites.value();
+ sh.print(F(" SIV: "));
+ sh.println(SIV);
+ if (now - lastPositionReport > REPORT_TX_INTERVAL) {
+ lastPositionReport = now;
+
+ digitalWrite(LED_STATUSn, LOW);
+
+ report_len = 0;
+
+ report[report_len++] = '<';
+ report[report_len++] = 0xFF;
+ report[report_len++] = 0x01;
+
+ const char* p = CALLSIGN_SSID_PATH;
+ while (*p) {
+ report[report_len++] = *p;
+ p++;
+ }
+
+ report[report_len++] = ':';
+ report[report_len++] = '!';
+ report[report_len++] = SYMBOL_TABLE_IDENTIFIER;
+ append_position_report();
+ int state = radio.transmit(report, report_len);
+ handle_radio_error(state);
+
+ digitalWrite(LED_STATUSn, HIGH);
+ }
+ }
+}
+
+#if 0
void loop()
{
while (serialGNSS.available() > 0) {
@@ -144,40 +255,40 @@ void loop()
// longitude and latitude are in degrees*1e7
const long latitude = gps.location.lat();
- Serial.print(F("Lat: "));
- Serial.print(latitude);
+ sh.print(F("Lat: "));
+ sh.print(latitude);
const long longitude = gps.location.lng();
- Serial.print(F(" Long: "));
- Serial.print(longitude);
+ sh.print(F(" Long: "));
+ sh.print(longitude);
const long altitude = gps.altitude.feet();
const int speed = gps.speed.kmph();
- Serial.print(F(" Speed: "));
- Serial.print(speed);
- Serial.print(F(" (mm/s)"));
+ sh.print(F(" Speed: "));
+ sh.print(speed);
+ sh.print(F(" (mm/s)"));
// 1m/s = 900/463 knots
const double speed_kn = gps.speed.knots();
const long heading = gps.course.deg();
- Serial.print(F(" Heading: "));
- Serial.print(heading);
- Serial.print(F(" (degrees * 10^-5)"));
+ sh.print(F(" Heading: "));
+ sh.print(heading);
+ sh.print(F(" (degrees * 10^-5)"));
const byte SIV = gps.satellites.value();
- Serial.print(F(" SIV: "));
- Serial.print(SIV);
+ sh.print(F(" SIV: "));
+ sh.print(SIV);
- Serial.print(F(" TX in: "));
- Serial.print(REPORT_TX_INTERVAL - (now - lastPositionReport));
+ sh.print(F(" TX in: "));
+ sh.print(REPORT_TX_INTERVAL - (now - lastPositionReport));
- Serial.println();
+ sh.println();
if (now - lastPositionReport > REPORT_TX_INTERVAL) {
lastPositionReport = now;
- digitalWrite(LED_BUILTIN, HIGH);
+ digitalWrite(LED_STATUSn, HIGH);
// Encode Compressed Geolocation Frame according to aprs434.github.io
const uint32_t callsign_EEEE = encodeCallsign(CALLSIGN);
@@ -223,21 +334,21 @@ void loop()
report[report_len++] = tmp_base91[0];
// Debug print
- Serial.println(F("Bytes: "));
+ sh.println(F("Bytes: "));
for (int i = 0; i < report_len; i++) {
- Serial.print((uint32_t)report[i]);
+ sh.print((uint32_t)report[i]);
}
- Serial.println(F(""));
+ sh.println(F(""));
int state = radio.transmit(report, report_len);
handle_radio_error(state);
- digitalWrite(LED_BUILTIN, LOW);
+ digitalWrite(LED_STATUSn, LOW);
}
if (now - lastTextReport > TEXT_TX_INTERVAL) {
lastTextReport = now;
- digitalWrite(LED_BUILTIN, HIGH);
+ digitalWrite(LED_STATUSn, HIGH);
// Encode Compressed Status Report Frame according to aprs434.github.io
const uint32_t callsign_EEEE = encodeCallsign(CALLSIGN);
@@ -261,15 +372,16 @@ void loop()
}
}
- Serial.print(F("TX length "));
- Serial.print(report_len);
- Serial.print(F(" bytes: "));
- Serial.println(TEXT_REPORT);
+ sh.print(F("TX length "));
+ sh.print(report_len);
+ sh.print(F(" bytes: "));
+ sh.println(TEXT_REPORT);
int state = radio.transmit(report, report_len);
handle_radio_error(state);
- digitalWrite(LED_BUILTIN, LOW);
+ digitalWrite(LED_STATUSn, LOW);
}
}
}
+#endif