<*+M2EXTENSIONS *> <*-CHECKDIV *> <*-CHECKRANGE *> <*-COVERFLOW *> <*-IOVERFLOW*> <*-DOREORDER*> <*-PROCINLINE*> <*+NOPTRALIAS*> <*CPU="PENTIUM"*> <*-CHECKNIL *> <*-CHECKSET*> <* IF __GEN_C__ THEN *> <*-GENCTYPES*> <*+COMMENT*> <*-GENHISTORY*> <*-GENDEBUG*> <*-GENDATE*> <*-LINENO*> <*-CHECKINDEX*> <*+GENCDIV*> <*-GENKRC*> <*+NOOPTIMIZE*> <*-GENSIZE*> <*-ASSERT*> <* ELSE *> <*-GENHISTORY*> <*-GENDEBUG*> <*-LINENO*> <*-CHECKINDEX*> <* END *> IMPLEMENTATION MODULE sondeaprs; (* encode demodulated sonde to aprs axudp by OE5DXL *) FROM SYSTEM IMPORT ADR, CARD8, CARD16, SHIFT, CAST, FILL, INT16; FROM osi IMPORT WrStr, WrStrLn, WrInt, OpenRead, RdBin, Close, time, ln, ALLOCATE, File, WrFixed, udpsend, realcard, realint, OpenAppend, OpenWrite, WrBin, OpenNONBLOCK, Seekend; FROM aprsstr IMPORT mon2raw, Append, Length, TimeToStr, DateToStr, Assign, FixToStr, IntToStr, StrCmp; FROM libsrtm IMPORT srtmmaxmem, srtmdir, getsrtmlong, egm96, ATTRWATER, ATTRWOOD, ATTRURBAN; FROM aprspos IMPORT wgs84s, posvalid, azimuth, distance; IMPORT aprsstr, math; CONST CR=15C; LF=12C; KNOTS=1.851984; FEET=1.0/0.3048; LINESBUF=60; (* seconds pos history *) PI=3.14159265358979323844; DAYSEC=60*60*24; RAD=PI/180.0; MAXHRMS=50.0; (* not send if gps h pos spreads more meters *) MAXVRMS=500.0; (* not send if gps v pos spreads more meters *) MAXAGE=86400; (* context lifetime *) TYPE SHORTREAL=REAL; REAL=LONGREAL; SET16=SET OF [0..15]; SET8 =SET OF [0..7]; ERRS=(ePRES, eTEMP, eHYG, eSPEED, eDIR, eLAT, eLONG, eALT, eMISS, eRMS); ERRSET=SET OF ERRS; DATLINE=RECORD hrms, vrms, hpa, temp, hyg, alt, speed, dir, lat, long, --- climb, clb:REAL; time:TIME; END; POSITION=RECORD long, lat:REAL; END; DATS=ARRAY[0..LINESBUF-1] OF DATLINE; pCONTEXT=POINTER TO CONTEXT; CONTEXT=RECORD next :pCONTEXT; name :ARRAY[0..11] OF CHAR; dat :DATS; speedsum:REAL; speedcnt:CARDINAL; lastused, lastbeacon:TIME; commentline,cyclevals:CARDINAL; END; VAR (*CRCL, CRCH: ARRAY[0..255] OF SET8;*) contexts:pCONTEXT; chk :ERRSET; egmoff, mhzfromsonde:BOOLEAN; jsonfd:INTEGER; PROCEDURE truncc(r:LONGREAL):CARDINAL; BEGIN IF r<=0.0 THEN RETURN 0 ELSIF r>=2000000000.0 THEN RETURN 2000000000 ELSE RETURN TRUNC(r) END; END truncc; PROCEDURE GetIp(h:ARRAY OF CHAR; VAR p:CARDINAL; VAR ip:CARDINAL; VAR port:CARDINAL):INTEGER; VAR i, n:CARDINAL; ok:BOOLEAN; BEGIN p:=0; h[HIGH(h)]:=0C; ip:=0; FOR i:=0 TO 4 DO n:=0; ok:=FALSE; WHILE (h[p]>="0") & (h[p]<="9") DO ok:=TRUE; n:=n*10+ORD(h[p])-ORD("0"); INC(p); END; IF NOT ok THEN RETURN -1 END; IF i<3 THEN IF (h[p]<>".") OR (n>255) THEN RETURN -1 END; ip:=ip*256+n; ELSIF i=3 THEN ip:=ip*256+n; IF (h[p]<>":") OR (n>255) THEN RETURN -1 END; ELSIF n>65535 THEN RETURN -1 END; port:=n; INC(p); END; RETURN 0 END GetIp; PROCEDURE wrcsv(sattime:TIME; typstr-, objname:ARRAY OF CHAR; lat, long, alt, speed, dir, clb, egmalt, og, mhz:LONGREAL; goodsats:CARDINAL; uptime:TIME; hp, hyg, temp, ozon, otemp, pumpmA, pumpv:LONGREAL; sdr-:SDRBLOCK; dist, azi, ele:REAL; fullid-:ARRAY OF CHAR; txpower:CARDINAL; vBatt:REAL; txtime:INTEGER; psatsig:pSATSIG; user-:ARRAY OF CHAR; leapsecs:INTEGER; xdatas-:XDATA; ogstr-:ARRAY OF CHAR); VAR fd:File; i, j:CARDINAL; com:BOOLEAN; s,h:ARRAY[0..999] OF CHAR; void:INTEGER; jdest:pUDPDESTS; satdb:ARRAY[0..32] OF INTEGER; BEGIN IF json THEN s:="{"; Append(s, '"id":"'); Append(s, objname); Append(s, '"'); Append(s, ',"type":"'); Append(s, typstr); Append(s, '"'); IF fullid<>"" THEN Append(s, ',"ser":"'); Append(s, fullid); Append(s, '"') END; IF mhz>0.1 THEN Append(s, ',"mhz":'); FixToStr(mhz+0.005, 3, h); Append(s, h) END; Append(s, ',"date":"'); DateToStr(sattime, h); h[10]:=0C; Append(s, h); Append(s, '"'); Append(s, ',"time":"'); TimeToStr(sattime MOD DAYSEC, h); Append(s, h); Append(s, '"'); -- IF uptime>0 THEN Append(s, ',"up":'); TimeToStr(uptime, 1 ,h); Append(s, h) END; IF uptime>0 THEN Append(s, ',"up":'); IntToStr(uptime, 1 ,h); Append(s, h) END; IF txtime>BEFOREBURST THEN Append(s, ',"bursttx":'); IntToStr(txtime-BEFOREBURST, 1, h); Append(s, h); END; IF (txtime>0 ) & (txtime-10000.0) & (egmalt<100000.0) THEN Append(s, ',"egmalt":'); FixToStr(egmalt, 2, h); ; Append(s, h); END; IF (og>-10000.0) & (og<100000.0) THEN Append(s, ',"og":'); FixToStr(og, 2, h); ; Append(s, h); IF ogstr[0]<>0C THEN Append(s, ',"ogtext":"'); Append(s, ogstr); Append(s, '"') END; END; Append(s, ',"spd":'); FixToStr(speed*3.6, 2, h); Append(s, h); Append(s, ',"dir":'); FixToStr(dir, 2, h); Append(s, h); IF clb<1000.0 THEN Append(s, ',"clb":'); FixToStr(clb, 3, h); Append(s, h); END; IF goodsats>0 THEN Append(s, ',"sat":'); IntToStr(goodsats, 1, h); Append(s, h) END; IF vBatt>0.1 THEN Append(s, ',"ub":'); FixToStr(vBatt, 3, h); Append(s, h) END; IF txpower>0 THEN Append(s, ',"txpo":'); IntToStr(txpower, 2, h); Append(s, h) END; IF (temp>-1000.0) & (temp<1000.0) THEN Append(s, ',"ptu":{"t":'); FixToStr(temp, 3, h); Append(s, h); IF (hp>0.1) & (hp<2000.0) THEN Append(s, ',"p":'); FixToStr(hp, 3, h); Append(s, h) END; IF (hyg>0.1) & (hyg<=100.0) THEN Append(s, ',"h":'); FixToStr(hyg, 2, h); Append(s, h); END; Append(s, '}') END; IF ozon>0.01 THEN Append(s, ',"aux":{"o3":'); FixToStr(ozon, 3, h); Append(s, h); Append(s, ',"o3tmp":'); FixToStr(otemp, 2, h); Append(s, h); Append(s, ',"pumpma":'); FixToStr(pumpmA, 2, h); Append(s, h); Append(s, ',"pumpv":'); FixToStr(pumpv, 3, h); Append(s, h); Append(s, '}') END; IF sdr.freq<>0 THEN Append(s, ',"sdr":{"rx":'); FixToStr(FLOAT(sdr.freq)*0.00001+0.0005, 4, h); Append(s, h); IF sdr.maxafc<>0 THEN Append(s, ',"afc":'); IntToStr(sdr.afc, 1, h); Append(s, h); Append(s, ',"mafc":'); IntToStr(sdr.maxafc, 1, h); Append(s, h); END; IF sdr.db<>0 THEN Append(s, ',"rssi":'); FixToStr(FLOAT(sdr.db)*0.1, 2, h); Append(s, h) END; IF sdr.name[0]<>0C THEN Append(s, ',"rxid":"'); Append(s, sdr.name); Append(s, '"') END; Append(s, '}'); END; IF ele>=-90.0 THEN Append(s, ',"ant":{"az":'); FixToStr(azi, 2, h); Append(s, h); Append(s, ',"el":'); FixToStr(ele, 3, h); Append(s, h); Append(s, ',"d":'); FixToStr(dist, 4, h); Append(s, h); Append(s, '}'); END; Append(s, ',"uid":"'); Append(s, user); Append(s, '"'); IF psatsig<>NIL THEN FOR i:=1 TO 32 DO satdb[i]:=-1 END; FOR i:=0 TO HIGH(psatsig^) DO IF psatsig^[i].num<=HIGH(satdb) THEN satdb[psatsig^[i].num]:=psatsig^[i].level END; END; Append(s, ',"satdb":['); FOR i:=1 TO HIGH(satdb) DO IF i>1 THEN Append(s, ',') END; IF satdb[i]<0 THEN Append(s, "-1"); ELSIF satdb[i]=0 THEN Append(s, "0"); ELSE FixToStr(VAL(REAL,satdb[i])*0.2, 2, h); Append(s, h); END; END; Append(s, ']') END; Append(s, ',"leaps":'); IntToStr(leapsecs, 1, h); ; Append(s, h); j:=0; WHILE j0 THEN IntToStr(j, 1, h); ; Append(s, h) END; Append(s, '":['); i:=0; WHILE i0 THEN Append(s, ",") END; IntToStr(ORD(xdatas.xdata[j].frame[i]), 1, h); Append(s, h); INC(i); END; Append(s, ']'); INC(j); END; Append(s, '}'+LF); IF csvfilename[0]<>0C THEN IF jsonfd<0 THEN jsonfd:=OpenNONBLOCK(csvfilename); IF jsonfd<0 THEN jsonfd:=OpenWrite(csvfilename) ELSE Seekend(jsonfd, 0) END; (* no file and no pipe *) END; IF jsonfd>=0 THEN WrBin(jsonfd, s, Length(s)) ELSE WrStrLn("cannot write json-file") END; END; jdest:=jsondests; WHILE jdest<>NIL DO void:=udpsend(udpsock, s, Length(s), jdest^.port, jdest^.ipnum); jdest:=jdest^.next; END; ELSE fd:=OpenAppend(csvfilename); IF fd<0 THEN fd:=OpenWrite(csvfilename); s:="Date,Time,Type,Name,lat,long,alt,speed,dir,clb,egmalt,og,mhz,sats,uptime,hPa,hum,temp,ozon,ozont,pumpmA,pumpV,RxMHz,AFC,maxAFC,rssi,dev,dist,azimuth,elevation,ser,TXdBm,batt,TxOff"+LF; ELSE s:=""; END; IF fd<0 THEN WrStrLn("cannot write csv-file"); RETURN END; IF s[0]<>0C THEN WrBin(fd, s, Length(s)) END; (* csv headline *) s:=""; IF sattime>=DAYSEC THEN DateToStr(sattime, s); s[10]:=0C END; Append(s, ","); IF sattime>0 THEN TimeToStr(sattime MOD DAYSEC, h); Append(s, h) END; Append(s, ","); Append(s, typstr); Append(s, ","); Append(s, objname); Append(s, ","); FixToStr(lat*(1.0/RAD), 6, h); Append(s, h); Append(s, ","); FixToStr(long*(1.0/RAD), 6, h); Append(s, h); Append(s, ","); IntToStr(VAL(INTEGER, alt), 1, h); Append(s, h); Append(s, ","); FixToStr(speed*3.6, 2, h); Append(s, h); Append(s, ","); IntToStr(VAL(INTEGER, dir), 1, h); Append(s, h); Append(s, ","); IF clb<1000.0 THEN FixToStr(clb, 2, h); Append(s, h); END; Append(s, ","); IF (egmalt>-10000.0) & (egmalt<100000.0) THEN IntToStr(VAL(INTEGER, egmalt), 1, h); Append(s, h) END; Append(s, ","); IF (og>-10000.0) & (og<100000.0) THEN IntToStr(VAL(INTEGER, og), 1, h); Append(s, h) END; Append(s, ","); IF mhz>0.1 THEN FixToStr(mhz+0.005, 3, h); Append(s, h) END; Append(s, ","); IF goodsats>0 THEN IntToStr(goodsats, 1, h); Append(s, h) END; Append(s, ","); IF uptime>0 THEN TimeToStr(uptime, h); Append(s, h) END; Append(s, ","); IF (hp>0.1) & (hp<2000.0) THEN FixToStr(hp, 2, h); Append(s, h) END; Append(s, ","); IF (hyg>0.1) & (hyg<=100.0) THEN IntToStr(VAL(INTEGER,hyg), 1, h); Append(s, h) END; Append(s, ","); IF (temp>-1000.0) & (temp<1000.0) THEN FixToStr(temp, 2, h); Append(s, h) END; Append(s, ","); IF ozon>0.1 THEN FixToStr(ozon, 2, h); Append(s, h) END; Append(s, ","); IF ozon>0.1 THEN FixToStr(otemp, 2, h); Append(s, h) END; Append(s, ","); IF (ozon>0.1) & (pumpmA>0.1) THEN FixToStr(pumpmA, 2, h); Append(s, h) END; Append(s, ","); IF (ozon>0.1) & (pumpv>0.1) THEN FixToStr(pumpv, 3, h); Append(s, h) END; Append(s, ","); IF sdr.freq<>0 THEN FixToStr(FLOAT(sdr.freq)*0.00001+0.0005, 4, h); Append(s, h) END; Append(s, ","); IF sdr.maxafc<>0 THEN IntToStr(sdr.afc, 1, h); Append(s, h) END; Append(s, ","); IF sdr.maxafc<>0 THEN IntToStr(sdr.maxafc, 1, h); Append(s, h) END; Append(s, ","); IF sdr.db<>0 THEN FixToStr(FLOAT(sdr.db)*0.1, 2, h); Append(s, h) END; Append(s, ","); IF sdr.name[0]<>0C THEN Append(s, sdr.name) END; Append(s, ","); IF dist>=0.0 THEN FixToStr(dist, 4, h); Append(s, h) END; Append(s, ","); IF azi>=0.0 THEN FixToStr(azi, 2, h); Append(s, h) END; Append(s, ","); IF ele>=-90.0 THEN FixToStr(ele, 3, h); Append(s, h) END; Append(s, ","); IF fullid[0]<>0C THEN Append(s, fullid) END; Append(s, ","); IF txpower>0 THEN IntToStr(txpower, 2, h); Append(s, h) END; Append(s, ","); IF vBatt>0.1 THEN FixToStr(vBatt, 2, h); Append(s, h) END; Append(s, ","); IF txtime>=BEFOREBURST THEN DEC(txtime, BEFOREBURST) END; IF txtime>0 THEN IntToStr(txtime, 1, h); Append(s, h) END; Append(s, LF); WrBin(fd, s, Length(s)); Close(fd); END; END wrcsv; PROCEDURE egm96corr(lat, long, alt:REAL):REAL; VAR pos:aprsstr.POSITION; ok:BOOLEAN; BEGIN pos.lat:=lat; pos.long:=long; alt:=alt-egm96(pos, ok); IF ok THEN RETURN alt ELSE IF verb THEN WrStrLn("--- no EGM96 data - only raw Sonde Altitudes") END; egmoff:=TRUE; END; RETURN -100000.0; END egm96corr; PROCEDURE getoverground(lat, long, alt:REAL; VAR att:CARD8):REAL; VAR pos:aprsstr.POSITION; srtm:REAL; res:SHORTREAL; BEGIN srtmmaxmem:=1000000; pos.lat:=lat; pos.long:=long; srtm:=getsrtmlong(VAL(LONGREAL,pos.lat), VAL(LONGREAL,pos.long), 1, FALSE, res, att, NIL); IF (srtm<10000.0) & (srtm>-1000.0) THEN IF alt<=-30000.0 THEN RETURN srtm END; (* srtm request *) RETURN alt - srtm; -- ELSIF verb THEN WrStrLn("---no SRTM data"); END; RETURN -100000.0; END getoverground; (* PROCEDURE getoverground(lat, long, alt:REAL):REAL; VAR pos:aprsstr.POSITION; resolution:SHORTREAL; srtm:REAL; BEGIN srtmmaxmem:=1000000; pos.lat:=lat; pos.long:=long; srtm:=getsrtm(pos, 1, resolution); IF (srtm<10000.0) & (srtm>-1000.0) THEN IF alt<=-30000.0 THEN RETURN srtm END; (* srtm request *) RETURN alt - srtm; -- ELSIF verb THEN WrStrLn("---no SRTM data"); END; RETURN -100000.0; END getoverground; *) PROCEDURE hms(t:TIME; withsec:BOOLEAN; VAR s:ARRAY OF CHAR); VAR i:CARDINAL; PROCEDURE dig(d, div:CARDINAL; withzero:BOOLEAN); BEGIN d:=d DIV div MOD 10; IF (d>0) OR (i>0) OR withzero THEN s[i]:=CHR(d+ORD("0")); INC(i) END; END dig; BEGIN t:=t MOD 86400; i:=0; dig(t, 36000, FALSE); dig(t, 3600, FALSE); IF i>0 THEN s[i]:="h"; INC(i) END; t:=t MOD 3600; dig(t, 600, FALSE); dig(t, 60, NOT withsec); IF i>0 THEN s[i]:="m"; INC(i) END; IF withsec THEN t:=t MOD 60; dig(t, 10, FALSE); dig(t, 1, TRUE); s[i]:="s"; INC(i); END; s[i]:=0C; END hms; PROCEDURE apptxon(t:INTEGER; cyc:CARDINAL; VAR s:ARRAY OF CHAR); VAR h:ARRAY[0..20] OF CHAR; b:BOOLEAN; BEGIN b:=t>=BEFOREBURST; IF b THEN DEC(t, BEFOREBURST) END; IF (t>0) & (cyc MOD (VAL(CARDINAL,t) DIV 3600+1)=0) THEN (* send often to end of time *) IF b THEN Append(s, " TxPastBurst=") ELSE Append(s, " TxOff="); END; hms(t, t<3600, h); Append(s, h); END; END apptxon; PROCEDURE comment(VAR buf:ARRAY OF CHAR; uptime:TIME; sats, txpower:CARDINAL; hrms:LONGREAL; VAR linec:CARDINAL; sdr-:SDRBLOCK; myazi, myele, mydist:REAL); VAR i, bol, eol, lc, len :INTEGER; f :File; fb :ARRAY[0..32767] OF CHAR; h,hb :ARRAY[0..159] OF CHAR; t :TIME; txtimedone :BOOLEAN; BEGIN buf[0]:=0C; len:=0; IF commentfn[0]<>0C THEN f:=OpenRead(commentfn); IF f>=0 THEN len:=RdBin(f, fb, SIZE(fb)-1); Close(f); WHILE (len>0) & (fb[len-1]<=" ") DO DEC(len) END; (* remove junk from eof *) IF (len>0) & (lenLF) DO INC(eol) END; IF eol>=len THEN bol:=eol; IF linec<>0 THEN lc:=1; linec:=0 END; EXIT END; IF fb[bol]<>"#" THEN IF lc=0 THEN INC(linec); EXIT END; DEC(lc); END; INC(eol); END; UNTIL lc=0; txtimedone:=FALSE; hb:=""; WHILE (eol+2>=bol) & (fb[bol]="%") DO IF fb[bol+1]="u" THEN (* insert uptime *) IF uptime>0 THEN Append(hb, " powerup="); hms(uptime, TRUE, h); Append(hb, h); END; ELSIF fb[bol+1]="n" THEN (* insert framenumber *) IF uptime>0 THEN Append(hb, " FN="); IntToStr(uptime, 1, h); Append(hb, h); END; (* ELSIF fb[bol+1]="o" THEN (* remainint tx on time *) apptxon; txtimedone:=TRUE; *) ELSIF fb[bol+1]="v" THEN (* insert version *) Append(hb, " "+VERSION); ELSIF fb[bol+1]="s" THEN (* insert sat count *) IF sats>0 THEN Append(hb, " Sats="); IntToStr(sats, 1, h); Append(hb, h); END; ELSIF fb[bol+1]="t" THEN (* insert sat count *) IF txpower>0 THEN Append(hb, " tx="); IntToStr(txpower, 1, h); Append(hb, h); Append(hb, "dBm"); END; ELSIF fb[bol+1]="r" THEN (* hrms +3m from tropomodel *) IF (sats>4) & (hrms>0.0) THEN Append(hb, " hdil="); FixToStr(hrms+3.0, 2, h); Append(hb, h); Append(hb, "m"); END; (* ELSIF fb[bol+1]="b" THEN IF vBatt>0.0 THEN Append(hb, " batt="); FixToStr(vBatt, 2, h); Append(hb, h); Append(hb, "V"); END; *) ELSIF CAP(fb[bol+1])="F" THEN (* sdr freq and afc *) IF sdr.valid & (NOT mhzfromsonde OR (fb[bol+1]="F")) & (sdr.freq<>0) THEN Append(hb, " rx="); IntToStr(sdr.freq DIV 100, 1, h); Append(hb, h); IF sdr.maxafc<>0 THEN Append(hb, "("); IF sdr.afc>=0 THEN Append(hb, "+") END; IntToStr(sdr.afc, 1, h); Append(hb, h); Append(hb,"/"); IntToStr(sdr.maxafc, 1, h); Append(hb, h); Append(hb,")"); END; END; ELSIF fb[bol+1]="d" THEN (* rssi *) IF sdr.valid & (sdr.db<>0) THEN Append(hb, " rssi="); FixToStr(FLOAT(sdr.db)*0.1, 2, h); Append(hb, h); Append(hb, "dB"); END; ELSIF fb[bol+1]="l" THEN (* label *) IF sdr.valid & (sdr.name[0]<>0C) THEN Append(hb, " dev="); Append(hb, sdr.name); END; ELSIF fb[bol+1]="D" THEN (* distance *) IF mydist>=0.0 THEN Append(hb, " dist="); FixToStr(mydist, 4, h); Append(hb, h) END; ELSIF fb[bol+1]="A" THEN (* azimuth *) IF myazi>=0.0 THEN Append(hb, " azimuth="); IntToStr(VAL(INTEGER,myazi), 1, h); Append(hb, h) END; ELSIF fb[bol+1]="E" THEN (* elevation *) IF myele>-90.0 THEN Append(hb, " elevation="); FixToStr(myele, 3, h); Append(hb, h) END; END; INC(bol, 2); END; Assign(buf, hb); IF (bol" ") THEN Append(buf, " ") END; i:=Length(buf); WHILE (bolNIL DO void:=udpsend(udpsock, buf, len, dest^.port, dest^.ipnum); dest:=dest^.next; END; END sendudp; PROCEDURE sendaprs(comp, micessid:CARDINAL; dao:BOOLEAN; time, uptime:TIME; mycall, destcall, via, sym, obj:ARRAY OF CHAR; lat, long, alt, course, speed:REAL; goodsats, txpower:CARDINAL; vBatt:REAL; hrms:LONGREAL; comm:ARRAY OF CHAR; VAR commentcnt:CARDINAL; sdr-:SDRBLOCK; myazi, myele, mydist:REAL; txtime:INTEGER); PROCEDURE num(n:CARDINAL):CHAR; BEGIN RETURN CHR(n MOD 10 + ORD("0")) END num; PROCEDURE dao91(x:LONGREAL):CARDINAL; (* radix91(xx/1.1) of dddmm.mmxx *) VAR a:LONGREAL; BEGIN a:=ABS(x); RETURN (truncc((a-LFLOAT(truncc(a)))*600000.0) MOD 100*20+11) DIV 22 END dao91; VAR b,h,ds:ARRAY[0..254] OF CHAR; monbuf, raw:ARRAY[0..360] OF CHAR; rp:INTEGER; i,n, nl, micdest:CARDINAL; a:REAL; BEGIN monbuf:=""; Append(monbuf, mycall); micdest:=Length(monbuf)+1; Append(monbuf, ">"); Append(monbuf, destcall); IF micessid>0 THEN Append(monbuf, "-"); Append(monbuf, CHR(micessid+ORD("0"))) END; IF via[0]<>0C THEN Append(monbuf, ","); Append(monbuf, via) END; Append(monbuf, ":"); b:=""; IF comp=0 THEN (* uncompressed *) Append(b, ";"); Assign(h, obj); Append(h, " "); h[9]:=0C; Append(b, h); Append(b, "*"); DateToStr(time, ds); ds[0]:=ds[11]; ds[1]:=ds[12]; ds[2]:=ds[14]; ds[3]:=ds[15]; ds[4]:=ds[17]; ds[5]:=ds[18]; ds[6]:=0C; Append(b, ds); Append(b, "h"); i:=Length(b); a:=ABS(lat); n:=realcard(a); b[i]:=num(n DIV 10); INC(i); b[i]:=num(n); INC(i); n:=realcard((a-FLOAT(n))*6000.0); b[i]:=num(n DIV 1000); INC(i); b[i]:=num(n DIV 100); INC(i); b[i]:="."; INC(i); b[i]:=num(n DIV 10); INC(i); b[i]:=num(n); INC(i); IF lat>=0.0 THEN b[i]:="N" ELSE b[i]:="S" END; INC(i); b[i]:=sym[0]; INC(i); a:=ABS(long); n:=realcard(a); b[i]:=num(n DIV 100); INC(i); b[i]:=num(n DIV 10); INC(i); b[i]:=num(n); INC(i); n:=realcard((a-FLOAT(n))*6000.0); b[i]:=num(n DIV 1000); INC(i); b[i]:=num(n DIV 100); INC(i); b[i]:="."; INC(i); b[i]:=num(n DIV 10); INC(i); b[i]:=num(n); INC(i); IF long>=0.0 THEN b[i]:="E" ELSE b[i]:="W" END; INC(i); b[i]:=sym[1]; INC(i); IF speed>0.5 THEN n:=realcard(course+1.5); b[i]:=num(n DIV 100); INC(i); b[i]:=num(n DIV 10); INC(i); b[i]:=num(n); INC(i); b[i]:="/"; INC(i); n:=realcard(speed*(1.0/KNOTS)+0.5); b[i]:=num(n DIV 100); INC(i); b[i]:=num(n DIV 10); INC(i); b[i]:=num(n); INC(i); END; IF alt>0.5 THEN b[i]:="/"; INC(i); b[i]:="A"; INC(i); b[i]:="="; INC(i); n:=realcard(ABS(alt*FEET+0.5)); IF alt>=0.0 THEN b[i]:=num(n DIV 100000) ELSE b[i]:="-" END; INC(i); b[i]:=num(n DIV 10000); INC(i); b[i]:=num(n DIV 1000); INC(i); b[i]:=num(n DIV 100); INC(i); b[i]:=num(n DIV 10); INC(i); b[i]:=num(n); INC(i); END; ELSIF comp=1 THEN (* compressed *) Append(b, "!"); i:=Length(b); b[i]:=sym[0]; INC(i); IF lat<90.0 THEN n:=realcard((90.0-lat)*380926.0) ELSE n:=0 END; b[i]:=CHR(33+n DIV (91*91*91)); INC(i); b[i]:=CHR(33+n DIV (91*91) MOD 91); INC(i); b[i]:=CHR(33+n DIV 91 MOD 91); INC(i); b[i]:=CHR(33+n MOD 91); INC(i); IF long>-180.0 THEN n:=realcard((180.0+long)*190463.0) ELSE n:=0 END; b[i]:=CHR(33+n DIV (91*91*91)); INC(i); b[i]:=CHR(33+n DIV (91*91) MOD 91); INC(i); b[i]:=CHR(33+n DIV 91 MOD 91); INC(i); b[i]:=CHR(33+n MOD 91); INC(i); b[i]:=sym[1]; INC(i); IF speed>0.5 THEN b[i]:=CHR(33+realcard(course) DIV 4); INC(i); b[i]:=CHR(33+realcard(ln(speed*(1.0/KNOTS)+1.0)*12.9935872129)); INC(i); b[i]:=CHR(33+32+24+6); INC(i); ELSIF alt>0.5 THEN IF alt*FEET>1.0 THEN n:=realcard(ln(alt*FEET)*500.5) ELSE n:=0 END; IF n>=91*91 THEN n:=91*91-1 END; b[i]:=CHR(33+n DIV 91); INC(i); b[i]:=CHR(33+n MOD 91); INC(i); b[i]:=CHR(33+32+16+6); INC(i); ELSE b[i]:=" "; INC(i); b[i]:=" "; INC(i); b[i]:=CHR(33+32+24+6); INC(i); END; IF speed>0.5 THEN b[i]:="/"; INC(i); b[i]:="A"; INC(i); b[i]:="="; INC(i); n:=realcard(alt*FEET+0.5); IF alt>=0.0 THEN b[i]:=num(n DIV 10000) ELSE b[i]:="-" END; INC(i); b[i]:=num(n DIV 10000); INC(i); b[i]:=num(n DIV 1000); INC(i); b[i]:=num(n DIV 100); INC(i); b[i]:=num(n DIV 10); INC(i); b[i]:=num(n); INC(i); END; ELSIF comp=2 THEN (* mic-e *) Append(b, 140C); i:=micdest; nl:=realcard(ABS(long)); n:=realcard(ABS(lat)); b[i]:=CHR(80 + n DIV 10); INC(i); b[i]:=CHR(80 + n MOD 10); INC(i); n:=realcard((ABS(lat)-FLOAT(n))*6000.0); b[i]:=CHR(80 + n DIV 1000); INC(i); b[i]:=CHR(48 + 32*ORD(lat>=0.0) + n DIV 100 MOD 10); INC(i); b[i]:=CHR(48 + 32*ORD((nl<10) OR (nl>=100)) + n DIV 10 MOD 10); INC(i); b[i]:=CHR(48 + 32*ORD(long<0.0) + n MOD 10); i:=Length(b); IF nl<10 THEN b[i]:=CHR(nl+118); ELSIF nl>=100 THEN IF nl<110 THEN b[i]:=CHR(nl+8) ELSE b[i]:=CHR(nl-72) END; ELSE b[i]:=CHR(nl+28) END; INC(i); nl:=realcard((ABS(long)-FLOAT(nl))*6000.0); (* long min*100 *) n:=nl DIV 100; IF n<10 THEN INC(n, 60) END; b[i]:=CHR(n+28); INC(i); b[i]:=CHR(nl MOD 100+28); INC(i); n:=realcard(speed*(1.0/KNOTS)+0.5); b[i]:=CHR(n DIV 10 + 28); INC(i); nl:=realcard(course); b[i]:=CHR(32 + n MOD 10*10 + nl DIV 100); INC(i); b[i]:=CHR(28 + nl MOD 100); INC(i); b[i]:=sym[1]; INC(i); b[i]:=sym[0]; INC(i); IF alt>0.5 THEN IF alt>-10000.0 THEN n:=realcard(alt+10000.5) ELSE n:=0 END; b[i]:=CHR(33 + n DIV (91*91) MOD 91); INC(i); b[i]:=CHR(33 + n DIV 91 MOD 91); INC(i); b[i]:=CHR(33 + n MOD 91); INC(i); b[i]:="}"; INC(i); END; END; IF dao THEN b[i]:="!"; INC(i); b[i]:="w"; INC(i); b[i]:=CHR(33 + dao91(lat)); INC(i); b[i]:=CHR(33 + dao91(long)); INC(i); b[i]:="!"; INC(i); END; b[i]:=0C; Append(b, comm); (* position + measurements *) comment(h, uptime, goodsats, txpower, hrms, commentcnt, sdr, myazi, myele, mydist); Append(b, h); (* position + measurements + usercomments *) IF HIGH(b)>=255 THEN b[255]:=0C END; (* limit to fit in pr *) Append(monbuf, b); (* pr-calls + position + measurements + usercomments *) -- Append(b, CR+LF); IF Length(mycall)>=3 THEN IF NOT sendmon THEN mon2raw(monbuf, raw, rp); IF rp>0 THEN sendudp(raw, rp) END; ELSE sendudp(b, Length(b)+1) END; END; IF verb THEN WrStrLn(monbuf) END; END sendaprs; PROCEDURE degtostr(d:REAL; lat:BOOLEAN; form:CHAR; VAR s:ARRAY OF CHAR); CONST Z=ORD("0"); VAR n,i:CARDINAL; BEGIN IF HIGH(s)<11 THEN s[0]:=0C; RETURN END; IF form="2" THEN i:=7 ELSIF form="3" THEN i:=8 ELSE i:=9 END; IF d<0.0 THEN d:=-d; IF lat THEN s[i]:="S" ELSE s[i+1]:="W" END; ELSIF lat THEN s[i]:="N" ELSE s[i+1]:="E" END; IF form="2" THEN (* DDMM.MMNDDMM.MME *) n:=realcard(d*(6000*180/PI)+0.5); s[0]:=CHR(n DIV 600000 MOD 10+Z); i:=ORD(NOT lat); s[i]:=CHR(n DIV 60000 MOD 10+Z); INC(i); s[i]:=CHR(n DIV 6000 MOD 10+Z); INC(i); s[i]:=CHR(n DIV 1000 MOD 6+Z); INC(i); s[i]:=CHR(n DIV 100 MOD 10+Z); INC(i); s[i]:="."; INC(i); s[i]:=CHR(n DIV 10 MOD 10+Z); INC(i); s[i]:=CHR(n MOD 10+Z); INC(i); ELSIF form="3" THEN (* DDMM.MMMNDDMM.MMME *) n:=realcard(d*(60000*180/PI)+0.5); s[0]:=CHR(n DIV 6000000 MOD 10+Z); i:=ORD(NOT lat); s[i]:=CHR(n DIV 600000 MOD 10+Z); INC(i); s[i]:=CHR(n DIV 60000 MOD 10+Z); INC(i); s[i]:=CHR(n DIV 10000 MOD 6+Z); INC(i); s[i]:=CHR(n DIV 1000 MOD 10+Z); INC(i); s[i]:="."; INC(i); s[i]:=CHR(n DIV 100 MOD 10+Z); INC(i); s[i]:=CHR(n DIV 10 MOD 10+Z); INC(i); s[i]:=CHR(n MOD 10+Z); INC(i); ELSE (* DDMMSS *) n:=realcard(d*(60*60*180/PI)+0.5); s[0]:=CHR(n DIV (60*6000) MOD 10+Z); i:=ORD(NOT lat); s[i]:=CHR(n DIV (60*600) MOD 10+Z); INC(i); s[i]:=CHR(n DIV (60*60) MOD 10+Z); INC(i); s[i]:="o"; INC(i); s[i]:=CHR(n DIV 600 MOD 6+Z); INC(i); s[i]:=CHR(n DIV 60 MOD 10+Z); INC(i); s[i]:="'"; INC(i); s[i]:=CHR(n DIV 10 MOD 6+Z); INC(i); s[i]:=CHR(n MOD 10+Z); INC(i); s[i]:='"'; INC(i); END; INC(i); s[i]:=0C; END degtostr; PROCEDURE postostr(pos:POSITION; form:CHAR; VAR s:ARRAY OF CHAR); VAR h:ARRAY[0..31] OF CHAR; BEGIN degtostr(pos.lat, TRUE, form, s); Append(s,"/"); degtostr(pos.long, FALSE, form, h); Append(s, h); END postostr; PROCEDURE WrDeg(la, lo:REAL); CONST RAD=PI/180.0; VAR s:ARRAY[0..30] OF CHAR; pos:POSITION; BEGIN pos.lat:=la*RAD; pos.long:=lo*RAD; postostr(pos, "2", s); WrStr(s); END WrDeg; PROCEDURE show(d:DATLINE); VAR s:ARRAY[0..30] OF CHAR; BEGIN IF (d.hpa>0.0) & (d.hpa<1500.0) THEN WrFixed(d.hpa, 2, 6);WrStr("hPa ") END; IF d.temp<100.0 THEN WrFixed(d.temp, 1, 5);WrStr("C ") END; IF d.hyg<=100.0 THEN WrInt(realcard(d.hyg), 2);WrStr("% ") END; WrInt(realcard(d.speed*3.6), 3);WrStr("km/h "); WrInt(realcard(d.dir), 3);WrStr("dir "); WrDeg(d.lat, d.long); WrStr(" "); --WrFixed(d.gpsalt, 1, 8); WrStr("m "); IF (d.alt>=-20000) & (d.alt<=100000) THEN WrInt(realint(d.alt), 1);WrStr("m ") END; IF d.clb<1000.0 THEN WrFixed(d.clb, 1, 5);WrStr("m/s ") END; TimeToStr(d.time, s); WrStr(s); END show; PROCEDURE Checkval(a-:ARRAY OF REAL; t-:ARRAY OF TIME; err, min, max, unitspers:REAL):BOOLEAN; VAR i:CARDINAL; k, m, y:REAL; BEGIN FOR i:=0 TO HIGH(a) DO IF (a[i]max) THEN RETURN FALSE END; (* >=1 value out of range *) IF (i>0) & (t[i]t[0] THEN y:=(a[i]-a[0])/FLOAT(t[i]-t[0]); IF ABS(y)>unitspers THEN RETURN FALSE END; k:=k + y; (* median slope *) END; END; k:=k/FLOAT(HIGH(a)); m:=0.0; FOR i:=1 TO HIGH(a) DO IF t[i]>t[0] THEN y:=ABS((a[i]-a[0])-FLOAT(t[i]-t[0])*k); IF y>m THEN m:=y END; (* max deviation from median slope *) END; END; -- k:=ABS(k); -- IF kMAXHRMS THEN INCL(e, eRMS) END; IF d[i].vrms>MAXVRMS THEN INCL(e, eRMS) END; IF (d[i].lat=0.0) & (d[i].long=0.0) THEN INCL(e, eRMS) END; END; (* FOR i:=0 TO n DO IF (i>0) & (ta<>(d[i].time+1) MOD (3600*24)) THEN INCL(e, eMISS) END; ta:=d[i].time; END; *) IF (d[0].time+3600*24-d[n].time) MOD (3600*24)>MAXTIMESPAN THEN INCL(e, eMISS) END; END Checkvals; PROCEDURE shift(VAR d:DATS); VAR i:CARDINAL; BEGIN FOR i:=HIGH(d) TO 1 BY -1 DO d[i]:=d[i-1] END; END shift; PROCEDURE findcontext(n:ARRAY OF CHAR; t:TIME):pCONTEXT; VAR c,p:pCONTEXT; BEGIN c:=contexts; WHILE (c<>NIL) & NOT StrCmp(c^.name, n) DO c:=c^.next END; IF c=NIL THEN c:=contexts; WHILE (c<>NIL) & (c^.lastused+MAXAGE>t) DO c:=c^.next END; IF c=NIL THEN ALLOCATE(c, SIZE(c^)); FILL(c, 0C, SIZE(c^)); c^.next:=contexts; contexts:=c; ELSE (* reuse old context *) p:=c^.next; FILL(c, 0C, SIZE(c^)); c^.next:=p; END; Assign(c^.name, n); END; IF c<>NIL THEN c^.lastused:=t END; RETURN c END findcontext; PROCEDURE elevation(VAR el, c:LONGREAL; home:aprsstr.POSITION; homealt:LONGREAL; dist:aprsstr.POSITION; distalt:LONGREAL); VAR x0,y0,z0, x1,y1,z1:SHORTREAL; a,b,s,r,sb:LONGREAL; BEGIN el:=-1000.0; wgs84s(home.lat, home.long, homealt*0.001, x0,y0,z0); wgs84s(dist.lat, dist.long, distalt*0.001, x1,y1,z1); a:=math.sqrt(x0*x0 + y0*y0 + z0*z0); b:=math.sqrt(x1*x1 + y1*y1 + z1*z1); x1:=x1-x0; y1:=y1-y0; z1:=z1-z0; c:=math.sqrt(x1*x1 + y1*y1 + z1*z1); (* halbwinkelsatz *) s:=(a+b+c)*0.5; IF s=0.0 THEN RETURN END; r:=(s-a)*(s-b)*(s-c)/s; IF r<=0.0 THEN RETURN END; r:=math.sqrt(r); sb:=s-b; IF sb<>0.0 THEN el:=(360.0/PI)*math.atan(r/sb)-90.0 ELSE el:=90.0 END; END elevation; PROCEDURE typisser(fullid-, typstr-:ARRAY OF CHAR):BOOLEAN; (* serial nr starts with type name *) VAR i:CARDINAL; BEGIN i:=0; LOOP IF (fullid[i]=0C) OR (fullid[i]<>typstr[i]) THEN RETURN FALSE END; INC(i); IF (i>HIGH(typstr)) OR (typstr[i]=0C) THEN RETURN TRUE END; IF i>HIGH(fullid) THEN RETURN FALSE END; END; END typisser; PROCEDURE infence(lat, long:REAL):BOOLEAN; (* true if pos in a rectangle or out if swapped margins *) VAR d, u:BOOLEAN; BEGIN WITH rectfence DO d:=lat>leftdown.lat; u:=latleftdown.long; u:=long-1000.0 THEN og:=getoverground(lat, long, altNN, attr); IF og>=0.0 THEN btalt:=og END; IF attr=ATTRWATER THEN ogwhat:="Water"; ELSIF attr=ATTRWOOD THEN ogwhat:="Wood"; ELSIF attr=ATTRURBAN THEN ogwhat:="Urban"; END; ELSIF ABS(altNN-alt)>250.0 THEN WrFixed(altNN-alt,2,1); WrStrLn("m egm96 correction? check file WW15MGH.DAC") END; END; --- azimuth elevation distance myazi:=-20000.0; myele:=-20000.0; mydist:=-20000.0; mygrounddist:=0.0; dpos.lat:=lat; dpos.long:=long; IF posvalid(mypos) & posvalid(dpos) THEN IF myalt<-200000.0 THEN (* try to get own alt from srtm *) myalt:=getoverground(mypos.lat, mypos.long, -100000.0, attr); IF verb & (myalt>-20000.0) & (myalt<20000.0) THEN WrStrLn(""); WrStr("got Your altitude from SRTM as "); WrInt(VAL(INTEGER, myalt),1); WrStrLn("m or overwrite with -N"); END; END; myazi:=azimuth(mypos,dpos); mygrounddist:=distance(mypos,dpos); IF mygrounddist>20000000.0 THEN mygrounddist:=20000000.0 END; IF (altNN>=-20000.0) & (myalt>=-20000.0) & (myalt<=20000.0) THEN elevation(myele, mydist, mypos, myalt, dpos, altNN) END; END; --- azimuth elevation distance IF (csvfilename[0]<>0C) OR json THEN wrcsv(sattime, typstr, objname, lat, long, alt, speed, dir, clb, altNN, og, mhz, goodsats, uptime, hp, hyg, temp, ozon, otemp, pumpmA, pumpv, sdr, mydist, myazi, myele, fullid, txpower, vBatt, txtime, psatsig, usercall, leapsecs, xdata, ogwhat); END; IF Length(usercall)<3 THEN WrStrLn("no tx without "); RETURN END; IF Length(objname)<3 THEN WrStrLn("no tx witout "); RETURN END; systime:=time(); mhzfromsonde:=FALSE; ct:=findcontext(objname, systime); IF ct<>NIL THEN WITH ct^ DO shift(dat); speedsum:=speedsum+speed; INC(speedcnt); dat[0].hpa:=hp; dat[0].temp:=temp; dat[0].hyg:=hyg; dat[0].alt:=alt; dat[0].speed:=speedsum/LFLOAT(speedcnt); dat[0].dir:=dir; dat[0].lat:=lat*(1.0/RAD); dat[0].long:=long*(1.0/RAD); IF sattime>=DAYSEC THEN dat[0].time:=sattime MOD DAYSEC; ELSE dat[0].time:=time() MOD DAYSEC END; dat[0].clb:=clb; dat[0].hrms:=hrms; dat[0].vrms:=vrms; -- climb(dat); Checkvals(dat, chk); -- IF (hrms>MAXHRMS) OR (vrms>MAXVRMS) THEN INCL(chk, eRMS) END; IF verb THEN -- WrStrLn(""); show(dat[0]); IF almanachage<>0 THEN WrStr(" AlmAge "); WrFixed(VAL(REAL, almanachage)/3600.0, 1,3); WrStrLn("h "); ELSE WrStrLn("") END; FOR e:=MIN(ERRS) TO MAX(ERRS) DO IF e IN chk THEN CASE e OF -- ePRES : WrStr("p"); -- |eTEMP : WrStr("t"); -- |eHYG : WrStr("h"); eSPEED: WrStr("v"); |eDIR : WrStr("d"); |eLAT : WrStr("y"); |eLONG : WrStr("x"); |eALT : WrStr("a"); |eMISS : WrStr("s"); |eRMS : WrStr("r"); (*WrFixed(vrms, 1,5); WrStr(" "); WrFixed(hrms, 1,5);*) ELSE END; END; END; END; bt:=beacontimes[0].beacontime; IF (clb<-0.4) & (btalt>0.0) THEN (* fast beacon only on minimum downward speed *) nt:=0; WHILE (nt0) & (lastbeacon+bt<=systime) & (nofilter OR (chk*ERRSET{eLAT,eLONG,eALT,eMISS,eRMS}=ERRSET{})) THEN s:=""; IF clb<1000.0 THEN Append(s, "Clb="); FixToStr((*dat[0].climb*)clb, 2, h); Append(s, h); Append(s, "m/s"); END; IF NOT (ePRES IN chk) & (dat[0].hpa>=1.0) THEN Append(s, " p="); FixToStr(dat[0].hpa, 2, h); Append(s, h); Append(s, "hPa"); ELSIF fakehp>=1.0 THEN Append(s, " fp="); FixToStr(fakehp, 2, h); Append(s, h); Append(s, "hPa"); END; IF NOT (eTEMP IN chk) THEN Append(s, " t="); FixToStr(dat[0].temp, 2, h); Append(s, h); Append(s, "C"); END; IF (dat[0].hyg>=0.1) & (dat[0].hyg<=100.0) & NOT (eHYG IN chk) THEN Append(s, " h="); FixToStr(dat[0].hyg, 2, h); Append(s, h); Append(s, "%"); END; IF ozon>0.1 THEN Append(s, " o3="); FixToStr(ozon, 2, h); Append(s, h); Append(s, "mPa ti="); FixToStr(otemp, 2, h); Append(s, h); Append(s, "C"); IF pumpmA>0.1 THEN Append(s, " Pump="); IntToStr(truncc(pumpmA), 1, h); Append(s, h); Append(s, "mA"); END; IF pumpv>0.1 THEN Append(s, " "); FixToStr(pumpv, 2, h); Append(s, h); Append(s, "V"); END; END; (* IF (dewp>-100.0) & (dewp<100.0) THEN Append(s, " dp="); FixToStr(dewp, 2, h); Append(s, h); Append(s, "C"); END; *) IF (calperc>0) & (calperc<100) THEN Append(s, " calibration "); IntToStr(calperc, 1, h); Append(s, h); Append(s, "%"); END; IF mhz>0.0 THEN Append(s, " "); FixToStr(mhz, 3, h); Append(s, h); Append(s, "MHz"); mhzfromsonde:=TRUE; (* mhz sent so do not with %f *) ELSIF (mhz<0.0) & sdr.valid & (sdr.freq<>0) THEN Append(s, " "); FixToStr(FLOAT(VAL(INTEGER, sdr.freq DIV 100)+sdr.afc)*0.001, 4, h); Append(s, h); Append(s, "MHz"); mhzfromsonde:=TRUE; (* mhz sent so do not with %f *) END; IF typstr[0]<>0C THEN Append(s, " Type="); IF typisser(fullid, typstr) THEN Append(s, fullid) ELSE Append(s, typstr) END; END; apptxon(txtime, cyclevals, s); (* remaining tx time *) IF (vBatt>0.0) & (cyclevals MOD 3=0) THEN Append(s, " batt="); FixToStr(vBatt, 2, h); Append(s, h); Append(s, "V"); END; IF (og>=0.0) & (og<=VAL(LONGREAL, beacontimes[1].below)) THEN Append(s, " OG="); IntToStr(VAL(INTEGER, og), 1, h); Append(s, h); Append(s, "m"); IF (og<=200.0) & (ogwhat[0]<>0C) THEN Append(s, "("); Append(s, ogwhat); Append(s, ")"); END; END; IF (fullid[0]<>0C) & NOT typisser(fullid, typstr) THEN Append(s, " ser="); Append(s, fullid) END; IF force THEN Append(s, " Unchecked-Data") END; IF (expire>0) & ((systime>sattime+expire) OR (systime+expire0) & (VAL(REAL, maxsenddistance)0.0) & NOT infence(dat[0].lat, dat[0].long) THEN IF verb THEN WrStrLn("---------- NO SEND (Out of Rectangle -"+minusa+" ... )"); END; ELSE sendaprs(0, 0, dao, dat[0].time, uptime, usercall, destcall, via, sym, objname, dat[0].lat, dat[0].long, dat[0].alt, FLOAT(truncc(dat[0].dir) MOD 360), dat[0].speed*3.6, goodsats, txpower, vBatt, hrms, s, commentline, sdr, myazi, myele, mydist, txtime); INC(cyclevals); END; lastbeacon:=systime; speedcnt:=0; speedsum:=0.0; END; END; END; END senddata; BEGIN contexts:=NIL; udpsock:=-1; commentfn[0]:=0C; csvfilename[0]:=0C; destcall:="APLWS2"; via[0]:=0C; sym:="/O"; objname[0]:=0C; nofilter:=FALSE; egmoff:=FALSE; jsonfd:=-1; -- FILL(ADR(dat), 0C, SIZE(dat)); -- lastbeacon:=0; -- commentline:=0; -- speedcnt:=0; -- speedsum:=0.0; END sondeaprs.