<*+M2EXTENSIONS *> <*-CHECKDIV *> <*-CHECKRANGE *> <*-COVERFLOW *> <*-IOVERFLOW*> <*+NOPTRALIAS*> <*CPU="PENTIUM"*> <*COMPILERHEAP="100000000"*> <*-CHECKNIL *> <*-DOREORDER*> <*-CHECKINDEX*> <*-CHECKSET*> <* IF __GEN_C__ THEN *> <*+COMMENT*> <*-GENCTYPES*> <*-GENDEBUG*> <*-LINENO*> <*-GENHISTORY*> <*-GENDATE*> <*+NOHEADER*> <*+GENCDIV*> <*-GENKRC*> <*+NOOPTIMIZE*> <*-GENSIZE*> <*-ASSERT*> <*GENWIDTH="240"*> <* ELSE *> <*-PROCINLINE*> <*-GENDEBUG*> <*-LINENO*> <*-GENHISTORY*> <* END *> MODULE gps2aprs; (* read serial gps and make axudp aprs frames *) FROM SYSTEM IMPORT ADR, CARD8, CARD16, SHIFT, CAST, FILL; <* IF TARGET_FAMILY="WIN32" THEN *> FROM Windows IMPORT CreateFile, GENERIC_READ, GENERIC_WRITE, Sleep, FILE_SHARE_READ, OPEN_EXISTING, HANDLE, ReadFile, DWORD, CloseHandle, FILE_ATTRIBUTE_NORMAL, COMMTIMEOUTS, SetCommTimeouts, DCB, GetCommState, SetCommState, PARITY_TYPE, DCB_FLAG, DCB_FLAGS; FROM osi IMPORT STDIO, NextArg, OpenWrite, InvalidFd, FdValid, WrCard, ALLOCATE, settime; <* ELSE *> IMPORT udp; FROM osi IMPORT OpenRW, OpenWrite, NextArg, usleep, InvalidFd, FdValid, WrInt, WrCard, ALLOCATE, setttybaudraw, settime; (* FROM mlib IMPORT termios, tcgetattr, tcsetattr, CS8, CLOCAL, CREAD, TCSAFLUSH, B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800; *) FROM Select IMPORT fdclr, fdsetr, issetr, selectr; FROM signal IMPORT signal, SIGTERM, SIGINT, SIGPIPE, sighandler_t; <* END *> FROM osi IMPORT File, WrLn, WrStr, WrStrLn, OpenRead, OpenAppend, WrBin, RdBin, Close, openudp, udpsend, WrFixed, time, ln, pi, exp, sin, cos, arctan, sqrt, WrHex; FROM aprsstr IMPORT IPNUM, UDPPORT, Append, mon2raw, Length, DateToStr, StrToTime, Assign, StrToInt, IntToStr, FixToStr, TimeToStr; TYPE SET16=SET OF [0..15]; SET8 =SET OF [0..7]; SAT=RECORD id, az, el, db:CARDINAL; END; POS=RECORD daytime, year, month, day, date, altok, sats, fix:CARDINAL; lat, long, speed, course, alt, climb:LONGREAL; vx, vy, vz:LONGREAL; posok, speedok, dateok:BOOLEAN; leapseconds:INTEGER; timeflags:CARD8; satcnt, lastsat:CARDINAL; satpos:ARRAY[0..15] OF SAT; END; pUDPDESTS=POINTER TO UDPDESTS; UDPDESTS=RECORD next:pUDPDESTS; ipnum:IPNUM; toport:UDPPORT; useaxudp:BOOLEAN; END; <* IF TARGET_FAMILY="WIN32" THEN *> CONST DEFTTY="com1"; <* ELSE *> CONST DEFTTY="/dev/ttyS0"; <* END *> CONST CR=15C; LF=12C; PI=3.1415926535; KNOTS=1.851984; FEET=1.0/0.3048; DEFAULTPORT=9002; DEFAULTIP=7F000001H; (* 127.0.0.1 *) BTIMENAVI=2; (* fast beacon to aprsmap as navi -N *) ALTLIFE=10; (* seconds altitude valid *) SETNMEA=ARRAY OF CARD8 {6,0,1, 0,0,0, 0D0H,8,0,0, 0,0,0,0, 3,0, 2,0, 0,0, 0,0}; INITBAUD=ARRAY OF CARD8 {6,0,1, 0,0,0, 0D0H,8,0,0, 0,0,0,0, 1,0, 1,0, 0,0, 0,0}; (* port com mode baud in outproto *) TYPE pCONF=POINTER TO CONF; CONF=RECORD next:pCONF; str:ARRAY[0..250] OF CHAR; END; VAR (*CRCL, CRCH: ARRAY[0..255] OF SET8;*) tbuf, ttynamee, logfilename:ARRAY[0..1023] OF CHAR; mycall, via, viaakt, comment:ARRAY[0..99] OF CHAR; symt, symb:CHAR; baud:CARDINAL; timecorr, timepuls, udpsock:INTEGER; verb, verb2, anyip, usbrobust, junk, sumoff, withalti, withspeed, withdao, balloon, ubloxraw:BOOLEAN; comptyp, micessid, btime0, btimedrive, drivekm, comintval, comcnt, btime, msgtyp, btimeN, btimenavi, frames, dynamicmodel, fixalt, fixmode, sumerrcnt, rawframeerr, duration, meshcom4hops:CARDINAL; timesetdone, terminatetimeset:BOOLEAN; pos:POS; gpsp:CARDINAL; gpsb:ARRAY[0..250] OF CHAR; Logl:ARRAY[0..250] OF CHAR; pconfig:pCONF; udpdests2, udpdests:pUDPDESTS; rndseed:LONGREAL; <* IF TARGET_FAMILY="WIN32" THEN *> tty:HANDLE; dlen:DWORD; void:BOOLEAN; <* ELSE *> tty:INTEGER; -- saved: termios; <* END *> (* <* IF TARGET_FAMILY="WIN32" THEN *> <* ELSE *> PROCEDURE ["C"] / stime(VAR time:CARDINAL):INTEGER; (* set system time, needs root *) <* END *> *) PROCEDURE Error(text:ARRAY OF CHAR); BEGIN WrStr("aprstracker: "); WrStr(text); WrStrLn(" error abort"); HALT END Error; PROCEDURE truncc(r:LONGREAL):CARDINAL; BEGIN IF r<=0.0 THEN RETURN 0 ELSIF r>=MAX(INTEGER) THEN RETURN MAX(INTEGER) ELSE RETURN TRUNC(r) END; END truncc; (* PROCEDURE rnd():CARDINAL; VAR fd:INTEGER; n:CARDINAL; BEGIN fd:=OpenRead("/dev/random"); n:=0; IF fd>=0 THEN RdBin(fd, n, 4); Close(fd); END; END rnd; *) PROCEDURE hex(n:CARDINAL; cap:BOOLEAN):CHAR; BEGIN n:=n MOD 16; IF n<=9 THEN RETURN CHR(n+ORD("0")) END; IF cap THEN RETURN CHR(n+(ORD("A")-10)) END; RETURN CHR(n+(ORD("a")-10)) END hex; PROCEDURE ChHex(c:CHAR; VAR s:ARRAY OF CHAR); BEGIN IF (c>=177C) OR (c<" ") THEN s[0]:="["; s[1]:=hex(ORD(c) DIV 16, FALSE); s[2]:=hex(ORD(c), FALSE); s[3]:="]"; s[4]:=0C; ELSE s[0]:=c; s[1]:=0C; END; END ChHex; PROCEDURE WrChHex(c:CHAR); VAR s:ARRAY[0..10] OF CHAR; BEGIN ChHex(c, s); WrStr(s); END WrChHex; PROCEDURE Random():CARDINAL; BEGIN rndseed:=rndseed + PI; rndseed:=rndseed*rndseed; rndseed:=rndseed*rndseed; rndseed:=rndseed*rndseed; rndseed:=rndseed - LFLOAT(TRUNC(rndseed)); RETURN TRUNC(rndseed*LFLOAT(MAX(CARDINAL))) END Random; PROCEDURE GetIp(h:ARRAY OF CHAR; VAR p:CARDINAL; VAR ip:CARDINAL; VAR port:CARDINAL):INTEGER; CONST DEFAULTIP=7F000001H; PORTSEP=":"; VAR i, n:CARDINAL; ok:BOOLEAN; BEGIN p:=0; h[HIGH(h)]:=0C; ip:=0; FOR i:=0 TO 4 DO IF (i>=3) OR (h[0]<>PORTSEP) THEN 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; END; IF i<3 THEN IF h[0]<>PORTSEP THEN IF (h[p]<>".") OR (n>255) THEN RETURN -1 END; ip:=ip*256+n; END; ELSIF i=3 THEN IF h[0]<>PORTSEP THEN ip:=ip*256+n; IF (h[p]<>PORTSEP) OR (n>255) THEN RETURN -1 END; ELSE p:=0; ip:=DEFAULTIP END; ELSIF n>65535 THEN RETURN -1 END; port:=n; INC(p); END; RETURN 0 END GetIp; <* IF TARGET_FAMILY="WIN32" THEN *> --PROCEDURE WrFixed(x:REAL; place:INTEGER; witdh:CARDINAL); --BEGIN WriteReal(x, place) END WrFixed; PROCEDURE opentty; VAR CommTimeouts: COMMTIMEOUTS; dcb:DCB; BEGIN -- tty:=CreateFile(ttyname,); -- tty:=Create(ttyname); tty:=CreateFile(ttynamee, GENERIC_READ+GENERIC_WRITE, FILE_SHARE_READ, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NIL); IF tty<>NIL THEN IF GetCommState(tty, dcb) THEN -- WrInt(dcb.BaudRate, 10); WrStrLn(" baud"); -- WrInt(dcb.ByteSize, 10); WrStrLn(" bits"); -- WrInt(CAST(CARDINAL, dcb.Flags), 10); WrStrLn(" flags"); dcb.Parity:=NOPARITY; dcb.ByteSize:=8; dcb.BaudRate:=baud; dcb.Flags:=DCB_FLAGS{DCB_fBinary, DCB_fDtrControl_1, DCB_fRtsControl_1}; void:=SetCommState(tty, dcb); -- IF GetCommTimeouts (tty, CommTimeouts) THEN FILL(ADR(CommTimeouts), 0C, SIZE(CommTimeouts)); CommTimeouts.ReadIntervalTimeout:=MAX(DWORD); void:=SetCommTimeouts(tty, CommTimeouts); ELSIF NOT usbrobust THEN Error("com config") ELSIF verb THEN WrStrLn("com config error") END; ELSIF NOT usbrobust THEN Error("com open error") ELSIF verb THEN WrStrLn("com open error") END; END opentty; <* ELSE *> PROCEDURE SetComMode(fd:INTEGER; baud:CARDINAL); VAR -- term : termios; res : INTEGER; -- bd : INTEGER; BEGIN IF setttybaudraw(fd, baud)<0 THEN IF verb THEN WrStrLn("cannot config tty") END; END; (* IF baud=1200 THEN bd:=B1200; ELSIF baud=2400 THEN bd:=B2400; ELSIF baud=4800 THEN bd:=B4800; ELSIF baud=9600 THEN bd:=B9600; ELSIF baud=19200 THEN bd:=B19200; ELSIF baud=38400 THEN bd:=B38400; ELSIF baud=57600 THEN bd:=B57600; ELSIF baud=115200 THEN bd:=B115200; ELSIF baud=230400 THEN bd:=B230400; ELSIF baud=460800 THEN bd:=B460800; ELSE Error("unknown baudrate") END; res:=tcgetattr(fd, saved); res:=tcgetattr (fd, term); WITH term DO c_lflag :=0; c_oflag :=0; c_iflag :=0; (* cfmakeraw(&termios);*) c_cflag :=CS8+CLOCAL+CREAD(*+CRTSCTS*)+bd; (*0800018B2H*) END; res:=tcsetattr (fd, TCSAFLUSH, term); *) END SetComMode; PROCEDURE opentty; BEGIN LOOP tty:=OpenRW(ttynamee); IF tty>=0 THEN SetComMode(tty, baud); EXIT ELSIF NOT usbrobust THEN Error("tty open") ELSIF verb THEN WrStrLn("tty open error") END; usleep(1000000); END; END opentty; <* END *> PROCEDURE testtty(len:INTEGER; VAR err:BOOLEAN); <* IF TARGET_FAMILY="WIN32" THEN *> VAR dcb:DCB; BEGIN IF NOT GetCommState(tty, dcb) THEN CloseHandle(tty); Sleep(1000); opentty; IF verb THEN WrStrLn("tty reopen") END; err:=TRUE; END; <* ELSE *> BEGIN IF len<=0 THEN Close(tty); usleep(1000000); opentty; err:=TRUE; END; <* END *> END testtty; PROCEDURE GetNum(h-:ARRAY OF CHAR; eot:CHAR; VAR p,n:CARDINAL):BOOLEAN; BEGIN n:=0; WHILE (h[p]>="0") & (h[p]<="9") DO n:=n*10+ORD(h[p])-ORD("0"); INC(p); END; RETURN h[p]=eot END GetNum; PROCEDURE GetInt(h-:ARRAY OF CHAR; eot:CHAR; VAR p:CARDINAL; VAR n:INTEGER):BOOLEAN; VAR s:BOOLEAN; BEGIN n:=0; s:=FALSE; IF h[p]="-" THEN s:=TRUE; INC(p) END; WHILE (h[p]>="0") & (h[p]<="9") DO n:=n*10+VAL(INTEGER, ORD(h[p])-ORD("0")); INC(p); END; IF s THEN n:=-n END; RETURN h[p]=eot END GetInt; PROCEDURE Parms; VAR err:BOOLEAN; h:ARRAY[0..1023] OF CHAR; VAR i:CARDINAL; pc, pch:pCONF; udest:pUDPDESTS; BEGIN err:=FALSE; LOOP NextArg(h); IF h[0]=0C THEN EXIT END; IF (h[0]="-") & (h[1]<>0C) & (h[2]=0C) THEN IF (h[1]="m") OR (h[1]="r") THEN ALLOCATE(udest, SIZE(udest^)); IF udest=NIL THEN Error("out of memory") END; udest^.useaxudp:=(h[1]="r"); udest^.next:=udpdests; udpdests:=udest; NextArg(h); i:=0; IF GetIp(h, i, udest^.ipnum, udest^.toport)<0 THEN Error("-m or -r ip:port number") END; IF udpsock<0 THEN udpsock:=openudp(); IF udpsock<0 THEN Error("cannot open udp socket") END; END; ELSIF h[1]="N" THEN ALLOCATE(udest, SIZE(udest^)); IF udest=NIL THEN Error("out of memory") END; udest^.useaxudp:=TRUE; udest^.next:=udpdests2; udpdests2:=udest; NextArg(h); i:=0; IF GetIp(h, i, udest^.ipnum, udest^.toport)<0 THEN Error("-N ip:port") END; IF udpsock<0 THEN udpsock:=openudp(); IF udpsock<0 THEN Error("cannot open udp socket") END; END; ELSIF h[1]="a" THEN withalti:=FALSE ELSIF h[1]="u" THEN usbrobust:=FALSE ELSIF h[1]="k" THEN withspeed:=FALSE ELSIF h[1]="s" THEN sumoff:=TRUE ELSIF h[1]="D" THEN withdao:=TRUE; ELSIF h[1]="B" THEN balloon:=TRUE; ELSIF h[1]="U" THEN ubloxraw:=TRUE; ELSIF CAP(h[1])="Z" THEN timesetdone:=FALSE; IF h[1]="Z" THEN terminatetimeset:=TRUE END; NextArg(h); IF NOT StrToInt(h, timecorr) THEN Error("-Z ") END; ELSIF h[1]="I" THEN NextArg(mycall); IF mycall[0]<"0" THEN Error("-I ") END; ELSIF h[1]="w" THEN NextArg(via); IF via[0]<=" " THEN Error("-m vias like RELAY,WIDE1-1") END; ELSIF h[1]="c" THEN NextArg(comment); IF Length(comment)>60 THEN Error("-c (max 60 byte)") END; ELSIF h[1]="C" THEN NextArg(h); IF h[0]="-" THEN Error("-C ") END; ALLOCATE(pc, SIZE(pc^)); IF pc=NIL THEN Error("-C out of memory>") END; pc^.next:=NIL; Assign(pc^.str, h); IF pconfig<>NIL THEN pch:=pconfig; WHILE pch^.next<>NIL DO pch:=pch^.next END; pch^.next:=pc; ELSE pconfig:=pc END; ELSIF h[1]="i" THEN NextArg(h); IF (h[0]>" ") & (h[1]>" ") THEN symt:=h[0]; symb:=h[1]; ELSE Error("-i (house /-)") END; ELSIF h[1]="t" THEN NextArg(h); i:=0; WHILE (h[i]<>0C) & (h[i]<>":") & (i0C THEN INC(i); IF NOT GetNum(h, 0C, i, baud) THEN Error("need ttydevice:baud") END; END; ELSIF h[1]="L" THEN NextArg(logfilename); ELSIF h[1]="b" THEN NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, btimedrive) THEN Error("-b ") END; ELSIF h[1]="n" THEN NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, btimenavi) THEN Error("-n ") END; ELSIF h[1]="0" THEN NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, btime0) THEN Error("-0 ") END; ELSIF h[1]="g" THEN NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, drivekm) THEN Error("-g ") END; ELSIF h[1]="A" THEN NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, fixalt) THEN Error("-A ") END; NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, fixmode) THEN Error("-A ") END; ELSIF h[1]="T" THEN NextArg(h); i:=0; IF NOT GetInt(h, 0C, i, timepuls) THEN Error("-T ") END; NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, duration) THEN Error("-T ") END; ELSIF h[1]="M" THEN NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, dynamicmodel) THEN Error("-M ") END; ELSIF h[1]="l" THEN NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, comintval) THEN Error("-l ") END; ELSIF h[1]="f" THEN NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, comptyp) OR (comptyp>2) THEN Error("-f 0=uncomp, 1=comp, 2=mic-e") END; ELSIF h[1]="d" THEN NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, micessid) OR (micessid>7) THEN Error("-d 0..7") END; ELSIF h[1]="4" THEN NextArg(h); i:=0; IF NOT GetNum(h, 0C, i, meshcom4hops) OR (meshcom4hops>7) THEN Error("-4 0..7") END; ELSIF h[1]="v" THEN verb:=TRUE; ELSIF h[1]="V" THEN verb:=TRUE; verb2:=TRUE; ELSIF h[1]="h" THEN WrLn; WrStrLn("Read serial GPS and make normal/compressed/mic-e Beacon as AXUDP or monitor"); WrStrLn(" -0 standing Beacon Time in Seconds (180)"); WrStrLn(" -4 enable meshcom4 encoding and set maxhops (4)"); WrStrLn(" raw udp frame, send with ra02 -B 8 -S 11 -C 6 -N 2B -K"); WrStrLn(" -A in Raw-Mode set fixed 2d altitude in cm NN"); WrStrLn(" 1 2D, 2 3D, 4 auto-2D/3D"); WrStrLn(" -a altitude OFF"); WrStrLn(" -B Balloon mode: -g is altitude(m)"); WrStrLn(" -b for below -0 for above"); WrStrLn(" -w is switched on below"); WrStrLn(" -b driving Beacon Time in Seconds (15)"); WrStrLn(" -c APRS Comment (max 60 char)"); WrStrLn(" insert time hhmmss : \\h"); WrStrLn(" insert time ddhhmm : \\z"); WrStrLn(" insert file : \\:filename:"); WrStrLn(" insert Clb= : \\c"); WrStrLn(" insert time hh-mm-ss: \\t"); WrStrLn(" insert sats : \\s"); WrStrLn(" insert fix : \\f"); WrStrLn(" insert framecounter : \\n"); WrStrLn(" insert \\ : \\\"); <* IF TARGET_FAMILY="WIN32" THEN *> <* ELSE *> WrStrLn(" double all \ to pass thru bash eg. \\\\h"); <* END *> WrStrLn(" -C Send Cfg to GPS, / for $, // for /"); WrStrLn(" /PUBX,41,1,0007,0003,19200,0"); WrStrLn(" -d Destination Call SSID 0..7"); WrStrLn(" -D DAO Extension on for 20cm Resolution"); WrStrLn(" -f format 0=normal 1=compressed 2=mic-e (0)"); WrStrLn(" -g min. Speed for driving Beacon Time (4)"); WrStrLn(" -h this"); WrStrLn(" -I Mycall with SSID like NOCALL-15"); WrStrLn(' -i 2 Icon chars "/-" (House), "/>" (Car)...(//)'); WrStrLn(" -k Speed/Course OFF (not in mic-e)"); WrStrLn(" -l every n Beacons send one with Comment (5)"); WrStrLn(" -L Append raw GPS text to this File"); WrStrLn(" -M in Raw-Mode set dynamic model (balloon 1g)"); WrStrLn(" 0 portabel, 2 stationary, 3 pedestrian, 4 car,"); WrStrLn(" 5 sea, 6 air 1g, 7 air 2g, air 4g"); WrStrLn(" -m use Monitor UDP format :port for localhost"); WrStrLn(" -N send Position AXUDP every -n (default 2) eg. to aprsmap"); WrStrLn(" may be repeated for more destinations"); WrStrLn(" -n Beacon Time in Seconds to -N destination (2)"); WrStrLn(" -r send AXUDP (to kiss-TNC or TCPKISS via udpflex,"); WrStrLn(" to afskmodem or via aprsmap or udpgate to TCP)"); WrStrLn(" may be repeated for more destinations"); WrStrLn(" -s GPS Checksum check OFF"); WrStrLn(" -T Raw-Mode, Timepulse <[-]periode> (us)"); <* IF TARGET_FAMILY="WIN32" THEN *> WrStrLn(" -t : (com1:4800)"); <* ELSE *> WrStrLn(" -t : (/dev/ttyS0:4800)"); <* END *> WrStrLn(" -U switch Ublox>=M6 sV>=7 to Ublox-Raw (get vertical speed)"); WrStrLn(" needs bidirectional connection"); WrStrLn(" -u abort, not retry until open removable USB tty"); WrStrLn(" -V verbous, show sats (GSV-frames)"); WrStrLn(" -v verbous"); WrStrLn(" -w via Path like RELAY,WIDE1-1"); <* IF TARGET_FAMILY="WIN32" THEN *> <* ELSE *> WrStrLn(" -Z set system time to GPStime+ (will need root)"); WrStrLn(" -z same but do not terminate after time set"); <* END *> WrLn; HALT ELSE err:=TRUE END; (* h[0]:=0C; *) ELSE err:=TRUE END; IF err THEN EXIT END; END; IF (comptyp=1) & withdao THEN Error("DAO Option not with compressed Format") END; IF err THEN WrStr(">"); WrStr(h); WrStrLn("< use -h"); HALT END; END Parms; PROCEDURE gpstimetosystime(p-:POS):CARDINAL; VAR s:ARRAY[0..20] OF CHAR; sec:CARDINAL; BEGIN s:="20 : : "; s[2]:=CHR(p.year DIV 10 + ORD("0")); s[3]:=CHR(p.year MOD 10 + ORD("0")); s[5]:=CHR(p.month DIV 10 + ORD("0")); s[6]:=CHR(p.month MOD 10 + ORD("0")); s[8]:=CHR(p.day DIV 10 + ORD("0")); s[9]:=CHR(p.day MOD 10 + ORD("0")); IF NOT StrToTime(s, sec) THEN RETURN 0 END; INC(sec, p.daytime); DateToStr(sec, s); RETURN sec END gpstimetosystime; PROCEDURE setstime(p-:POS); VAR s:ARRAY[0..20] OF CHAR; sec:CARDINAL; BEGIN sec:=p.date; IF sec>0 THEN INC(sec, timecorr); DateToStr(sec, s); IF verb THEN WrStr("time to sys:"); WrStrLn(s); END; <* IF TARGET_FAMILY="WIN32" THEN *> <* ELSE *> IF settime(sec)>=0 THEN WrStrLn("system time set"); ELSE WrStrLn("--- error setting system time (will need root)") END; IF terminatetimeset THEN HALT END; <* END *> timesetdone:=TRUE; END; END setstime; PROCEDURE sendudp(buf:ARRAY OF CHAR; len:INTEGER; ip:IPNUM; port:CARDINAL); VAR i:INTEGER; -- crc:CARDINAL; BEGIN i:=udpsend(udpsock, buf, len, port, ip); --FOR i:=0 TO upos-2 DO IO.WrHex(ORD(buf[i]), 3) END; IO.WrLn; END sendudp; PROCEDURE skip(b-:ARRAY OF CHAR; VAR p:CARDINAL; len:CARDINAL); BEGIN WHILE (p",") DO INC(p) END; IF p="0") & (b[p]<="9") THEN n:=ORD(b[p]) - ORD("0"); INC(p); RETURN TRUE END; n:=0; RETURN FALSE; END getnum; PROCEDURE beaconmacros(VAR s:ARRAY OF CHAR); CONST MSYM="\"; FILESYM=":"; VAR i,n,ic,tt:CARDINAL; len,j:INTEGER; ds,ns:ARRAY[0..255] OF CHAR; fn:ARRAY[0..1023] OF CHAR; f:File; BEGIN i:=0; ns[0]:=0C; WHILE (i0C) DO IF (s[i]=MSYM) & (s[i+1]=MSYM) THEN INC(i, 2); IF s[i]="z" THEN (* insert day, hour, min *) tt:=pos.date; IF NOT pos.dateok THEN tt:=time() END; DateToStr(tt, ds); DateToStr(time(), ds); ds[0]:=ds[8]; ds[1]:=ds[9]; ds[2]:=ds[11]; ds[3]:=ds[12]; ds[4]:=ds[14]; ds[5]:=ds[15]; ds[6]:=0C; Append(ns, ds); ELSIF s[i]="h" THEN (* insert hour, min, s *) tt:=pos.date; IF NOT pos.dateok THEN tt:=time() END; DateToStr(tt, 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(ns, ds); ELSIF s[i]=FILESYM THEN (* insert or write file *) fn[0]:=0C; INC(i); WHILE (i0C) & (s[i]<>FILESYM) DO Append(fn, s[i]); INC(i); END; f:=OpenRead(fn); IF FdValid(f) THEN len:=RdBin(f, ds, SIZE(ds)-1); Close(f); j:=0; WHILE (jCR) & (ds[j]<>LF) & (ds[j]<>0C) DO Append(ns, ds[j]); INC(j); END; ELSE Assign(s, "beacon macro file not readable "); Append(s, fn); IF verb THEN WrStrLn(s) END; -- s[0]:=0C; -- RETURN END; ELSIF s[i]=MSYM THEN Append(ns, MSYM+MSYM); ELSIF s[i]="s" THEN IntToStr(pos.sats, 1, ds); Append(ns, ds); ELSIF s[i]="f" THEN IntToStr(pos.fix, 1, ds); Append(ns, ds); ELSIF s[i]="t" THEN TimeToStr(pos.date MOD 86400, ds); Append(ns, ds); ELSIF s[i]="c" THEN ds:="Clb="; ic:=4; IF pos.climb<0.0 THEN ds[ic]:="-"; INC(ic); END; n:=TRUNC(ABS(pos.climb)*10.0+0.5); IF n>9999 THEN n:=9999 END; IF n>=1000 THEN ds[ic]:=CHR(n DIV 1000+ORD("0")); INC(ic) END; n:=n MOD 1000; IF n>=100 THEN ds[ic]:=CHR(n DIV 100+ORD("0")); INC(ic) END; n:=n MOD 100; ds[ic]:=CHR(n DIV 10+ORD("0")); INC(ic); ds[ic]:="."; INC(ic); ds[ic]:=CHR(n MOD 10+ORD("0")); INC(ic); ds[ic]:=0C; Append(ns, ds); ELSIF s[i]="n" THEN IntToStr(frames, 1, ds); Append(ns, ds); frames:=(frames+1) MOD 100000; ELSE Assign(s, "bad beacon macro "); Append(s, ns); Append(s, "???"); IF verb THEN WrStrLn(s) END; s[0]:=0C; RETURN END; ELSE Append(ns, s[i]) END; INC(i); END; Assign(s, ns); END beaconmacros; PROCEDURE decodeline(b-:ARRAY OF CHAR; len:CARDINAL; VAR p:POS); VAR i, n, j, msgs, msg :CARDINAL; div :LONGREAL; sign :BOOLEAN; BEGIN IF b[0]="$" THEN IF b[1]="G" THEN IF (b[3]="R") & (b[4]="M") & (b[5]="C") THEN i:=7; IF getnum(b, i, len, n) THEN p.daytime:=n*36000 ELSE RETURN END; IF getnum(b, i, len, n) THEN INC(p.daytime,n*3600) ELSE RETURN END; IF getnum(b, i, len, n) THEN INC(p.daytime,n*600) ELSE RETURN END; IF getnum(b, i, len, n) THEN INC(p.daytime,n*60) ELSE RETURN END; IF getnum(b, i, len, n) THEN INC(p.daytime,n*10) ELSE RETURN END; IF getnum(b, i, len, n) THEN INC(p.daytime,n) ELSE RETURN END; skip(b, i, len); IF b[i]<>"A" THEN RETURN END; skip(b, i, len); IF getnum(b, i, len, n) THEN p.lat:=FLOAT(n*10) ELSE RETURN END; IF getnum(b, i, len, n) THEN p.lat:=p.lat + FLOAT(n) ELSE RETURN END; IF getnum(b, i, len, n) THEN p.lat:=p.lat + FLOAT(n)/6.0 ELSE RETURN END; IF getnum(b, i, len, n) THEN p.lat:=p.lat + FLOAT(n)/60.0 ELSE RETURN END; IF b[i]="." THEN INC(i) ELSE RETURN END; IF getnum(b, i, len, n) THEN p.lat:=p.lat + FLOAT(n)/600.0 ELSE RETURN END; IF getnum(b, i, len, n) THEN p.lat:=p.lat + FLOAT(n)/6000.0 ELSE RETURN END; IF getnum(b, i, len, n) THEN p.lat:=p.lat + FLOAT(n)/60000.0 END; IF getnum(b, i, len, n) THEN p.lat:=p.lat + FLOAT(n)/600000.0 END; skip(b, i, len); IF b[i]="S" THEN p.lat:=-p.lat ELSIF b[i]<>"N" THEN RETURN END; skip(b, i, len); IF getnum(b, i, len, n) THEN p.long:=FLOAT(n*100) ELSE RETURN END; IF getnum(b, i, len, n) THEN p.long:=p.long + FLOAT(n*10) ELSE RETURN END; IF getnum(b, i, len, n) THEN p.long:=p.long + FLOAT(n) ELSE RETURN END; IF getnum(b, i, len, n) THEN p.long:=p.long + FLOAT(n)/6.0 ELSE RETURN END; IF getnum(b, i, len, n) THEN p.long:=p.long + FLOAT(n)/60.0 ELSE RETURN END; IF b[i]="." THEN INC(i) ELSE RETURN END; IF getnum(b, i, len, n) THEN p.long:=p.long + FLOAT(n)/600.0 ELSE RETURN END; IF getnum(b, i, len, n) THEN p.long:=p.long + FLOAT(n)/6000.0 ELSE RETURN END; IF getnum(b, i, len, n) THEN p.long:=p.long + FLOAT(n)/60000.0 END; IF getnum(b, i, len, n) THEN p.long:=p.long + FLOAT(n)/600000.0 END; skip(b, i, len); IF b[i]="W" THEN p.long:=-p.long ELSIF b[i]<>"E" THEN RETURN END; skip(b, i, len); p.speed:=0.0; WHILE getnum(b, i, len, n) DO p.speed:=p.speed*10.0 + FLOAT(n) END; IF b[i]="." THEN INC(i); div:=0.1; WHILE getnum(b, i, len, n) DO p.speed:=p.speed + FLOAT(n)*div; div:=div*0.1 END; END; p.speed:=p.speed*KNOTS; (* knots to km/h *) skip(b, i, len); p.course:=0.0; WHILE getnum(b, i, len, n) DO p.course:=p.course*10.0 + FLOAT(n) END; IF b[i]="." THEN INC(i); div:=0.1; WHILE getnum(b, i, len, n) DO p.course:=p.course + FLOAT(n)*div; div:=div*0.1 END; END; p.posok:=TRUE; skip(b, i, len); IF getnum(b, i, len, n) THEN p.day:=n*10 ELSE RETURN END; IF getnum(b, i, len, n) THEN INC(p.day,n) ELSE RETURN END; IF getnum(b, i, len, n) THEN p.month:=n*10 ELSE RETURN END; IF getnum(b, i, len, n) THEN INC(p.month,n) ELSE RETURN END; IF getnum(b, i, len, n) THEN p.year:=n*10 ELSE RETURN END; IF getnum(b, i, len, n) THEN INC(p.year,n) ELSE RETURN END; p.date:=gpstimetosystime(p); p.dateok:=p.date>0; ELSIF (b[3]="G") & (b[4]="G") & (b[5]="A") THEN (* $GPGGA,152554,3938.5665,N,10346.2039,W,1,08,1.7,12382.7,M,-22.3,M,,*7B *) (* $GPGGA,112435.00,4812.41112,N,01305.61998,E,1,08,1.04,398.3,M,44.9,M,,*59 *) i:=7; skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); IF getnum(b, i, len, n) THEN p.fix:=n ELSE RETURN END; skip(b, i, len); p.sats:=0; WHILE getnum(b, i, len, n) DO p.sats:=p.sats*10+n END; skip(b, i, len); skip(b, i, len); p.alt:=0.0; IF b[i]="-" THEN sign:=TRUE; INC(i) ELSE sign:=FALSE END; WHILE getnum(b, i, len, n) DO p.altok:=ALTLIFE; p.alt:=p.alt*10.0 + FLOAT(n) END; IF b[i]="." THEN INC(i); div:=0.1; WHILE getnum(b, i, len, n) DO p.alt:=p.alt + FLOAT(n)*div; div:=div*0.1 END; END; IF sign THEN p.alt:=-p.alt END; ELSIF (b[3]="G") & (b[4]="S") & (b[5]="V") THEN (* sat num/az/el/dB *) (* $GPGSV,3,1,11,22,78,048,19,01,75,130,32,03,74,289,,21,53,136,40*76 $GPGSV,3,2,11,17,41,291,16,04,31,195,37,19,24,315,,31,21,089,35*76 $GPGSV,3,3,11,32,13,043,,08,01,176,,09,,210,*4E *) i:=7; IF NOT getnum(b, i, len, msgs) THEN RETURN END; skip(b, i, len); IF NOT getnum(b, i, len, msg) OR (msg=0) OR (msg>4) THEN RETURN END; skip(b, i, len); IF NOT getnum(b, i, len, n) THEN RETURN END; IF NOT getnum(b, i, len, p.satcnt) THEN RETURN END; INC(p.satcnt, n*10); skip(b, i, len); msg:=(msg-1)*4; j:=0; LOOP IF msg+j>=p.satcnt THEN EXIT END; WITH p.satpos[msg+j] DO IF getnum(b, i, len, n) THEN END; IF getnum(b, i, len, id) THEN INC(id, n*10) END; skip(b, i, len); IF getnum(b, i, len, n) THEN END; IF getnum(b, i, len, el) THEN INC(el, n*10) END; skip(b, i, len); IF getnum(b, i, len, n) THEN END; IF getnum(b, i, len, az) THEN INC(az, n*10) END; IF getnum(b, i, len, n) THEN az:=az*10+n END; skip(b, i, len); IF getnum(b, i, len, n) THEN END; IF getnum(b, i, len, db) THEN INC(db, n*10) END; skip(b, i, len); END; INC(j); p.lastsat:=msg+j; IF j>3 THEN EXIT END; END; END; ELSIF (b[1]="P") & (b[2]="U") & (b[3]="B") & (b[4]="X") THEN (* ublox propietary for versical speed *) (* $PUBX,00,230327.00,7825.08527,N,01202.28188,E,425.646,G3,3.4,7.8,0.050,331.58,-0.026,,1.11,1.95,1.33,7,0,0*49 *) (* -climb *) i:=5; skip(b, i, len); IF (b[i]="0") & (b[i+1]="0") THEN (* frametype 00 *) INC(i, 2); skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); skip(b, i, len); p.climb:=0.0; IF b[i]="-" THEN sign:=TRUE; INC(i) ELSE sign:=FALSE END; WHILE getnum(b, i, len, n) DO p.climb:=p.climb*10.0 + FLOAT(n) END; IF b[i]="." THEN INC(i); div:=0.1; WHILE getnum(b, i, len, n) DO p.climb:=p.climb + FLOAT(n)*div; div:=div*0.1 END; END; IF NOT sign THEN p.climb:=-p.climb END; END; END; END; END decodeline; PROCEDURE Hex(d:CARDINAL):CHAR; BEGIN d:=d MOD 16; IF d>9 THEN INC(d, ORD("A")-10-ORD("0")) END; RETURN CHR(d+ORD("0")) END Hex; PROCEDURE checksum(b-:ARRAY OF CHAR; len:CARDINAL):BOOLEAN; TYPE SET8=SET OF [0..7]; VAR i:CARDINAL; cs:SET8; ok:BOOLEAN; BEGIN ok:=TRUE; i:=1; cs:=SET8{}; WHILE (i"*") DO cs:=cs/CAST(SET8, b[i]); INC(i); END; IF i+2>=len THEN ok:=FALSE END; IF ok THEN IF (b[i+1]<>Hex(CAST(CARDINAL, cs) DIV 16)) OR (b[i+2]<>Hex(CAST(CARDINAL, cs))) THEN ok:=FALSE END; END; IF verb & NOT ok THEN WrStrLn("GPS Checksum Error") END; RETURN ok END checksum; PROCEDURE showline(b-:ARRAY OF CHAR; len:CARDINAL); VAR i:CARDINAL; BEGIN i:=0; WHILE i0) & (cnt<=HIGH(sats)+1) THEN FOR i:=0 TO cnt-1 DO WITH sats[i] DO IF (id>0) & (db>0) & (db<100) THEN INC(med, db); INC(medc); pow:=pow+exp(FLOAT(db)*(1.0/DB)); IF az0 THEN Append(h, " median:"); FixToStr(FLOAT(med)/FLOAT(medc), 2, hh); Append(h, hh); Append(h, "dB"); ELSIF pow>0.1 THEN Append(h, " sum:"); FixToStr(ln(pow)*DB, 2, hh); Append(h, hh); Append(h, "dB"); END; WrStrLn(h); REPEAT (* sort up by atimuth *) minn:=MAX(CARDINAL); FOR i:=0 TO cnt-1 DO WITH sats[i] DO IF id>0 THEN IF az=min THEN IntToStr(id, 2, h); IntToStr(az, 4, hh); Append(h, hh); IntToStr(el, 3, hh); Append(h, hh); IntToStr(db, 3, hh); Append(h, hh); p:=Length(h); Append(h, " **************************************************"); dh:=db DIV 2; IF dh>49 THEN dh:=49 END; h[p+dh+1]:=0C; IF ODD(db) THEN Append(h, "-") END; WrStrLn(h); ELSIF (az>min) & (az0C) DO IF s[i]="/" THEN INC(i); IF s[i]<>"/" THEN Append(b, "$") END; END; Append(b, s[i]); INC(i); END; i:=1; cs:=SET8{}; WHILE (i0C) DO cs:=cs/CAST(SET8, b[i]); INC(i); END; Append(b, "*"); Append(b, Hex(CAST(CARDINAL, cs) DIV 16)); Append(b, Hex(CAST(CARDINAL, cs))); Append(b, CR); Append(b, LF); WrBin(tty, b, Length(b)); IF verb THEN WrStr("uploaded:"); WrStrLn(b) END; END uploadcfg; PROCEDURE sendaprs(lat, long, alt, course, speed:LONGREAL; comp:CARDINAL; withspd, withalt, dao, com:BOOLEAN; comm, viapath-:ARRAY OF CHAR; local:BOOLEAN; udp:pUDPDESTS; symt, symb:CHAR; meshcom4:CARDINAL); 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:ARRAY[0..250] OF CHAR; raw:ARRAY[0..360] OF CHAR; rp:INTEGER; i,n, nl, micdest:CARDINAL; a:LONGREAL; BEGIN (* OE0AAA-9>APERXQ,RELAY,WIDE2-2:!4805.44N/01333.64E>325/016/A=001824 *) (* !mmmmbOE0AAA-99>*!8307.32N/01803.71E#/A=000082[00][04][03][0C][F0][18][09] *) b:=""; IF meshcom4>0 THEN b:="!mmmmb" END; Append(b, mycall); micdest:=Length(b)+1; IF meshcom4=0 THEN IF local THEN Append(b, ">NOGATE"); ELSE Append(b, ">APLT01"); IF micessid>0 THEN Append(b, "-"); Append(b, CHR(micessid+ORD("0"))) END; IF viapath[0]<>0C THEN Append(b, ","); Append(b, viapath) END; END; Append(b, ":"); ELSE Append(b,">*") END; IF comp=0 THEN (* uncompressed *) Append(b, "!"); i:=Length(b); a:=ABS(lat); n:=truncc(a); b[i]:=num(n DIV 10); INC(i); b[i]:=num(n); INC(i); n:=truncc((a-LFLOAT(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]:=symt; INC(i); a:=ABS(long); n:=truncc(a); b[i]:=num(n DIV 100); INC(i); b[i]:=num(n DIV 10); INC(i); b[i]:=num(n); INC(i); n:=truncc((a-LFLOAT(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]:=symb; INC(i); IF withspd THEN n:=truncc(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:=truncc(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 withalt THEN b[i]:="/"; INC(i); b[i]:="A"; INC(i); b[i]:="="; INC(i); n:=truncc(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]:=symt; INC(i); IF lat<90.0 THEN n:=truncc((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:=truncc((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]:=symb; INC(i); IF withspd THEN b[i]:=CHR(33+truncc(course) DIV 4); INC(i); b[i]:=CHR(33+truncc(ln(speed*(1.0/KNOTS)+1.0)*12.9935872129)); INC(i); b[i]:=CHR(33+32+24+6); INC(i); ELSIF withalt THEN IF alt*FEET>1.0 THEN n:=truncc(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 withspeed & withalt THEN b[i]:="/"; INC(i); b[i]:="A"; INC(i); b[i]:="="; INC(i); n:=truncc(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:=truncc(ABS(long)); n:=truncc(ABS(lat)); b[i]:=CHR(80 + n DIV 10); INC(i); b[i]:=CHR(80 + n MOD 10); INC(i); n:=truncc((ABS(lat)-LFLOAT(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:=truncc((ABS(long)-LFLOAT(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:=truncc(speed*(1.0/KNOTS)+0.5); b[i]:=CHR(n DIV 10 + 28); INC(i); nl:=truncc(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]:=symb; INC(i); b[i]:=symt; INC(i); IF withalt THEN IF alt>-10000.0 THEN n:=truncc(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; IF com THEN beaconmacros(comm); Append(b, comm); END; IF meshcom4>0 THEN nl:=Length(b); b[0]:="!"; n:=Random(); (* MID *) b[1]:=CHR(n MOD 256); b[2]:=CHR(ASH(n,-8) MOD 256); b[3]:=CHR(ASH(n,-16) MOD 256); b[4]:=CHR(ASH(n,-24) MOD 256); b[5]:=CHR(meshcom4 MOD 8); (* maxhops, traceroute=bit6, via mqtt=bit7*) IF nl+6=3 THEN WHILE udp<>NIL DO IF meshcom4=0 THEN IF udp^.useaxudp THEN mon2raw(b, raw, rp); ELSE rp:=Length(b); Assign(raw, b); END; END; IF rp>2 THEN sendudp(raw, rp, udp^.ipnum, udp^.toport); udp:=udp^.next; END; END; END; IF verb THEN WrFixed(lat, 6,1); WrStr(" "); WrFixed(long, 6,1); WrStr(" "); WrFixed(speed, 2,1); WrStr("km/h "); WrFixed(course, 1,1); WrStr("deg "); WrFixed(alt, 2,1); WrStrLn("m"); IF rp>0 THEN FOR i:=0 TO VAL(CARDINAL, rp-1) DO WrChHex(b[i]) END; WrStrLn(""); END; END; END sendaprs; PROCEDURE newpos; VAR balloonkm:CARDINAL; BEGIN IF pos.posok THEN viaakt:=via; INC(btime); IF balloon THEN IF pos.alt>0.0 THEN balloonkm:=truncc(pos.alt) ELSE balloonkm:=0 END; ELSE balloonkm:=truncc(pos.speed) END; IF (balloonkm>=drivekm)<>balloon THEN IF btime>=btimedrive THEN btime:=0 END; (* drive / low altitude beacon *) ELSE (* no drive / high altitide *) IF balloon THEN viaakt[0]:=0C END; (* via path off *) IF btime>btime0 THEN btime:=0 END; (* no drive / high altitide *) END; IF btime=0 THEN sendaprs(pos.lat, pos.long, pos.alt, pos.course, pos.speed, comptyp, withspeed, withalti & (pos.altok>0), withdao, comcnt=0, comment, viaakt, FALSE, udpdests, symt, symb, meshcom4hops); INC(comcnt); IF comcnt>=comintval THEN comcnt:=0 END; END; IF udpdests2<>NIL THEN (* second (fast) beacon to map *) INC(btimeN); IF btimeN>=btimenavi THEN sendaprs(pos.lat, pos.long, pos.alt, pos.course, pos.speed, 0, TRUE, pos.altok>0, TRUE, FALSE, 0C, 0C, TRUE, udpdests2, symt, symb, 0); btimeN:=0; END; END; IF pos.altok>0 THEN DEC(pos.altok) END; pos.posok:=FALSE; END; IF pos.dateok & NOT timesetdone THEN setstime(pos); END; END newpos; <* IF TARGET_FAMILY="WIN32" THEN *> PROCEDURE WrLog(b:ARRAY OF CHAR; len:CARDINAL); <* ELSE *> PROCEDURE WrLog(b-:ARRAY OF CHAR; len:CARDINAL); <* END *> VAR logfd:File; <* IF TARGET_FAMILY="WIN32" THEN *> crlf:ARRAY[0..1] OF CHAR; <* END *> BEGIN IF logfilename[0]<>0C THEN logfd:=OpenAppend(logfilename); IF NOT FdValid(logfd) THEN logfd:=OpenWrite(logfilename) END; IF FdValid(logfd) THEN WrBin(logfd, b, len); <* IF TARGET_FAMILY="WIN32" THEN *> crlf:=CR+LF; WrBin(logfd, crlf, 2); <* ELSE *> WrBin(logfd, LF, 1); <* END *> Close(logfd); ELSE WrStr("cannot write ["); WrStr(logfilename); WrStrLn("]") END; END; END WrLog; ---------- ublox raw PROCEDURE atang2(x, y:LONGREAL):LONGREAL; VAR w:REAL; BEGIN IF ABS(x)>ABS(y) THEN w:=arctan(y/x); IF x<0.0 THEN IF y>0.0 THEN w:=pi+w ELSE w:=w-pi END; END; ELSIF y<>0.0 THEN w:=(pi*0.5-arctan(x/y)); IF y<0.0 THEN w:=w-pi END; ELSE w:=0.0 END; RETURN w END atang2; PROCEDURE initubloxraw(cmd-:ARRAY OF CARD8); VAR sum1, sum2:CARD8; b:ARRAY[0..50] OF CARD8; i,j:CARDINAL; BEGIN b[0]:=0B5H; b[1]:=062H; j:=HIGH(cmd)+1; b[2]:=cmd[0]; b[3]:=cmd[1]; b[4]:=j-2; b[5]:=(j-2) DIV 256; i:=2; WHILE (i0) & (dur0 DO DEC(len); w:=w*256+ORD(b[p+len]) END; RETURN w END btow; PROCEDURE rawbyte(c:CHAR); CONST ZEROTIME=315964800; RAD=pi/180.0; VAR bt, ps, tow, week:CARDINAL; sum1, sum2:CARD8; cstr:ARRAY[0..60] OF CHAR; vn,ve, slong, clong, slat, clat:LONGREAL; s:ARRAY[0..30] OF CHAR; BEGIN --WrHex(ORD(c), 3); gpsb[gpsp]:=c; IF gpsp=0 THEN IF c=CHR(0B5H) THEN INC(gpsp) ELSE INC(rawframeerr) END; ELSIF gpsp=1 THEN IF c<>CHR(062H) THEN gpsp:=0 ELSE INC(gpsp) END; ELSE INC(gpsp); IF gpsp>HIGH(gpsb) THEN gpsp:=0; ELSIF gpsp>=5 THEN IF gpsp>ORD(gpsb[4])+ORD(gpsb[5])*256+7 THEN sum1:=ORD(gpsb[2])+ORD(gpsb[3]); sum2:=ORD(gpsb[2])*2+ORD(gpsb[3]); ps:=4; WHILE ps+20) & (pos.timeflags=7); pos.vx:=VAL(LONGREAL, btow(gpsb,34,4))*0.01; pos.vy:=VAL(LONGREAL, btow(gpsb,38,4))*0.01; pos.vz:=VAL(LONGREAL, btow(gpsb,42,4))*0.01; pos.sats:=btow(gpsb,53,1); pos.speedok:=TRUE; ELSIF (ORD(gpsb[2])=1) & (ORD(gpsb[3])=2) & (gpsp=36) THEN (* navPOSLLH frame *) pos.long:=VAL(LONGREAL, btow(gpsb,10,4))*(0.0000001); pos.lat:=VAL(LONGREAL, btow(gpsb,14,4))*(0.0000001); pos.alt:=VAL(LONGREAL, btow(gpsb,22,4))*0.001; pos.posok:=TRUE; IF pos.fix=3 THEN pos.altok:=ALTLIFE END; ELSIF (ORD(gpsb[2])=1) & (ORD(gpsb[3])=32) & (gpsp=24) THEN (* navTIMEGPS frame *) pos.leapseconds:=btow(gpsb,16,1); IF pos.leapseconds>=128 THEN DEC(pos.leapseconds, 256) END; (* signed *) -- WrInt(btow(gpsb,6,4) DIV 1000, 10); (* ms in week *) pos.timeflags:=btow(gpsb,17,1); (* 1:tow ok 2:week ok 4:leapsecond ok *) ELSE (* other frame types *) IF verb THEN showh(gpsb, gpsp) END; END; IF pos.posok & pos.speedok THEN IF (pos.fix>1) & (pos.fix<5) THEN slong:=sin(pos.long*RAD); clong:=cos(pos.long*RAD); slat:=sin(pos.lat*RAD); clat:=cos(pos.lat*RAD); vn:=-pos.vx*slat*clong - pos.vy*slat*slong + pos.vz*clat; ve:=-pos.vx*slong + pos.vy*clong; pos.climb:=pos.vx*clat*clong + pos.vy*clat*slong + pos.vz*slat; pos.course:=atang2(vn, ve)*(1.0/RAD); IF pos.course<0.0 THEN pos.course:=360.0+pos.course END; pos.speed:=sqrt(vn*vn + ve*ve)*3.6; newpos; END; Logl:="sats="; IntToStr(pos.sats, 1, s); Append(Logl, s); Append(Logl, " fix="); IntToStr(pos.fix, 1, s); Append(Logl, s); Append(Logl, " "); IF pos.dateok THEN DateToStr(pos.date, s); ELSE s:="[no time fix]" END; Append(Logl, s); Append(Logl, " vx="); FixToStr(pos.vx, 2, s); Append(Logl, s); Append(Logl, " vy="); FixToStr(pos.vy, 2, s); Append(Logl, s); Append(Logl, " vz="); FixToStr(pos.vz, 2, s); Append(Logl, s); Append(Logl, " "); FixToStr(pos.lat, 5, s); Append(Logl, s); Append(Logl, " "); FixToStr(pos.long, 5, s); Append(Logl, s); Append(Logl, " "); FixToStr(pos.alt, 2, s); Append(Logl, s); Append(Logl, "m "); FixToStr(pos.speed, 2, s); Append(Logl, s); Append(Logl, "km/h "); IntToStr(VAL(INTEGER, pos.course), 1, s); Append(Logl, s); Append(Logl, "deg "); FixToStr(pos.climb, 2, s); Append(Logl, s); Append(Logl, "m/s"); IF verb THEN WrStrLn(Logl) END; WrLog(Logl, Length(Logl)); Logl:=""; pos.posok:=FALSE; pos.speedok:=FALSE; END; rawframeerr:=0; sumerrcnt:=0; ELSE INC(sumerrcnt); IF verb THEN WrCard(sumerrcnt, 1); WrStrLn(" raw-checksum err") END; END; gpsp:=0; END; END; END; END rawbyte; PROCEDURE ubloxon(on:BOOLEAN; baud:CARDINAL); VAR s:ARRAY[0..21] OF CARD8; i:CARDINAL; BEGIN sumerrcnt:=0; rawframeerr:=0; IF on THEN IF verb THEN WrStrLn("switch gps to ubloxraw") END; FOR i:=0 TO HIGH(s) DO s[i]:=INITBAUD[i] END; ELSE IF verb THEN WrStrLn("switch gps to nmea") END; FOR i:=0 TO HIGH(s) DO s[i]:=SETNMEA[i] END; END; s[10]:=baud MOD 256; s[11]:=baud DIV 256 MOD 256; s[12]:=baud DIV 65536 MOD 256; initubloxraw(s); IF on THEN <* IF TARGET_FAMILY="WIN32" THEN *> Sleep(200); <* ELSE *> usleep(200000); <* END *> FrameOn(1,6); (* speeds *) FrameOn(1,2); (* egmalt, pos *) FrameOn(1,32); (* leap second *) IF balloon THEN SetDynamicModel(6) END; IF fixalt0 THEN TimePuls(timepuls, duration) END; -- Power(10000, 10000); END; END ubloxon; -------ublox raw VAR len, rp:INTEGER; PROCEDURE gpsbyte(c:CHAR); BEGIN IF (c=CR) OR (c=LF) THEN IF gpsp>0 THEN pos.dateok:=FALSE; IF sumoff OR checksum(gpsb, gpsp) THEN decodeline(gpsb, gpsp, pos); WrLog(gpsb, gpsp); ELSE pos.posok:=FALSE; END; IF verb THEN showline(gpsb, gpsp) END; IF verb2 & (pos.lastsat>0) & (pos.satcnt=pos.lastsat) THEN showsats(pos.satcnt, pos.satpos); FILL(ADR(pos.satpos), 0C, SIZE(pos.satpos)); pos.lastsat:=0; END; newpos; END; gpsp:=0; ELSIF (c>" ") & (gpsp <* ELSE *> PROCEDURE ["C"] resetgps(signum:INTEGER); BEGIN IF ubloxraw THEN ubloxon(FALSE, baud) END; WrStr("exit "); WrInt(signum,0); WrStrLn("!"); HALT(signum) END resetgps; PROCEDURE ["C"] test(signum:INTEGER); BEGIN (* Power(5000,10000) *) GetAlm END test; <* END *> BEGIN <* IF TARGET_FAMILY="WIN32" THEN *> STDIO(TRUE); <* ELSE *> signal(SIGTERM,resetgps); signal(SIGINT, resetgps); <* END *> sumoff:=FALSE; anyip:=TRUE; junk:=TRUE; FILL(ADR(pos), 0C, SIZE(pos)); verb:=FALSE; verb2:=FALSE; usbrobust:=TRUE; balloon:=FALSE; baud:=4800; <* IF TARGET_FAMILY="WIN32" THEN *> ttynamee:="com1"; <* ELSE *> ttynamee:="/dev/ttyS0"; <* END *> logfilename:=""; udpsock:=-1; gpsp:=0; mycall[0]:=0C; via[0]:=0C; comment[0]:=0C; symt:="/"; symb:="/"; comptyp:=0; withalti:=TRUE; withspeed:=TRUE; withdao:=FALSE; micessid:=0; btime0:=3*60; btimedrive:=15; drivekm:=4; btimeN:=0; comintval:=5; comcnt:=0; btime:=0; msgtyp:=6; btimenavi:=BTIMENAVI; timesetdone:=TRUE; terminatetimeset:=FALSE; timecorr:=0; frames:=0; Logl:=""; dynamicmodel:=MAX(CARDINAL); fixalt:=MAX(CARDINAL); fixmode:=3; sumerrcnt:=0; timepuls:=0; pconfig:=NIL; udpdests:=NIL; udpdests2:=NIL; udpsock:=-1; meshcom4hops:=0; Parms; IF (Length(mycall)<3) & NOT terminatetimeset THEN WrStrLn("no tx without ") END; IF (meshcom4hops<>0) & (comptyp>1) THEN Error("meshcom4 will not work with mic-e") END; --Gencrctab; opentty; rndseed:=LFLOAT(time())/LFLOAT(MAX(CARDINAL)); WHILE pconfig<>NIL DO uploadcfg(pconfig^.str); pconfig:=pconfig^.next END; IF ubloxraw THEN ubloxon(TRUE, baud) END; LOOP <* IF TARGET_FAMILY="WIN32" THEN *> IF NOT ReadFile(tty, tbuf, SIZE(tbuf), dlen, NIL) THEN dlen:=0 END; len:=dlen; Sleep(250); <* ELSE *> fdclr; fdsetr(tty); IF selectr(0, 0)>=0 THEN IF issetr(tty) THEN len:=RdBin(tty, tbuf, SIZE(tbuf)); <* END *> testtty(len, junk); IF NOT junk THEN FOR rp:=0 TO len-1 DO IF ubloxraw THEN rawbyte(tbuf[rp]) ELSE gpsbyte(tbuf[rp]) END; END; ELSIF ubloxraw THEN ubloxon(TRUE, baud) END; junk:=FALSE; IF ubloxraw & (rawframeerr>=200) THEN (* maybe gps reset and is in nmea *) IF verb THEN WrStrLn("rawmode framing errors") END; ubloxon(TRUE, baud); END; <* IF TARGET_FAMILY="WIN32" THEN *> <* ELSE *> END; END; <* END *> END; END gps2aprs.