aboutsummaryrefslogtreecommitdiffstats
path: root/tracker-stm32/src
diff options
context:
space:
mode:
Diffstat (limited to 'tracker-stm32/src')
-rw-r--r--tracker-stm32/src/compression.cpp97
-rw-r--r--tracker-stm32/src/compression.h9
-rw-r--r--tracker-stm32/src/main.cpp (renamed from tracker-stm32/src/main.ino)134
3 files changed, 176 insertions, 64 deletions
diff --git a/tracker-stm32/src/compression.cpp b/tracker-stm32/src/compression.cpp
new file mode 100644
index 0000000..9b108fd
--- /dev/null
+++ b/tracker-stm32/src/compression.cpp
@@ -0,0 +1,97 @@
+#include "compression.h"
+
+using math::wide_integer::uint512_t;
+
+uint512_t decodeBase(int b, const char *str);
+
+const char* digits = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-./?@";
+
+// This function is from aprs434.github.io,
+// MIT License, Copyright (c) 2022 Serge Y. Stroobandt, ON4AA
+uint32_t encodeCallsign(const char *callsign) {
+ // Encode CCCC according to aprs434.github.io/code/codec.cpp
+ const int b = 37;
+
+ uint32_t result;
+ uint32_t weight;
+ int i, j, k, ch;
+
+ result = 0, weight = 1;
+ for (i = j = strlen(callsign); i > 0; i--) { // iterate over input string
+ ch = toupper(callsign[i-1]);
+ for (k = 0; k < strlen(digits); k++) { // lookup char index
+ if (digits[k] == ch) {
+ break;
+ }
+ }
+ if (k == strlen(digits)) // ignore if ch not found in digits
+ continue;
+ result = result + ((k) * weight);
+ weight = weight * b;
+ }
+
+ return result; // result can be pow(42,51)!
+}
+
+// This function is from ESP32 lora.tracker,
+// MIT License, Copyright (c) 2020 Peter Buchegger
+void ax25_base91enc(char *s, uint8_t n, uint32_t v) {
+ /* Creates a Base-91 representation of the value in v in the string
+ * pointed to by s, n-characters long. String length should be n+1.
+ */
+
+ for (s += n, *s = '\0'; n; n--) {
+ *(--s) = v % 91 + 33;
+ v /= 91;
+ }
+}
+
+static void strrev(char s[])
+{
+ int length = strlen(s) ;
+ int c, i, j;
+
+ for (i = 0, j = length - 1; i < j; i++, j--)
+ {
+ c = s[i];
+ s[i] = s[j];
+ s[j] = c;
+ }
+}
+
+inline void assert(bool cond) {
+ while (!cond) {}
+}
+
+static uint8_t bytes[100];
+
+uint512_t decodeBase(int b, const char* str) { // base b, str 64 bytes max '\0' terminated
+
+ uint512_t result;
+ uint512_t weight;
+ int i, j, k, ch;
+
+ assert(b <= strlen(digits));
+ assert(b > 1);
+
+ result = 0, weight = 1;
+ for (i = j = strlen(str); i > 0; i--) // iterate over input string
+ {
+ ch=toupper(str[i-1]);
+ for (k = 0; k < strlen(digits); k++) { //lookup char index
+ if (digits[k] == ch) {
+ break;
+ }
+ }
+ if (k == strlen(digits)) // ignore if ch not found in digits
+ continue;
+ result = result + ((k) * weight);
+ weight = weight * b;
+ }
+
+ return result; // result can be pow(42,51)!
+}
+
+uint512_t encodetttt(const char *s) {
+ return decodeBase(42, s);
+}
diff --git a/tracker-stm32/src/compression.h b/tracker-stm32/src/compression.h
new file mode 100644
index 0000000..064369b
--- /dev/null
+++ b/tracker-stm32/src/compression.h
@@ -0,0 +1,9 @@
+#pragma once
+#include "uintwide_t.h"
+
+uint32_t encodeCallsign(const char *callsign);
+
+void ax25_base91enc(char *s, uint8_t n, uint32_t v);
+
+math::wide_integer::uint512_t encodetttt(const char *s);
+
diff --git a/tracker-stm32/src/main.ino b/tracker-stm32/src/main.cpp
index 6a98cf9..1ae97e9 100644
--- a/tracker-stm32/src/main.ino
+++ b/tracker-stm32/src/main.cpp
@@ -4,15 +4,22 @@
#include <Wire.h>
#include <SparkFun_u-blox_GNSS_Arduino_Library.h>
#include <SD.h>
+#include "compression.h"
+
+// Date Type Codes defined in aprs434.github.io
+constexpr int DATA_TYPE_CODE_GEOLOCATION = 0;
+constexpr int DATA_TYPE_CODE_STATUS_REPORT = 1;
// TODO: read these settings from the SD Card
constexpr char CALLSIGN[] = "HB9EGM";
constexpr int SSID = 12;
-constexpr int DATE_TYPE_CODE = 0; // compressed geolocation
constexpr int PATH_CODE = 2; // metropolitan mobile
constexpr char SYMBOL_TABLE_IDENTIFIER = '/';
constexpr char SYMBOL_CODE_BICYCLE = 'b';
-constexpr long TX_INTERVAL = 15000;
+constexpr long REPORT_TX_INTERVAL = 15000;
+
+constexpr long TEXT_TX_INTERVAL = 47000;
+constexpr char TEXT_REPORT[] = "mpb.li/git/lora-aprs-hb9egm"; // Max length=28
#if 0
File myFile;
@@ -29,58 +36,16 @@ SFE_UBLOX_GNSS gnss;
long lastGnssPoll = 0;
long lastPositionReport = 0;
+long lastTextReport = 0;
constexpr size_t MAX_REPORT_LEN = 32;
size_t report_len = 0;
uint8_t report[MAX_REPORT_LEN];
-const char* digits = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-./?@";
-
-#define callsign_int_t uint32_t
-// This function is from aprs434.github.io,
-// MIT License, Copyright (c) 2022 Serge Y. Stroobandt, ON4AA
-callsign_int_t encodeCallsign(const char *callsign) {
- // Encode CCCC according to aprs434.github.io/code/codec.cpp
- const int b = 37;
-
- callsign_int_t result;
- callsign_int_t weight;
- int i, j, k, ch;
-
- result = 0, weight = 1;
- for (i = j = strlen(callsign); i > 0; i--) { // iterate over input string
- ch = toupper(callsign[i-1]);
- for (k = 0; k < strlen(digits); k++) { // lookup char index
- if (digits[k] == ch) {
- break;
- }
- }
- if (k == strlen(digits)) // ignore if ch not found in digits
- continue;
- result = result + ((k) * weight);
- weight = weight * b;
- }
-
- return result; // result can be pow(42,51)!
-}
-
-// This function is from ESP32 lora.tracker,
-// MIT License, Copyright (c) 2020 Peter Buchegger
-static void ax25_base91enc(char *s, uint8_t n, uint32_t v) {
- /* Creates a Base-91 representation of the value in v in the string
- * pointed to by s, n-characters long. String length should be n+1.
- */
-
- for (s += n, *s = '\0'; n; n--) {
- *(--s) = v % 91 + 33;
- v /= 91;
- }
-}
-
-
static char letterize(int x) {
return (char) x + 65;
}
+
static char* get_mh(double lat, double lon, int size) {
static char locator[11];
double LON_F[]={20,2.0,0.083333,0.008333,0.0003472083333333333};
@@ -183,6 +148,28 @@ void setup() {
// radio.setRfSwitchPins(4, 5);
}
+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"));
+
+ }
+ else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
+ Serial.println(F(" too long!"));
+
+ }
+ else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
+ Serial.println(F(" timeout!"));
+
+ }
+ else {
+ Serial.print(F(" failed, code "));
+ Serial.println(state);
+ }
+}
+
void loop()
{
const auto now = millis();
@@ -224,16 +211,16 @@ void loop()
Serial.print(SIV);
Serial.print(F(" TX in: "));
- Serial.print(TX_INTERVAL - (now - lastPositionReport));
+ Serial.print(REPORT_TX_INTERVAL - (now - lastPositionReport));
Serial.println();
- if (now - lastPositionReport > TX_INTERVAL) {
+ if (now - lastPositionReport > REPORT_TX_INTERVAL) {
lastPositionReport = now;
digitalWrite(LED_BUILTIN, HIGH);
- // Encode LoRa message according to aprs434.github.io
+ // Encode Compressed Geolocation Frame according to aprs434.github.io
const uint32_t callsign_EEEE = encodeCallsign(CALLSIGN);
report_len = 0;
@@ -244,7 +231,7 @@ void loop()
report[report_len++] = callsign_EEEE & 0xFF;
// D SSID Path Code and Data Type Code
- report[report_len++] = SSID * 16 + PATH_CODE * 4 + DATE_TYPE_CODE;
+ report[report_len++] = SSID * 16 + PATH_CODE * 4 + DATA_TYPE_CODE_GEOLOCATION;
// / Symbol Table Identifier
report[report_len++] = SYMBOL_TABLE_IDENTIFIER;
@@ -291,25 +278,44 @@ void loop()
Serial.println(F(""));
int state = radio.transmit(report, report_len);
+ handle_radio_error(state);
- if (state == RADIOLIB_ERR_NONE) {
- Serial.print(F(" RFM OK Datarate: "));
- Serial.print(radio.getDataRate());
- Serial.println(F(" bps"));
+ digitalWrite(LED_BUILTIN, LOW);
+ }
- }
- else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
- Serial.println(F(" too long!"));
+ if (now - lastTextReport > TEXT_TX_INTERVAL) {
+ lastTextReport = now;
+ digitalWrite(LED_BUILTIN, HIGH);
- }
- else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
- Serial.println(F(" timeout!"));
+ // Encode Compressed Status Report Frame according to aprs434.github.io
+ const uint32_t callsign_EEEE = encodeCallsign(CALLSIGN);
+ report_len = 0;
+ // Callsign encoded as CCCC
+ report[report_len++] = (callsign_EEEE >> 24) & 0xFF;
+ report[report_len++] = (callsign_EEEE >> 16) & 0xFF;
+ report[report_len++] = (callsign_EEEE >> 8) & 0xFF;
+ report[report_len++] = callsign_EEEE & 0xFF;
+
+ // D SSID Path Code and Data Type Code
+ report[report_len++] = SSID * 16 + PATH_CODE * 4 + DATA_TYPE_CODE_STATUS_REPORT;
+
+ // t(t...) text
+ const auto bignum = encodetttt(TEXT_REPORT);
+ for (int i = 0; i <= 512; i += 8) {
+ auto v = static_cast<uint8_t>((bignum >> (512-i)) & 0xFF);
+ if (v) {
+ report[report_len++] = v;
+ }
}
- else {
- Serial.print(F(" failed, code "));
- Serial.println(state);
- }
+
+ Serial.print(F("TX length "));
+ Serial.print(report_len);
+ Serial.print(F(" bytes: "));
+ Serial.println(TEXT_REPORT);
+
+ int state = radio.transmit(report, report_len);
+ handle_radio_error(state);
digitalWrite(LED_BUILTIN, LOW);
}