From df4514f48c1cf0d0a1859059d926fabd95fc3c25 Mon Sep 17 00:00:00 2001 From: "Hans P. Reiser" Date: Thu, 11 Apr 2019 00:00:25 +0200 Subject: [PATCH] +aprs udp (axupd) --- RX_FSK/RX_FSK.ino | 56 +++++++- libraries/SondeLib/aprs.cpp | 265 +++++++++++++++++++++++++++++++++--- 2 files changed, 302 insertions(+), 19 deletions(-) diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index ad8e961..de10d64 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -7,6 +8,7 @@ #include #include #include +#include //#include //#include @@ -26,6 +28,13 @@ int e; AsyncWebServer server(80); +const char * udpAddress = "192.168.179.21"; +const int udpPort = 9002; + +boolean connected = false; +WiFiUDP udp; + + // Set LED GPIO const int ledPin = 2; // Stores LED state @@ -360,6 +369,7 @@ void setup() Serial.begin(115200); u8x8.begin(); + aprs_gencrctab(); pinMode(LORA_LED, OUTPUT); @@ -440,7 +450,23 @@ void loopDecoder() { return; } // sonde knows the current type and frequency, and delegates to the right decoder - sonde.receiveFrame(); + int res = sonde.receiveFrame(); + + if(res==0 && connected){ + //Send a packet with position information + // first check if ID and position lat+lonis ok + if(sonde.si()->validID && (sonde.si()->validPos&0x03==0x03)) { + Serial.println("Sending position via UDP"); + SondeInfo *s = sonde.si(); + char raw[201]; + const char *str = aprs_senddata(s->lat, s->lon, s->hei, s->hs, s->dir, s->vs, sondeTypeStr[s->type], s->id, "TE0ST", "EO"); + int rawlen = aprsstr_mon2raw(str, raw, MAXLEN); + Serial.print("Sending: "); Serial.println(raw); + udp.beginPacket(udpAddress,udpPort); + udp.write((const uint8_t *)raw,rawlen); + udp.endPacket(); + } + } sonde.updateDisplay(); } @@ -508,6 +534,25 @@ String translateEncryptionType(wifi_auth_mode_t encryptionType) { } } +//wifi event handler +void WiFiEvent(WiFiEvent_t event){ + switch(event) { + case SYSTEM_EVENT_STA_GOT_IP: + //When connected set + Serial.print("WiFi connected! IP address: "); + Serial.println(WiFi.localIP()); + //initializes the UDP state + //This initializes the transfer buffer + udp.begin(WiFi.localIP(),udpPort); + connected = true; + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + Serial.println("WiFi lost connection"); + connected = false; + break; + } +} + static char* _scan[2]={"/","\\"}; void loopWifiScan() { u8x8.setFont(u8x8_font_chroma48medium8_r); @@ -515,6 +560,7 @@ void loopWifiScan() { int line=0; int cnt=0; + WiFi.disconnect(true); WiFi.mode(WIFI_STA); const char *id, *pw; int n = WiFi.scanNetworks(); @@ -539,6 +585,9 @@ void loopWifiScan() { Serial.print("Connecting to: "); Serial.println(id); u8x8.drawString(0,6, "Conn:"); u8x8.drawString(6,6, id); + //register event handler + WiFi.onEvent(WiFiEvent); + WiFi.begin(id, pw); while(WiFi.status() != WL_CONNECTED) { delay(500); @@ -546,11 +595,12 @@ void loopWifiScan() { u8x8.drawString(15,7,_scan[cnt&1]); cnt++; if(cnt==4) { - WiFi.disconnect(); // retry, for my buggy FritzBox + WiFi.disconnect(true); // retry, for my buggy FritzBox + WiFi.onEvent(WiFiEvent); WiFi.begin(id, pw); } if(cnt==10) { - WiFi.disconnect(); + WiFi.disconnect(true); delay(1000); WiFi.softAP(networks[0].id.c_str(),networks[0].pw.c_str()); IPAddress myIP = WiFi.softAPIP(); diff --git a/libraries/SondeLib/aprs.cpp b/libraries/SondeLib/aprs.cpp index 75884c7..7c57310 100644 --- a/libraries/SondeLib/aprs.cpp +++ b/libraries/SondeLib/aprs.cpp @@ -1,7 +1,50 @@ -#define MAXLEN 201 -void aprsstr_append(char *b, char *data) +/* Copyright (C) Hansi Reiser, dl9rdz + * + * partially based on dxlAPRS toolchain + * + * Copyright (C) Christian Rabler + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include ; +//#include +//#include +#include +#include +#include +#include "aprs.h" + +#if 0 +int openudp(const char *ip, int port, struct sockaddr_in *si) { + int fd; + if((fd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) return -1; + memset((char *)&si, 0, sizeof(si)); + si->sin_family = AF_INET; + si->sin_port = htons(port); + if(inet_aton(ip, &(si->sin_addr))==0) { + return -1; + } + return fd; +} + +int sendudp(int fd, struct sockaddr_in *si, char *frame, int framelen) +{ + if(sendto(fd, frame, framelen, 0, (struct sockaddr *)si, sizeof(struct sockaddr_in))==-1) { + return -1; + } + return 0; +} +#endif + + + +void aprsstr_append(char *b, const char *data) { int blen=strlen(b); + int len=strlen(data); if(blen+len>MAXLEN) len=MAXLEN-blen; strncat(b, data, len); } @@ -11,17 +54,173 @@ uint32_t realcard(float x) { else return (uint32_t)x; } + +/* CRC for AXUDP frames */ + +#define APRSCRC_POLY 0x8408 +static uint8_t CRCL[256]; +static uint8_t CRCH[256]; + +void aprs_gencrctab(void) +{ + uint32_t c; + uint32_t crc; + uint32_t i; + for (c = 0UL; c<=255UL; c++) { + crc = 255UL-c; + for (i = 0UL; i<=7UL; i++) { + if ((crc&1)) crc = (uint32_t)((uint32_t)(crc>>1)^APRSCRC_POLY); + else crc = crc>>1; + } /* end for */ + CRCL[c] = (uint8_t)crc; + CRCH[c] = (uint8_t)(255UL-(crc>>8)); + } /* end for */ +} /* end Gencrctab() */ + +static void aprsstr_appcrc(char frame[], uint32_t frame_len, int32_t size) +{ + uint8_t h; + uint8_t l; + uint8_t b; + int32_t i; + int32_t tmp; + l = 0U; + h = 0U; + tmp = size-1L; + i = 0L; + if (i<=tmp) for (;; i++) { + b = (uint8_t)((uint8_t)(uint8_t)frame[i]^l); + l = CRCL[b]^h; + h = CRCH[b]; + if (i==tmp) break; + } /* end for */ + frame[size] = (char)l; + frame[size+1L] = (char)h; +} /* end aprsstr_appcrc() */ + + +static int mkaprscall(int32_t * p, char raw[], + uint32_t * i, const char mon[], + char sep1, char sep2, char sep3, + uint32_t sbase) +{ + uint32_t s; + uint32_t l; + l = 0UL; + while ((((mon[*i] && mon[*i]!=sep1) && mon[*i]!=sep2) && mon[*i]!=sep3) + && mon[*i]!='-') { + s = (uint32_t)(uint8_t)mon[*i]*2UL&255UL; + if (s<=64UL) return 0; + raw[*p] = (char)s; + ++*p; + ++*i; + ++l; + if (l>=7UL) return 0; + } + while (l<6UL) { + raw[*p] = '@'; + ++*p; + ++l; + } + s = 0UL; + if (mon[*i]=='-') { + ++*i; + while ((uint8_t)mon[*i]>='0' && (uint8_t)mon[*i]<='9') { + s = (s*10UL+(uint32_t)(uint8_t)mon[*i])-48UL; + ++*i; + } + if (s>15UL) return 0; + } + raw[*p] = (char)((s+sbase)*2UL); + ++*p; + return 1; +} /* end call() */ + + +// returns raw len, 0 in case of error +extern int aprsstr_mon2raw(const char *mon, char raw[], int raw_len) +{ + uint32_t r; + uint32_t n; + uint32_t i; + uint32_t tmp; + int p = 7L; + i = 0UL; + fprintf(stderr,"mon2raw for %s\n", mon); + if (!mkaprscall(&p, raw, &i, mon, '>', 0, 0, 48UL)) { + return 0; + } + p = 0L; + if (mon[i]!='>') return 0; + /* ">" */ + ++i; + if (!mkaprscall(&p, raw, &i, mon, ':', ',', 0, 112UL)) { + return 0; + } + p = 14L; + n = 0UL; + while (mon[i]==',') { + ++i; + if (!mkaprscall(&p, raw, &i, mon, ':', ',', '*', 48UL)) { + return 0; + } + ++n; + if (n>8UL) { + return 0; + } + if (mon[i]=='*') { + /* "*" has repeatet sign */ + ++i; + r = (uint32_t)p; + if (r>=21UL) for (tmp = (uint32_t)(r-21UL)/7UL;;) { + raw[r-1UL] = (char)((uint32_t)(uint8_t)raw[r-1UL]+128UL); + /* set "has repeated" flags */ + if (!tmp) break; + --tmp; + r -= 7UL; + } /* end for */ + } + } + if (p==0L || mon[i]!=':') { + return 0; + } + raw[p-1L] = (char)((uint32_t)(uint8_t)raw[p-1L]+1UL); + /* end address field mark */ + raw[p] = '\003'; + ++p; + raw[p] = '\360'; + ++p; + ++i; + n = 256UL; + while (mon[i]) { + /* copy info part */ + if (p>=(int32_t)(raw_len-1)-2L || n==0UL) { + return 0; + } + raw[p] = mon[i]; + ++p; + ++i; + --n; + } + aprsstr_appcrc(raw, raw_len, p); + fprintf(stderr,"results in %s\n",raw); + return p+2; +} /* end mon2raw() */ + + #define FEET (1.0/0.3048) #define KNOTS (1.851984) -void aprs_senddata(float lat, float lon, float hei, float speed, float dir, float climb, char *type, char *objname, char *usercall) +char b[201]; +char raw[201]; + +char * aprs_senddata(float lat, float lon, float hei, float speed, float dir, float climb, const char *type, const char *objname, const char *usercall, const char *sym) { - char b[201]; *b=0; aprsstr_append(b, usercall); aprsstr_append(b, ">"); - char *destcall="APZRDZ"; - aprsstr_append(b, destcall)); + const char *destcall="APZRDZ"; + aprsstr_append(b, destcall); // uncompressed aprsstr_append(b, ":;"); char tmp[10]; @@ -30,24 +229,58 @@ void aprs_senddata(float lat, float lon, float hei, float speed, float dir, floa aprsstr_append(b, "*"); // TODO: time //aprsstr_append_data(time, ds); - aprsstr_append(b, "12:12:12h"); + aprsstr_append(b, "121212z"); int i = strlen(b); - snprintf(b+i, MAXLEN-i, "%04.2f%c", lat<0?-lat*100:lat*100, lat<0?"S":"N"); + int lati = abs((int)lat); + int latm = (fabs(lat)-lati)*6000; + snprintf(b+i, MAXLEN-i, "%02d%02d.%02d%c%c", lati, latm/100, latm%100, lat<0?'S':'N', sym[0]); i = strlen(b); - snprintf(b+i, MAXLEN-i "%5.2f%c", lon<0?-lon*100:lon*100, lon<0?"W":"E"); + int loni = abs((int)lon); + int lonm = (fabs(lon)-loni)*6000; + snprintf(b+i, MAXLEN-i, "%03d%02d.%02d%c%c", loni, lonm/100, lonm%100, lon<0?'W':'E', sym[1]); +#if 1 if(speed>0.5) { i=strlen(b); - snprintf(b+i, MAXLEN-i, "%03d/%03d", realcard(course+1.5), realcard(speed*1.0/KNOTS+0.5)); - ] - if(alt>0.5) { - i=strlen(b); - snprintf(b+i, MAXLEN-i, "/A=%06d", realcard(alt*FEET+0.5)); + snprintf(b+i, MAXLEN-i, "%03d/%03d", realcard(dir+1.5), realcard(speed*1.0/KNOTS+0.5)); } +#endif + if(hei>0.5) { + i=strlen(b); + snprintf(b+i, MAXLEN-i, "/A=%06d", realcard(hei*FEET+0.5)); + } +#if 0 + int dao=1; if(dao) { i=strlen(b); snprintf(b+i, MAXLEN-i, "!w%c%c!", 33+dao91(lat), 33+dao91(lon)); } +#endif + const char *comm="&test"; strcat(b, comm); - - + return b; } + + +#if 0 +int main(int argc, char *argv[]) +{ + Gencrctab(); + + struct sockaddr_in si; + int fd = openudp("127.0.0.1",9002,&si); + if(fd<0) { fprintf(stderr,"open failed\n"); return 1; } + + float lat=48, lon=10; + while(1) { + const char *str = aprs_senddata(lat, lon, 543, 5, 180, 1.5, "RS41", "TE0ST", "TE1ST", "EO"); + int rawlen = aprsstr_mon2raw(str, raw, MAXLEN); + sendudp(fd, raw, rawlen); + + str = "OE3XKC>APMI06,qAR,OE3XLR:;ER-341109*111111z4803.61NE01532.39E0145.650MHz R15k OE3XPA"; + rawlen = aprsstr_mon2raw(str, raw, MAXLEN); + sendudp(fd, &si, raw, rawlen); + lat += 0.002; lon += 0.01; + sleep(5); + } +} +#endif