From 949ac6f75f06fc79fc10c79685408b8e95545ad1 Mon Sep 17 00:00:00 2001 From: "Hansi, dl9rdz" Date: Sat, 30 Oct 2021 11:51:12 +0200 Subject: [PATCH] ax25 aprs beacon; irq-less pmu button for m5stack --- RX_FSK/RX_FSK.ino | 79 ++++++++++++++++++++++++++++++++++++++------ RX_FSK/data/cfg.js | 5 ++- RX_FSK/src/Sonde.cpp | 6 ++-- RX_FSK/src/Sonde.h | 3 ++ RX_FSK/src/aprs.cpp | 32 +++++++++++++++++- RX_FSK/src/aprs.h | 1 + 6 files changed, 111 insertions(+), 15 deletions(-) diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index 70e6cfa..21172b9 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -43,7 +43,8 @@ AsyncWebServer server(80); AXP20X_Class axp; #define PMU_IRQ 35 SemaphoreHandle_t axpSemaphore; -bool pmu_irq = false; +// 0: cleared; 1: set; 2: do not check, also query state of axp via i2c on each loop +uint8_t pmu_irq = 0; const char *updateHost = "rdzsonde.mooo.com"; int updatePort = 80; @@ -75,6 +76,13 @@ const char *dfmSubtypeStrSH[16] = { NULL, NULL, NULL, NULL, NULL, NULL, "DFM17", // 0x0D NULL, NULL }; + +// Times in ms, i.e. station: 10 minutes, mobile: 20 seconds +//#define APRS_STATION_UPDATE_TIME (10*60*1000) +//#define APRS_MOBILE_STATION_UPDATE_TIME (20*1000) +#define APRS_STATION_UPDATE_TIME (10*1000) +#define APRS_MOBILE_STATION_UPDATE_TIME (10*1000) +unsigned long time_last_aprs_update = 0; #if FEATURE_SONDEHUB #define SONDEHUB_STATION_UPDATE_TIME (60*60*1000) // 60 min @@ -83,18 +91,19 @@ WiFiClient shclient; // Sondehub v2 int shImportInterval = 0; char shImport = 0; unsigned long time_last_update = 0; +#endif /* SH_LOC_OFF: never send position information to SondeHub SH_LOC_FIXED: send fixed position (if specified in config) to sondehub SH_LOC_CHASE: always activate chase mode and send GPS position (if available) SH_LOC_AUTO: if there is no valid GPS position, or GPS position < MIN_LOC_AUTO_DIST away from known fixed position: use FIXED mode otherwise, i.e. if there is a valid GPS position and (either no fixed position in config, or GPS position is far away from fixed position), use CHASE mode. */ +// same constants used for SondeHub and APRS enum { SH_LOC_OFF, SH_LOC_FIXED, SH_LOC_CHASE, SH_LOC_AUTO }; /* auto mode is chase if valid GPS position and (no fixed location entered OR valid GPS position and distance in lat/lon deg to fixed location > threshold) */ #define MIN_LOC_AUTO_DIST 200 /* meter */ #define SH_LOC_AUTO_IS_CHASE ( gpsPos.valid && ( (isnan(sonde.config.rxlat) || isnan(sonde.config.rxlon) ) || \ calcLatLonDist( gpsPos.lat, gpsPos.lon, sonde.config.rxlat, sonde.config.rxlon ) > MIN_LOC_AUTO_DIST ) ) -#endif extern float calcLatLonDist(float lat1, float lon1, float lat2, float lon2); // KISS over TCP for communicating with APRSdroid @@ -745,7 +754,7 @@ struct st_configitems config_list[] = { {"mp3h.rxbw", 0, &sonde.config.mp3h.rxbw}, {"ephftp", 39, &sonde.config.ephftp}, /* APRS settings */ - {"call", 8, sonde.config.call}, + {"call", 9, sonde.config.call}, {"passcode", 0, &sonde.config.passcode}, /* KISS tnc settings */ {"kisstnc.active", 0, &sonde.config.kisstnc.active}, @@ -760,6 +769,9 @@ struct st_configitems config_list[] = { {"tcp.active", -3, &sonde.config.tcpfeed.active}, {"tcp.host", 63, sonde.config.tcpfeed.host}, {"tcp.port", 0, &sonde.config.tcpfeed.port}, + {"tcp.chase", 0, &sonde.config.chase}, + {"tcp.comment", 30, sonde.config.comment}, + {"tcp.bcall", 9, sonde.config.bcall}, {"tcp.idformat", -2, &sonde.config.tcpfeed.idformat}, {"tcp.highrate", 0, &sonde.config.tcpfeed.highrate}, #if FEATURE_CHASEMAPPER @@ -2008,13 +2020,13 @@ void handlePMUirq() { button2.pressed = KP_MID; button2.keydownTime = my_millis(); } - pmu_irq = false; + if(pmu_irq!=2) { pmu_irq = 0; } axp.clearIRQ(); xSemaphoreGive( axpSemaphore ); } } else { Serial.println("handlePMIirq() called. THIS SHOULD NOT HAPPEN w/o button2_axp set"); - pmu_irq = false; // prevent main loop blocking + pmu_irq = 0; // prevent main loop blocking } } @@ -2171,6 +2183,7 @@ void setup() // Display backlight on M5 Core2 axp.setPowerOutPut(AXP192_DCDC3, AXP202_ON); axp.setDCDC3Voltage(3300); + pmu_irq = 2; // IRQ pin is not connected on Core2 } else { // GPS on T-Beam, buzzer on M5 Core2 axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); @@ -2182,11 +2195,13 @@ void setup() axp.adc1Enable(AXP202_VBUS_VOL_ADC1, 1); axp.adc1Enable(AXP202_VBUS_CUR_ADC1, 1); axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1); - if (sonde.config.button2_axp) { - pinMode(PMU_IRQ, INPUT_PULLUP); - attachInterrupt(PMU_IRQ, [] { - pmu_irq = true; - }, FALLING); + if (sonde.config.button2_axp ) { + if(pmu_irq !=2) { + pinMode(PMU_IRQ, INPUT_PULLUP); + attachInterrupt(PMU_IRQ, [] { + pmu_irq = 1; + }, FALLING); + } //axp.enableIRQ(AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ, 1); axp.enableIRQ( AXP202_PEK_LONGPRESS_IRQ | AXP202_PEK_SHORTPRESS_IRQ, 1 ); axp.clearIRQ(); @@ -2601,6 +2616,10 @@ void loopDecoder() { sondehub_finish_data(&shclient, s, &sonde.config.sondehub); #endif } + // Send own position periodically + if(sonde.config.tcpfeed.active) { + aprs_station_update(); + } // always send data, even if not valid.... if (rdzclient.connected()) { Serial.println("Sending position via TCP as rdzJSON"); @@ -3445,6 +3464,46 @@ void loop() { } +void aprs_station_update() { + int chase = sonde.config.chase; + // automatically decided if CHASE or FIXED mode is used (for config AUTO) + if (chase == SH_LOC_AUTO) { + if (SH_LOC_AUTO_IS_CHASE) chase = SH_LOC_CHASE; else chase = SH_LOC_FIXED; + } + unsigned long time_now = millis(); + unsigned long time_delta = time_now - time_last_aprs_update; + unsigned long update_time = (chase == SH_LOC_CHASE) ? APRS_MOBILE_STATION_UPDATE_TIME : APRS_STATION_UPDATE_TIME; + if(time_delta < update_time) return; + Serial.println("Update is due!!"); + + float lat, lon; + if(chase == SH_LOC_FIXED) { + // fixed location + lat = sonde.config.rxlat; + lon = sonde.config.rxlon; + if(isnan(lat) || isnan(lon)) return; + } else { + if (gpsPos.valid && gpsPos.lat != 0 && gpsPos.lon != 0) { + lat = gpsPos.lat; + lon = gpsPos.lon; + } else { + return; + } + } + Serial.printf("Really updating!! (bcall is %s)", sonde.config.bcall); + time_last_aprs_update = time_now; + char *bcn = aprs_send_beacon(sonde.config.bcall, lat, lon, "/O"); + if ( tcpclient.disconnected()) { + tcpclient.connect(sonde.config.tcpfeed.host, sonde.config.tcpfeed.port); + } + if ( tcpclient.connected() ) { + strcat(bcn, "\r\n"); + Serial.println("****BEACON****"); + Serial.print(bcn); + tcpclient.write(bcn, strlen(bcn)); + } +} + #if FEATURE_SONDEHUB // Sondehub v2 DB related codes /* diff --git a/RX_FSK/data/cfg.js b/RX_FSK/data/cfg.js index ddc6231..1b28955 100644 --- a/RX_FSK/data/cfg.js +++ b/RX_FSK/data/cfg.js @@ -42,10 +42,13 @@ var cfgs = [ [ "axudp.idformat", "DFM ID format"], [ "axudp.highrate", "Rate limit"], [ "tcp.active", "APRS TCP active"], -[ "tcp.host", "ARPS TCP host"], +[ "tcp.host", "APRS TCP host"], [ "tcp.port", "APRS TCP port"], [ "tcp.idformat", "DFM ID format"], [ "tcp.highrate", "Rate limit"], +[ "tcp.bcall", "APRS location beacon call"], +[ "tcp.chase", "APRS location reporting (0=off, 1=fixed, 2=chase/GPS, 3=auto)"], +[ "tcp.comment", "APRS location comment"], [ "", "MQTT data feed configuration", "https://github.com/dl9rdz/rdz_ttgo_sonde/wiki/MQTT-configuration"], [ "mqtt.active", "MQTT active (needs reboot)"], [ "mqtt.id", "MQTT client ID"], diff --git a/RX_FSK/src/Sonde.cpp b/RX_FSK/src/Sonde.cpp index 4680919..1edfd64 100644 --- a/RX_FSK/src/Sonde.cpp +++ b/RX_FSK/src/Sonde.cpp @@ -43,7 +43,7 @@ const char *fingerprintText[]={ /* global variables from RX_FSK.ino */ int getKeyPressEvent(); int handlePMUirq(); -extern bool pmu_irq; +extern uint8_t pmu_irq; extern SX1278FSK sx1278; /* Task model: @@ -542,10 +542,10 @@ uint16_t Sonde::waitRXcomplete() { uint16_t res=0; uint32_t t0 = millis(); rxloop: - while( !pmu_irq && rxtask.receiveResult==0xFFFF && millis()-t0 < 3000) { delay(50); } + while( (pmu_irq!=1) && rxtask.receiveResult==0xFFFF && millis()-t0 < 3000) { delay(50); } if( pmu_irq ) { handlePMUirq(); - goto rxloop; + if(pmu_irq!=2) goto rxloop; } if( rxtask.receiveResult == RX_UPDATERSSI ) { rxtask.receiveResult = 0xFFFF; diff --git a/RX_FSK/src/Sonde.h b/RX_FSK/src/Sonde.h index 36a5470..8ea9b8d 100644 --- a/RX_FSK/src/Sonde.h +++ b/RX_FSK/src/Sonde.h @@ -287,6 +287,9 @@ typedef struct st_rdzconfig { // for now, one feed for each type is enough, but might get extended to more? char call[10]; // APRS callsign int passcode; // APRS passcode + int chase; + char bcall[10]; // APRS position beacon call + char comment[32]; struct st_feedinfo udpfeed; // target for AXUDP messages struct st_feedinfo tcpfeed; // target for APRS-IS TCP connections struct st_kisstnc kisstnc; // target for KISS TNC (via TCP, mainly for APRSdroid) diff --git a/RX_FSK/src/aprs.cpp b/RX_FSK/src/aprs.cpp index dc7ff6c..10ab176 100644 --- a/RX_FSK/src/aprs.cpp +++ b/RX_FSK/src/aprs.cpp @@ -258,13 +258,43 @@ static uint32_t dao91(double x) char b[251]; //char raw[201]; +const char *destcall="APRRDZ"; + +char *aprs_send_beacon(const char *usercall, float lat, float lon, const char *sym) { + *b = 0; + aprsstr_append(b, usercall); + aprsstr_append(b, ">"); + aprsstr_append(b, destcall); +#if 0 + aprsstr_append(b, ":/"); // / is report with timestamp + int i = strlen(b); + int sec = 0; // TODO: NOW!!! + snprintf(b+i, APRS_MAXLEN, "%02d%02d%02dh", sec/(60*60), (sec%(60*60))/60, sec%60); +#else + // report without timestamp + aprsstr_append(b, ":!"); // ! is report w/p timestamp +#endif + // lat + i = strlen(b); + int lati = abs((int)lat); + int latm = (fabs(lat)-lati)*6000; + snprintf(b+i, APRS_MAXLEN-i, "%02d%02d.%02d%c%c", lati, latm/100, latm%100, lat<0?'S':'N', sym[0]); + // lon + i = strlen(b); + int loni = abs((int)lon); + int lonm = (fabs(lon)-loni)*6000; + snprintf(b+i, APRS_MAXLEN-i, "%03d%02d.%02d%c%c", loni, lonm/100, lonm%100, lon<0?'W':'E', sym[1]); + // maybe add alt + // maybe add DAO? + sprintf(b + strlen(b), "%s", version_name); + return b; +} char *aprs_senddata(SondeInfo *si, const char *usercall, const char *sym) { SondeData *s = &(si->d); *b=0; aprsstr_append(b, usercall); aprsstr_append(b, ">"); - const char *destcall="APRRDZ"; // const char *destcall="APRARX,SONDEGATE,TCPIP,qAR,oh3bsg"; aprsstr_append(b, destcall); // uncompressed diff --git a/RX_FSK/src/aprs.h b/RX_FSK/src/aprs.h index 6ac8b8e..36a9bef 100644 --- a/RX_FSK/src/aprs.h +++ b/RX_FSK/src/aprs.h @@ -8,6 +8,7 @@ void aprs_gencrctab(void); int aprsstr_mon2raw(const char *mon, char raw[], int raw_len); int aprsstr_mon2kiss(const char *mon, char raw[], int raw_len); +char *aprs_send_beacon(const char *call, float lat, float lon, const char *sym); char *aprs_senddata(SondeInfo *s, const char *usercall, const char *sym);