(* -lrt *) <*+M2EXTENSIONS *> <*-CHECKDIV *> <*-CHECKRANGE *> <*-COVERFLOW *> <*-IOVERFLOW*> <*-DOREORDER*> <*-PROCINLINE*> <*+GENCTYPES*> <*+COMMENT*> <*+GENCDIV*> <* IF __GEN_C__ THEN *> <*+M2EXTENSIONS *> <*+STORAGE *> <*-GENCTYPES*> <*+COMMENT*> <*-GENHISTORY*> <*-GENDEBUG*> <*-GENDATE*> <*-LINENO*> <*-CHECKINDEX*> <*-CHECKDNDEX*> <*+GENCDIV*> <*-GENKRC*> <*+NOOPTIMIZE*> <*-GENSIZE*> <*-ASSERT*> <*-CHECKNIL*> <*-COVERFLOW*> <*-IOVERFLOW*> <*-CHECKRANGE*> <*-CHECKSET*> <*-CHECKDIV*> <*-GENCONSTENUM*> <*GENWIDTH="120"*> <* ELSE *> <*+GENHISTORY*> <*+GENDEBUG*> <*+LINENO*> <*+CHECKINDEX*> <*+CHECKDINDEX*> <* END *> MODULE ra02; (* gpio or lpt to scp ra02 radio module(s) fsk, afsk lora tx, lora rx *) <* IF __GEN_C__ THEN *> <* ELSE *> IMPORT lpt; <* END *> IMPORT udp; FROM SYSTEM IMPORT ADR, CAST, FILL, SHIFT, INT16, CARD16, CARD8, INT8; FROM osi IMPORT Werr, WrStr, WrStrLn, WrInt, WrCard, File, IsFifo, OpenRead, OpenRW, Close, WrBin, WrFixed, ALLOCATE, DEALLOCATE, NextArg, RdBin, time, usleep, Rename, openudp, SOCKET, udpsend, timens, OpenWrite; FROM aprsstr IMPORT IntToStr, StrToCard, StrToInt, StrToFix, mon2raw, AppCRC, GetIp2, raw2mon, extrudp2, GHOSTSET, Append, CardToStr, Length, Assign, TimeToStr, FixToStr, DateToStr; FROM signal IMPORT signal, SIGTERM, SIGINT, SIGPIPE, sighandler_t; --FROM Select IMPORT monotonicms; CONST LF=12C; STOUT=2; STIN=1; STATLEN=1; (* 30 *) CALMASK=0; NETID=12H; XTAL=32000000.0; FSTEP=XTAL/524288.0; MINBAUD=VAL(INTEGER, XTAL/255/256); BWTAB=ARRAY OF REAL {7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0, 500.0}; RegSyncWord=039H; RegFeiMsb=028H; RegFeiMid=029H; RegFeiLsb=02AH; RegPacketRssi=01AH; RegPaRamp=0AH; RegPaDac=04DH; RegOcp=0BH; RegPktSnrValue=019H; RegFifoRxCurrentAddr=10H; RegOpMode=01H; RegModemStat=18H; RegIrqFlagsMask=11H; RegIrqFlags=12H; RegRxNbBytes=13H; RegFifoAddrPtr=0DH; RegHopChannel=1CH; RegRssiValue=1BH; RegRxPacketCntValueLsb=17H; RegFifo=00H; RegFifoTxBaseAddr=0EH; RegFrMsb=06H; RegFrMid=07H; RegFrLsb=08H; RegDetectOptimice=31H; RegDetectionThreshold=37H; RegLna=0CH; RegModemConfig3=26H; RegModemConfig2=1EH; RegModemConfig1=1DH; RegPaConfig=09H; RegPayloadLength=22H; RegPreambleMsb=20H; RegPreambleLsb=21H; RegInvertIQ=33H; RegInvertIQ2=3BH; RegTemp=3CH; RegHighBwOptimize1=36H; RegHighBwOptimize2=3AH; --fsk RegBitrateMsb=02H; RegBitrateLsb=03H; RegFdevMsb=04H; RegFdevLsb=05H; RegPreampleMsb=025H; RegPreampleLsb=026H; RegSyncConfig=27H; RegPacketConfig1=030H; RegPacketConfig2=031H; RegPayloadLengthFsk=032H; RegFifoThresh=035H; RegSeqConfig1=036H; RegSeqConfig2=037H; RegIrqFlags1=03EH; RegIrqFlags2=03FH; RegBitrateFrac=05DH; RegRxConfig=0DH; RegPllHf=70H; FIFOFILL=8; OVERSAMP=11; AFSKBAUD=1200*OVERSAMP; GPIOFN="/sys/class/gpio"; GPIOEXPORT=GPIOFN+"/export"; GPIOUNEXPORT=GPIOFN+"/unexport"; GPIOX=GPIOFN+"/gpio"; GPIODIRECTION="/direction"; GPIOIN="in"; GPIOOUT="out"; GPIODATA="/value"; GPIOS=256; TYPE SET32=SET OF [0..31]; SET8=SET OF [0..7]; IPNUM=CARDINAL; UDPPORT=CARDINAL; STATE=(stSLEEP, stRX, stWAITDCD, stTX); pTXCONTEXT=POINTER TO TXCONTEXT; TXCONTEXT=RECORD next :pTXCONTEXT; symboltime, mhz :REAL; sf, bw, cr, ftextlen, preamb, power, txdel, deviation, splitlen, netid :CARDINAL; scrambler :SET32; cfgoptimize, baud, fskp, cfgramp:INTEGER; swapiq, usedcd, rawfsk, sendfsk, rawlora, checkip, optimize, verbpart2, implicit :BOOLEAN; udpip :IPNUM; udpbind, udpport :UDPPORT; udpsocket :INTEGER; udp2 :BOOLEAN; ftext :ARRAY[0..350*OVERSAMP] OF CHAR; END; GPIO=RECORD ceN, mosiN, misoN, sckN :CARDINAL; ceFD, mosiFD, sckFD :INTEGER; misoFN :ARRAY[0..99] OF CHAR; END; pCHIP=POINTER TO CHIP; CHIP=RECORD next :pCHIP; gpio :GPIO; state :STATE; atx, ptx :pTXCONTEXT; swapiq, implicit, optimize, rxon, agc, boost :BOOLEAN; rxtxdel, num, lnaboost, lnagain, rxcr, rxsf, rxbw, band, mso, stato, statu, netid, preamblelimit, calcnt :CARDINAL; cfgoptimize, cfgramp, rssicorr, cfgocp :INTEGER; symboltime, rxmhz, datarate, ppm:REAL; splitb :ARRAY[0..350] OF CHAR; issplit :BOOLEAN; END; GPIOSET=SET OF [0..GPIOS-1]; VAR BASE, i, ch, synt, lptnum, tcnt, loopdelay, loopdelayfast:CARDINAL; verb, verb2:BOOLEAN; fn:ARRAY[0..99] OF CHAR; chips:pCHIP; gpostate:GPIOSET; gpiofds:ARRAY[0..GPIOS-1] OF INTEGER; judpsock :INTEGER; jipnum :IPNUM; judpport :UDPPORT; PROCEDURE monotonicms():CARDINAL; VAR s,ns:CARDINAL; BEGIN timens(TRUE, s, ns); RETURN ns DIV 1000000 + s*1000 END monotonicms; PROCEDURE Error(text-:ARRAY OF CHAR); BEGIN Werr(text); Werr(" error abort"+LF); HALT END Error; PROCEDURE hex(n:CARDINAL):CHAR; BEGIN n:=n MOD 16; IF n<=9 THEN RETURN CHR(n+ORD("0")) END; RETURN CHR(n+(ORD("A")-10)) END hex; PROCEDURE WrHex(x, digits, len:CARDINAL); VAR i:CARDINAL; s:ARRAY[0..255] OF CHAR; BEGIN IF digits>HIGH(s) THEN digits:=HIGH(s) END; i:=digits; WHILE (i0 DO DEC(digits); s[digits]:=hex(x); x:=x DIV 16; END; WrStr(s); END WrHex; PROCEDURE WrChHex(c:CHAR); VAR s:ARRAY[0..10] OF CHAR; BEGIN IF (c>=177C) OR (c<" ") THEN s[0]:="["; s[1]:=hex(ORD(c) DIV 16); s[2]:=hex(ORD(c)); s[3]:="]"; s[4]:=0C; ELSE s[0]:=c; s[1]:=0C; END; WrStr(s); END WrChHex; PROCEDURE ShowFrame(VAR f:ARRAY OF CHAR; len:CARDINAL; port:CHAR); PROCEDURE WCh(c:CHAR); BEGIN IF c<>15C THEN IF (c<" ") OR (c>=177C) THEN WrStr(".") ELSE WrStr(c) END; END; END WCh; PROCEDURE ShowCall(VAR f:ARRAY OF CHAR; pos:CARDINAL); VAR i,e:CARDINAL; BEGIN e:=pos; FOR i:=pos TO pos+5 DO IF f[i]<>100C THEN e:=i END; END; FOR i:=pos TO e DO WCh(CHR(ASH(ORD(f[i]), -1))) END; i:=ASH(ORD(f[pos+6]), -1) MOD 16; IF i<>0 THEN WrStr("-"); IF i>=10 THEN WrStr(CHR(i DIV 10 + ORD("0"))) END; WrStr(CHR(i MOD 10 + ORD("0"))); END; END ShowCall; PROCEDURE Showctl(com, cmd:CARDINAL); CONST UA = {0,1,5,6}; DM = {0,1,2,3}; SABM={0,1,2,3,5}; DISC={0,1,6}; FRMR={0,1,2,7}; UI = {0,1}; RR = {0}; REJ= {0,3}; RNR= {0,2}; VAR cm:BITSET; PF:ARRAY[0..3] OF CHAR; BEGIN WrStr(" ctl "); cm:=CAST(BITSET, cmd) - {4}; IF cm * {0,1,2,3} = RR THEN WrStr("RR"); WrStr(CHR(48+ASH(cmd, -5))); ELSIF cm * {0,1,2,3} = RNR THEN WrStr("RNR"); WrStr(CHR(48+ASH(cmd, -5))); ELSIF cm * {0,1,2,3} = REJ THEN WrStr("REJ"); WrStr(CHR(48+ASH(cmd, -5))); ELSIF cm * {0} = {} THEN WrStr("I"); WrStr(CHR(48+ASH(cmd, -5))); WrStr(CHR(48+ASH(cmd, -1) MOD 8)); ELSIF cm = UI THEN WrStr("UI") ELSIF cm = DM THEN WrStr("DM"); ELSIF cm = SABM THEN WrStr("SABM") ELSIF cm = DISC THEN WrStr("DISC") ELSIF cm = UA THEN WrStr("UA") ELSIF cm = FRMR THEN WrStr("FRMR") ELSE WrHex(cmd,2,0) END; PF:="v^-+"; IF (com=0) OR (com=3) THEN WrStr("v1") ELSE WrStr(PF[com MOD 2 + 2*ORD(4 IN CAST(BITSET, cmd))]) END; END Showctl; VAR i:CARDINAL; v, d:BOOLEAN; h:ARRAY[0..20] OF CHAR; BEGIN WrStr(port); i:=0; LOOP IF ODD(ORD(f[i])) THEN EXIT END; INC(i); IF i>len THEN i:=0; EXIT (* no address end mark found *) END; END; IF i MOD 7 <> 6 THEN -- WrStrLn(" no ax.25 (address field size not multiples of 7)"); i:=0; WHILE (i=128) & (ODD(ORD(f[i+6])) OR (ORD(f[i+13])<128)) THEN WrStr("*") END; INC(i,7); END; Showctl(ORD(7 IN CAST(SET8, f[6])) + 2*ORD(7 IN CAST(SET8,f[13])), ORD(f[i])); INC(i); IF i15C THEN WCh(f[i]); d:=TRUE; ELSIF d THEN WrStrLn(""); d:=FALSE END; INC(i); END; IF d THEN WrStrLn("") END; -- END; END ShowFrame; PROCEDURE StrToHex(s-:ARRAY OF CHAR; VAR n:CARDINAL):BOOLEAN; VAR i:CARDINAL; c:CHAR; BEGIN i:=0; n:=0; WHILE (i<=HIGH(s)) & (s[i]<>0C) DO n:=n*16; c:=CAP(s[i]); IF (c>="0") & (c<="9") THEN INC(n, ORD(c)-ORD("0")) ELSIF (c>="A") & (c<="F") THEN INC(n, ORD(c)-(ORD("A")-10)); ELSE RETURN FALSE END; INC(i); END; RETURN TRUE END StrToHex; PROCEDURE GetIp(h-:ARRAY OF CHAR; VAR ip:IPNUM; VAR dp, lp:UDPPORT; VAR fd:INTEGER; VAR check:BOOLEAN):INTEGER; BEGIN IF GetIp2(h, ip, dp, lp, check)<0 THEN RETURN -1 END; fd:=udp.openudp(); IF (fd<0) OR (udp.bindudp(fd, lp)<0) (*OR (udp.udpnonblock(fd)<0)*) THEN RETURN -1 END; RETURN 0 END GetIp; PROCEDURE opengpio(n:CARDINAL; out:BOOLEAN; VAR fnr:ARRAY OF CHAR):INTEGER; VAR h, hh, hp:ARRAY[0..99] OF CHAR; fd:INTEGER; tr:CARDINAL; BEGIN CardToStr(n, 1, h); hp:=GPIOX; (* /sys/class/gpio/gpio *) Append(hp, h); (* /sys/class/gpio/gpio *) hh:=hp; Append(hp, GPIODATA); (* /sys/class/gpio/gpio/value *) IF NOT out THEN Assign(fnr, hp) END; fd:=gpiofds[n]; IF fd=-2 THEN (* port is not open jet *) tr:=0; LOOP fd:=OpenWrite(GPIOUNEXPORT); (* /sys/class/gpio/unexport *) IF fd>=0 THEN EXIT END; usleep(100000); (* pray for udev junk is fast enough *) INC(tr); IF tr>4 THEN EXIT END; END; WrBin(fd, h, Length(h)); Close(fd); fd:=OpenWrite(GPIOEXPORT); (* /sys/class/gpio/export *) IF fd<0 THEN Error("cannot open gpio export") END; WrBin(fd, h, Length(h)); Close(fd); Append(hh, GPIODIRECTION); tr:=0; LOOP fd:=OpenWrite(hh); (* /sys/class/gpio/gpio *) IF fd>=0 THEN EXIT END; usleep(100000); (* pray for udev junk is fast enough *) INC(tr); IF tr>4 THEN EXIT END; END; IF fd<0 THEN Error("cannot open gpio direction") END; IF out THEN h:=GPIOOUT ELSE h:=GPIOIN END; WrBin(fd, h, Length(h)); (* in / out *) Close(fd); IF out THEN fd:=OpenRW(hp); IF fd<0 THEN Error("cannot open gpio value") END; ELSE fd:=-1 END; gpiofds[n]:=fd; END; RETURN fd END opengpio; PROCEDURE Wrchipnum(chip:pCHIP; nl:BOOLEAN); BEGIN IF chips^.next<>NIL THEN WrStr("chip:"); WrCard(chip^.num,1); IF nl THEN WrStrLn("") END; END; END Wrchipnum; PROCEDURE GetIp1(h:ARRAY OF CHAR; VAR ip:CARDINAL; VAR port:CARDINAL):INTEGER; CONST DEFAULTIP=7F000001H; PORTSEP=":"; VAR i, n, p: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 GetIp1; PROCEDURE Parms; VAR err:BOOLEAN; h,hh:ARRAY[0..4095] OF CHAR; ce0, miso0, mosi0, sck0, pcnt, txcnt, lptnum :CARDINAL; res :INTEGER; tx :pTXCONTEXT; chip :pCHIP; PROCEDURE chkports; VAR chip:pCHIP; ins, outs:GPIOSET; i:CARDINAL; BEGIN ins:=GPIOSET{}; outs:=GPIOSET{}; chip:=chips; WHILE chip<>NIL DO INCL(outs, chip^.gpio.mosiN); INCL(outs, chip^.gpio.sckN); IF chip^.gpio.misoN IN ins THEN Werr("hint, shared inputs need nss-pullup if driver is started for not all connected chips (floating nss pin)"+LF) END; INCL(ins, chip^.gpio.misoN); chip:=chip^.next; END; FOR i:=0 TO GPIOS-1 DO IF (i IN ins) & (i IN outs) THEN Error("input<->output port conflict") END; END; FOR i:=0 TO GPIOS-1 DO IF i IN ins THEN INCL(outs,i) END; END; chip:=chips; WHILE chip<>NIL DO IF chip^.gpio.ceN IN outs THEN Error("ce must not be shared") END; INCL(outs, chip^.gpio.ceN); chip:=chip^.next; END; END chkports; PROCEDURE autoopt(tx:pTXCONTEXT); BEGIN tx^.symboltime:=FLOAT(CAST(CARDINAL, SHIFT(SET32{0}, VAL(INTEGER, tx^.sf))))/BWTAB[tx^.bw]; tx^.optimize:=tx^.symboltime>16.0; IF tx^.cfgoptimize=0 THEN tx^.optimize:=FALSE ELSIF tx^.cfgoptimize=1 THEN tx^.optimize:=TRUE END; END autoopt; PROCEDURE rxautoopt(chp:pCHIP); BEGIN chp^.symboltime:=FLOAT(CAST(CARDINAL, SHIFT(SET32{0}, VAL(INTEGER, chp^.rxsf))))/BWTAB[chp^.rxbw]; chp^.optimize:=chp^.symboltime>16.0; IF chp^.cfgoptimize=0 THEN chp^.optimize:=FALSE ELSIF chp^.cfgoptimize=1 THEN chp^.optimize:=TRUE END; END rxautoopt; PROCEDURE newchip():pCHIP; VAR chp:pCHIP; BEGIN ALLOCATE(chp, SIZE(chp^)); IF chp=NIL THEN Error("out of memory") END; FILL(chp, 0C, SIZE(chp^)); chp^.lnaboost:=3; chp^.lnagain:=1; chp^.rxon:=FALSE; chp^.ppm:=0.0; chp^.datarate:=1000.0; chp^.rssicorr:=0; chp^.cfgocp:=-1; chp^.cfgramp:=-1; chp^.agc:=FALSE; chp^.rxmhz:=433.775; chp^.rxsf:=12; chp^.rxbw:=7; chp^.rxcr:=5; chp^.netid:=NETID; chp^.cfgoptimize:=-1; chp^.swapiq:=FALSE; chp^.preamblelimit:=250; RETURN chp END newchip; PROCEDURE storechip; VAR fn:ARRAY[0..99] OF CHAR; BEGIN WITH chip^.gpio DO ceN:=ce0; mosiN:=mosi0; misoN:=miso0; sckN:=sck0; <* IF __GEN_C__ THEN *> ceFD:=opengpio(ceN, TRUE, fn); mosiFD:=opengpio(mosiN, TRUE, fn); res:=opengpio(misoN, FALSE, misoFN); sckFD:=opengpio(sckN, TRUE, fn); <* END *> END; chip^.num:=pcnt; IF chip^.rxmhz<400.0 THEN chip^.band:=1 ELSIF chip^.rxmhz<500.0 THEN chip^.band:=2 ELSE chip^.band:=3 END; rxautoopt(chip); chip^.next:=chips; chips:=chip; chip:=newchip(); END storechip; PROCEDURE newtx():pTXCONTEXT; VAR tx:pTXCONTEXT; BEGIN ALLOCATE(tx, SIZE(tx^)); IF tx=NIL THEN Error("out of memory") END; FILL(tx, 0C, SIZE(tx^)); tx^.cfgoptimize:=-1; tx^.cfgramp:=-1; tx^.mhz:=433.775; tx^.sf:=12; tx^.bw:=7; tx^.cr:=5; tx^.netid:=NETID; tx^.power:=10; tx^.preamb:=8; tx^.txdel:=4; tx^.deviation:=3000; tx^.baud:=0; tx^.sendfsk:=FALSE; tx^.rawfsk:=FALSE; tx^.swapiq:=FALSE; tx^.rawlora:=FALSE; RETURN tx END newtx; PROCEDURE storetx; VAR t:pTXCONTEXT; BEGIN autoopt(tx); -- IF tx^.udpbind<>0 THEN tx^.next:=chip^.ptx; chip^.ptx:=tx; -- ELSE DEALLOCATE(tx, SIZE(tx^)); END; END storetx; BEGIN FOR pcnt:=0 TO HIGH(gpiofds) DO gpiofds[pcnt]:=-2 END; lptnum:=0; err:=FALSE; pcnt:=0; chips:=NIL; ce0:=8; mosi0:=10; miso0:=9; sck0:=11; loopdelay:=50000; loopdelayfast:=20000; chip:=NIL; tx:=newtx(); txcnt:=0; judpsock:=-1; judpport:=0; LOOP IF chip=NIL THEN chip:=newchip(); txcnt:=0; END; NextArg(h); IF h[0]=0C THEN EXIT END; IF (h[0]="-") & (h[1]<>0C) THEN IF h[1]="p" THEN IF pcnt>0 THEN storetx; storechip; tx:=newtx(); txcnt:=0; END; INC(pcnt); <* IF __GEN_C__ THEN *> NextArg(h); IF NOT StrToCard(h, ce0) OR (ce0>=GPIOS) THEN Error("-p ") END; NextArg(h); IF NOT StrToCard(h, mosi0) OR (mosi0>=GPIOS) THEN Error("-p ") END; NextArg(h); IF NOT StrToCard(h, miso0) OR (miso0>=GPIOS) THEN Error("-p ") END; NextArg(h); IF NOT StrToCard(h, sck0) OR (sck0>=GPIOS) THEN Error("-p ") END; <* ELSE *> NextArg(h); IF NOT StrToCard(h, lptnum) THEN Error("-p ") END; <* END *> ELSIF h[1]="l" THEN NextArg(h); IF NOT StrToCard(h, chip^.lnaboost) OR (chip^.lnaboost>3) THEN Error("-l ") END; ELSIF h[1]="u" THEN NextArg(h); IF NOT StrToCard(h, loopdelay) THEN Error("-u ") END; NextArg(h); IF NOT StrToCard(h, loopdelayfast) THEN Error("-u ") END; ELSIF h[1]="C" THEN NextArg(h); IF NOT StrToCard(h, tx^.cr) OR (tx^.cr<5) OR (tx^.cr>8) THEN Error("-C ") END; ELSIF h[1]="c" THEN NextArg(h); IF NOT StrToCard(h, chip^.rxcr) OR (chip^.rxcr<5) OR (chip^.rxcr>8) THEN Error("-c ") END; ELSIF h[1]="D" THEN NextArg(h); IF NOT StrToCard(h, tx^.deviation) OR (tx^.deviation>20000) THEN Error("-D ") END; ELSIF h[1]="s" THEN NextArg(h); IF NOT StrToInt(h, res) OR (ABS(res)<6) OR (ABS(res)>12) THEN Error("-s ") END; chip^.rxsf:=ABS(res); IF res<0 THEN chip^.swapiq:=TRUE END; ELSIF h[1]="S" THEN NextArg(h); IF NOT StrToInt(h, res) OR (ABS(res)<6) OR (ABS(res)>12) THEN Error("-S ") END; tx^.sf:=ABS(res); IF res<0 THEN tx^.swapiq:=TRUE END; ELSIF h[1]="n" THEN NextArg(h); IF NOT StrToHex(h, chip^.netid) THEN Error("-n ") END; ELSIF h[1]="N" THEN NextArg(h); IF NOT StrToHex(h, tx^.netid) THEN Error("-N ") END; ELSIF h[1]="g" THEN NextArg(h); IF NOT StrToCard(h, chip^.lnagain) OR (chip^.lnagain>6) OR (chip^.lnagain<1) THEN Error("-g ") END; ELSIF h[1]="T" THEN NextArg(h); IF NOT StrToCard(h, tx^.txdel) OR (tx^.txdel>100) THEN Error("-T (0..100)") END; ELSIF h[1]="H" THEN NextArg(h); IF NOT StrToCard(h, tx^.preamb) THEN Error("-H 9) THEN Error("-b 9) THEN Error("-B 17) THEN Error("-w 0 THEN storetx; tx:=newtx(); END; INC(txcnt); tx^.udp2:=h[1]<>"U"; (* switch on axudp2 *) NextArg(h); IF GetIp(h, tx^.udpip, tx^.udpport, tx^.udpbind, tx^.udpsocket, tx^.checkip)<0 THEN h:="cannot open udp socket port "; CardToStr(tx^.udpbind, 1, hh); Append(h, hh); Error(h); END; IF tx^.udpport<>0 THEN chip^.rxon:=TRUE END; ELSIF h[1]="v" THEN verb:=TRUE; ELSIF h[1]="V" THEN verb:=TRUE; verb2:=TRUE; ELSIF h[1]="a" THEN chip^.agc:=TRUE; ELSIF h[1]="E" THEN tx^.rawfsk:=TRUE; ELSIF h[1]="I" THEN tx^.implicit:=TRUE; ELSIF h[1]="i" THEN chip^.implicit:=TRUE; ELSIF h[1]="A" THEN tx^.sendfsk:=TRUE; ELSIF h[1]="d" THEN tx^.usedcd:=TRUE; ELSIF h[1]="Q" THEN tx^.swapiq:=TRUE; ELSIF h[1]="q" THEN chip^.swapiq:=TRUE; ELSIF h[1]="K" THEN tx^.rawlora:=TRUE; ELSIF h[1]="G" THEN NextArg(h); IF NOT StrToInt(h, tx^.baud) THEN Error("-G [-]") END; IF ABS(tx^.baud) 0..15") END; ELSIF h[1]="r" THEN NextArg(h); IF NOT StrToInt(h, chip^.rssicorr) THEN Error("-r ") END; ELSIF h[1]="Z" THEN NextArg(h); IF NOT StrToInt(h, chip^.cfgocp) THEN Error("-Z ") END; ELSIF h[1]="O" THEN NextArg(h); IF NOT StrToInt(h, tx^.cfgoptimize) THEN Error("-O <-1..1") END; ELSIF h[1]="o" THEN NextArg(h); IF NOT StrToInt(h, chip^.cfgoptimize) THEN Error("-o <-1..1") END; ELSIF h[1]="P" THEN NextArg(h); IF NOT StrToFix(chip^.ppm, h) OR (chip^.ppm<-133.0) OR (chip^.ppm>133.0) THEN Error("-P ") END; ELSIF h[1]="X" THEN NextArg(h); IF NOT StrToFix(chip^.datarate, h) OR (chip^.datarate<-133.0) OR (chip^.datarate>133.0) THEN Error("-X ") END; ELSIF h[1]="F" THEN NextArg(h); IF NOT StrToFix(tx^.mhz, h) OR (tx^.mhz<137.0) OR (tx^.mhz>1020.0) THEN Error("-F (137..1020)") END; ELSIF h[1]="f" THEN NextArg(h); IF NOT StrToFix(chip^.rxmhz, h) OR (chip^.rxmhz<137.0) OR (chip^.rxmhz>1020.0) THEN Error("-f (137..1020)") END; ELSIF h[1]="J" THEN NextArg(h); IF GetIp1(h, jipnum, judpport)<0 THEN Error("-J ip:port number") END; IF judpport<>0 THEN IF judpsock<0 THEN judpsock:=openudp() END; IF judpsock<0 THEN Error("cannot open udp socket") END; chip^.rxon:=TRUE; END; ELSIF h[1]="W" THEN NextArg(h); IF NOT StrToCard(h, chip^.preamblelimit) THEN Error("-W ") END; ELSIF h[1]="h" THEN WrStrLn(" ra-02 (sx127x) via LPT or multiple chips via GPIO to axudp or json by oe5dxl"); WrStrLn(" -A tx AFSK 1200 Baud"); WrStrLn(" -a AGC on"); WrStrLn(" -B tx bandwidth kHz 0:7.8 1:10.4 2:15.6 3:20.8 4:31.25 5:41.7 6:62.5 7:125 8:250 9:500 (7)"); WrStrLn(" -b rx bandwidth (7)"); WrStrLn(" -C tx coding rate 5..8 (5)"); WrStrLn(" -c rx coding rate 5..8 (5)"); WrStrLn(" -D (a)fsk deviation +-Hz (3000)"); WrStrLn(" -d do not send while DCD on this band or if dcd on tx sf/bw)"); WrStrLn(" timebase is detection duration, some ms see chip manual"); WrStrLn(" -E Send UDP frame unmodified in FSK up to 1500Byte eg. for POCSAG"); WrStrLn(" -F tx MHz (433.775) (137..1020)"); WrStrLn(" -f rx MHz (433.775) (137..1020)"); WrStrLn(" -G [-] Send GFSK -baud same but g3ruh scrambler off (490..250000)"); WrStrLn(" -g lna gain 6..1, 1 is maximum gain! see chip manual(1)"); WrStrLn(" -H Preamble length (8) sx seems to need minimum 4 (8)"); WrStrLn(" -h this"); WrStrLn(" -I tx implicit header on"); WrStrLn(" -i rx implicit header on"); WrStrLn(" -J send demodulated data(base64) with metadata in json"); WrStrLn(" -K tx unmodified axudp and split if too long, rx autodetect"); WrStrLn(" -L ip:sendport:listenport AXUDPv2 data, apply before all other parameters for this channel"); WrStrLn(" repeat for more tx contexts with different listen ports"); WrStrLn(" same rx data are sent to all non zero sendports"); WrStrLn(" -l lna boost 0..3, more for better ip3 by more supply current (3)"); WrStrLn(" -N network id tx (sync word) (not use 34=lorawan) (12)"); WrStrLn(" -n network id rx (sync word)) (12)"); WrStrLn(" -O 0 | 1 tx low datarate optimize 0=off 1=on else automatic (-1)"); WrStrLn(" -o 0 | 1 rx low datarate optimize 0=off 1=on else automatic (-1)"); WrStrLn(" -P x-tal correction +-128 (0.0), datarate correction may be overwritten by -X"); <* IF __GEN_C__ THEN *> WrStrLn(" -p GPIO numbers, apply before all parameter to this chip"); WrStrLn(" repeat for more chips (8 10 9 11)"); WrStrLn(" with different pins. Sharing needs high"); WrStrLn(" on not configed chips by pullup or setting nss-gpio high with other tools"); <* ELSE *> WrStrLn(" -p LPT port"); <* END *> WrStrLn(" -Q tx invert IQ (or give negative -S)"); WrStrLn(" -q rx invert IQ (or give negative -s)"); WrStrLn(" -R PaRamp how fast tx goes to power, see chip manual (9)"); WrStrLn(" -r add to rssi value to compensate internal and external preamps (0)"); WrStrLn(" -S tx spread factor 6..12 (12) -6..-12 for invers chirps same as -Q"); WrStrLn(" -s rx spread factor 6..12 (12) -6..-12 for invers chirps same as -q"); WrStrLn(" -T (A)FSK txdel in byte (4), not used for raw mode -E"); WrStrLn(" -U ip:sendport:receiveport AXUDP data, same as -L but standard AXUDP (no metadata)"); WrStrLn(" -u sleep time between device polls rx/(a)fsk tx, more:faster response, more cpu (50000 20000)"); WrStrLn(" afsk needs 20000 or less to avoid underruns"); WrStrLn(" -V show more infos on stdout"); WrStrLn(" -v show some infos on stdout"); WrStrLn(" -W limit rx preamble symbols against spoofing (250)"); WrStrLn(" -w tx power 0..17 (10)"); WrStrLn(" -X data rate correction (0)"); WrStrLn(" -Z set overcurrent protection, use with care, see chip manual"); WrStrLn(""); WrStrLn("ra02 -L 127.0.0.1:9000:9001 -d -r -10 -f 433.775 -w 17 -v"); WrStrLn("ra02 -p 8 10 9 11 -L 127.0.0.1:2400:2401 -P -2 -d -S 9 -B 6 -F 434.1 -f 433.775 -s 12 -b 7 -L 127.0.0.1:0:2400 -v"); WrStrLn("ra02 -P -L ... -L ... -P -L ... -L ... -v"); WrStrLn(""); HALT ELSE h[2]:=0C; Append(h, "? use -h"); Error(h) END; h[0]:=0C; ELSE h[1]:=0C; Append(h, "? use -h"); Error(h) END; END; IF (chips=NIL) OR (pcnt>0) THEN storetx; storechip; END; chkports; <* IF __GEN_C__ THEN *> <* ELSE *> CASE lptnum OF 0:BASE:=0378H; |1:BASE:=0278H; |2:BASE:=03BCH; ELSE WrStrLn("error: lpt 0..2"); HALT END; IF lpt.perm(BASE)<>0 THEN WrStrLn("lpt port nicht ansprechbar"); HALT END; WrStr(" lptbase="); WrHex(BASE, 2,0); WrStr(" lpt statusport liefert:"); WrHex(lpt.lptin(BASE+1), 2,0); WrStrLn(""); <* END *> chip:=chips; WHILE chip<>NIL DO WITH chip^ DO IF ABS(datarate)>133.0 THEN datarate:=ppm END; IF verb THEN Wrchipnum(chip, TRUE); WrStr("RX:"); tx:=ptx; txcnt:=0; WHILE tx<>NIL DO IF tx^.udpport<>0 THEN IF txcnt=0 THEN WrStr(" port=") ELSE WrStr(",") END; WrCard(tx^.udpport, 1); INC(txcnt); END; tx:=tx^.next; END; WrStr(" on="); WrCard(ORD(rxon),1); WrStr(" opt="); WrCard(ORD(optimize),1); WrStr(" agc="); WrCard(ORD(agc),1); WrStr(" f="); WrFixed(rxmhz, 4, 1); WrStr("MHz"); WrStr(" sf="); WrCard(rxsf, 1); WrStr(" bw="); WrFixed(BWTAB[rxbw],1,1); WrStr("kHz"); WrStr(" id="); WrHex(netid, 2,0); WrStr(" lnaboost="); WrCard(lnaboost, 1); IF swapiq THEN WrStr(" invertIQ") END; WrStr(" symt="); WrFixed(symboltime, 3, 1);WrStr("ms"); WrStr(" ppm="); WrFixed(ppm, 1, 1); WrStr(" dr="); WrFixed(datarate, 1, 1);WrStr("ppm"); WrStrLn(""); tx:=ptx; WHILE tx<>NIL DO IF tx^.udpbind<>0 THEN WrStr("TX:"); WrStr(" port="); WrCard(tx^.udpbind, 1); WrStr(" pwr="); WrCard(tx^.power, 1); WrStr("dBm"); WrStr(" f="); WrFixed(tx^.mhz, 4, 1); WrStr("MHz"); IF NOT tx^.rawfsk & NOT tx^.sendfsk THEN WrStr(" opt="); WrCard(ORD(tx^.optimize),1); WrStr(" imp="); WrCard(ORD(tx^.implicit),1); WrStr(" sf="); WrCard(tx^.sf, 1); WrStr(" cr="); WrCard(tx^.cr, 1); WrStr(" bw="); WrFixed(BWTAB[tx^.bw],1,1); WrStr("kHz"); WrStr(" id="); WrHex(tx^.netid, 2, 0); WrStr(" preamb="); WrFixed(tx^.symboltime*FLOAT(tx^.preamb), 2, 1);WrStr("ms"); IF tx^.swapiq THEN WrStr(" invertIQ") END; IF tx^.rawlora THEN WrStr(" rawdata") END; ELSE IF NOT tx^.rawfsk THEN WrStr(" txdel="); WrCard(tx^.txdel, 1); WrStr("byte"); IF tx^.baud=0 THEN WrStr(" baud=1200 AFSK"); ELSE WrStr("baud="); WrCard(ABS(tx^.baud), 1); IF tx^.baud<0 THEN WrStr(" FSK") ELSE WrStr(" g3ruh") END; END; ELSE WrStr(" baud="); WrCard(ABS(tx^.baud), 1); WrStr(" raw FSK") END; WrStr(" deviation+-="); WrCard(tx^.deviation, 1); END; WrStrLn(""); END; tx:=tx^.next; END; END; chip:=next; END; END; END Parms; PROCEDURE delay; BEGIN <* IF __GEN_C__ THEN *> -- usleep(20); <* ELSE *> <* END *> END delay; <* IF __GEN_C__ THEN *> PROCEDURE scp(gpio-:GPIO; rd, nss,sck, mosi:BOOLEAN):BOOLEAN; VAR h:ARRAY[0..1] OF CHAR; res:BOOLEAN; r, fd:INTEGER; BEGIN IF rd THEN fd:=OpenRead(gpio.misoFN); IF fd>=0 THEN r:=RdBin(fd, h, 1); Close(fd); res:=h[0]<>"0"; ELSE res:=FALSE END; ELSE res:=FALSE END; h[0]:=CHR(ORD("0")+ORD(sck)); WrBin(gpio.sckFD, h, 1); IF nss<>(gpio.ceN IN gpostate) THEN IF nss THEN h[0]:="1"; INCL(gpostate, gpio.ceN); ELSE h[0]:="0"; EXCL(gpostate, gpio.ceN); END; WrBin(gpio.ceFD, h, 1); END; IF mosi<>(gpio.mosiN IN gpostate) THEN IF mosi THEN h[0]:="1"; INCL(gpostate, gpio.mosiN); ELSE h[0]:="0"; EXCL(gpostate, gpio.mosiN); END; WrBin(gpio.mosiFD, h, 1); END; RETURN res END scp; <* ELSE *> PROCEDURE scp(gpio-:GPIO; rd, nss,sck, mosi:BOOLEAN):BOOLEAN; VAR res:BOOLEAN; BEGIN res:=FALSE; IF rd THEN res:=NOT ODD(lpt.lptin(BASE+1) DIV 64) END; lpt.lptout(BASE, ORD(NOT mosi)+ORD(NOT sck)*2+ORD(NOT nss)*4); RETURN res END scp; <* END *> PROCEDURE scpio(gpio-:GPIO; wr:BOOLEAN; a, len:CARDINAL; VAR s:ARRAY OF CHAR); (* send or receive a buffer *) VAR i, j, rd, d:CARDINAL; b:BOOLEAN; BEGIN j:=0; i:=16; WHILE j=CHR(32)) & (c0C DO b[p]:=CHR(ORD(s[i])<<0); INC(p); INC(i) END; b[p]:=" "; INC(p); END app; BEGIN IF chp^.rxon THEN IF len=0 THEN (* aprs *) mon2raw(mon, data, datalen); IF datalen>2 THEN DEC(datalen, 2); (* remove crc *) b[0]:=1C; b[1]:=CHR(30H); p:=2; app("T", VAL(INTEGER, txd)); app("V", VAL(INTEGER, lev)); app("S", VAL(INTEGER, snr)); app("A", VAL(INTEGER, afc)); b[p]:=0C; INC(p); (* end of axudp2 header *) i:=0; REPEAT b[p]:=data[i]; INC(p); INC(i); UNTIL VAL(INTEGER, i)>=datalen; AppCRC(b, p); tx:=chp^.ptx; WHILE tx<>NIL DO (* send rx data to all tx contexts *) IF tx^.udpport<>0 THEN ret:=udp.udpsend(tx^.udpsocket, b, p+2, tx^.udpport, tx^.udpip); END; tx:=tx^.next; (* prx next points to ptx table *) END; END; ELSE (* pr *) tx:=chp^.ptx; WHILE tx<>NIL DO (* send rx data to all tx contexts *) IF tx^.udpport<>0 THEN ret:=udp.udpsend(tx^.udpsocket, mon, len, tx^.udpport, tx^.udpip); END; tx:=tx^.next; (* prx next points to ptx table *) END; END; END; END sendaxudp2; PROCEDURE sendjson(jipnum:IPNUM; judpport:UDPPORT; id:CARDINAL; text-:ARRAY OF CHAR; dlen:CARDINAL; hascrc, crc, invert:BOOLEAN; sf, cr, txd, bwnum:CARDINAL; level:INTEGER; snr, jmhz:REAL; df:INTEGER); PROCEDURE b64(c:CARDINAL):CHAR; BEGIN c:=c MOD 64; IF c<26 THEN RETURN CHR(c+ORD("A")) ELSIF c<52 THEN RETURN CHR(c+(ORD("a")-26)) ELSIF c<62 THEN RETURN CHR(VAL(INTEGER, c)+(VAL(INTEGER,ORD("0"))-52)) ELSIF c=62 THEN RETURN "+" ELSE RETURN "/" END; END b64; PROCEDURE enc64(b, n:CARDINAL; VAR s:ARRAY OF CHAR); VAR i:CARDINAL; BEGIN FOR i:=n TO 2 DO b:=b*256 END; s[2]:="="; s[3]:="="; s[4]:=0C; s[0]:=b64(b DIV 40000H); s[1]:=b64(b DIV 1000H); IF n>=2 THEN s[2]:=b64(b DIV 40H) END; IF n=3 THEN s[3]:=b64(b) END; END enc64; VAR s,h:ARRAY[0..999] OF CHAR; ret:INTEGER; i,b:CARDINAL; BEGIN s:="{"; Append(s, '"net":'); IntToStr(id, 1, h); Append(s, h); Append(s, ',"crc":'); IntToStr(VAL(INTEGER, ORD(hascrc)+ORD(crc))-1, 1, h); Append(s, h); Append(s, ',"invers":'); IntToStr(ORD(invert), 1, h); Append(s, h); Append(s, ',"bw":'); FixToStr(BWTAB[bwnum]*1000.0, 2, h); Append(s, h); Append(s, ',"sf":'); IntToStr(sf, 1, h); Append(s, h); Append(s, ',"cr":'); IntToStr(cr, 1, h); Append(s, h); Append(s, ',"preamb":'); IntToStr(txd, 1, h); Append(s, h); -- Append(s, ',"duration":'); IntToStr(frametime, 1, h); Append(s, h); Append(s, ',"level":'); IntToStr(level, 1, h); Append(s, h); Append(s, ',"afc":'); IntToStr(df, 1, h); Append(s, h); -- Append(s, ',"nfloor":'); FixToStr(n, 2, h); Append(s, h); Append(s, ',"snr":'); FixToStr(snr, 2, h); Append(s, h); IF jmhz<>0.0 THEN Append(s, ',"rxmhz":'); FixToStr(jmhz+0.0005, 4, h); Append(s, h) END; Append(s, ',"ver":"sx"'); Append(s, ',"payload":"'); b:=0; i:=0; WHILE i0 THEN enc64(b, i MOD 3, h); Append(s, h) END; Append(s, '"}'+LF); (* IF jpipename[0]<>0C THEN IF jsonfd<0 THEN jsonfd:=OpenNONBLOCK(jpipename); IF jsonfd<0 THEN jsonfd:=OpenWrite(jpipename) 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; *) IF judpport<>0 THEN ret:=udpsend(judpsock, s, Length(s), judpport, jipnum) END; END sendjson; PROCEDURE hdlc(VAR b:ARRAY OF CHAR; len, txdel:INTEGER; VAR h:ARRAY OF CHAR; VAR hlen:CARDINAL; fsk, scramb, notxd:BOOLEAN; VAR scrambler:SET32); VAR st,stuff,bitc, obc, sc, dds:CARDINAL; p:INTEGER; c:CARD16; nrzi, dostuff:BOOLEAN; BEGIN nrzi:=FALSE; bitc:=0; IF notxd THEN p:=-2 ELSE p:=-VAL(INTEGER, txdel) END; stuff:=0; dostuff:=FALSE; obc:=0; hlen:=0; dds:=0; REPEAT IF stuff>=5 THEN nrzi:=NOT nrzi; (* stuffbit *) stuff:=0; ELSE IF bitc=0 THEN dostuff:=(p>=0) & (p ((12 IN scrambler) <> (17 IN scrambler)) THEN INCL(scrambler, 0) END; ELSIF nrzi THEN INCL(scrambler, 0) END; h[hlen]:=CHR(ORD(h[hlen])*2+ORD(0 IN scrambler)); INC(obc); IF obc>7 THEN obc:=0; INC(hlen) END; END; ELSE FOR sc:=0 TO OVERSAMP-1 DO IF hlen=32768*65536)); INC(obc); IF obc>7 THEN obc:=0; INC(hlen) END; END; END; END; -- store nrzi bit UNTIL (p>len+1) & (obc=0) (*+2*VAL(INTEGER,ORD(scramb))*); (* trailing flags *) --WrStrLn(""); FOR p:=0 TO VAL(INTEGER,hlen) DO WrHex(ORD(h[p]),2,0) END; WrStrLn(""); END hdlc; PROCEDURE showbits(b-:ARRAY OF CHAR; len:INTEGER); VAR i, j:INTEGER; BEGIN IF len>5 THEN len:=3 END; FOR i:=0 TO len-1 DO FOR j:=7 TO 0 BY -1 DO WrInt(ORD(j IN CAST(SET8, b[i])), 1) END; END; END showbits; PROCEDURE decodejson(VAR b:ARRAY OF CHAR; VAR bl:INTEGER); (* {"payload":"base64..."} *) PROCEDURE cmp(a,b:CARDINAL; h-,w-:ARRAY OF CHAR):BOOLEAN; VAR i:CARDINAL; BEGIN i:=0; LOOP IF (i>HIGH(w)) OR (w[i]=0C) THEN RETURN a>=b END; IF (a>=b) OR (w[i]<>h[a]) THEN RETURN FALSE END; INC(i); INC(a); END; END cmp; PROCEDURE d64(c:CHAR):CARDINAL; BEGIN IF c="=" THEN RETURN 64 END; IF c="+" THEN RETURN 62 END; IF c="/" THEN RETURN 63 END; IF (c>="0") & (c<="9") THEN RETURN ORD(c)+52-ORD("0") END; IF (c>="A") & (c<="Z") THEN RETURN ORD(c)-ORD("A") END; IF (c>="a") & (c<="z") THEN RETURN ORD(c)+26-ORD("a") END; RETURN 255 END d64; VAR p, a, len:CARDINAL; c, w, wp, wh:CARDINAL; BEGIN len:=bl; IF (len>=2) & (b[0]="{") THEN p:=1; WHILE b[p]=" " DO INC(p); IF p>len THEN RETURN END; END; IF (b[p]='"') THEN INC(p); IF p>len THEN RETURN END; a:=p; WHILE (b[p]>=" ") & (b[p]<>'"') DO INC(p); IF p>len THEN RETURN END; END; IF b[p]<>'"' THEN RETURN END; IF cmp(a,p,b,"payload") THEN bl:=0; INC(p); IF p>len THEN RETURN END; WHILE b[p]=" " DO INC(p); IF p>len THEN RETURN END; END; IF b[p]<>':' THEN RETURN END; INC(p); IF p>len THEN RETURN END; WHILE b[p]=" " DO INC(p); IF p>len THEN RETURN END; END; IF b[p]<>'"' THEN RETURN END; INC(p); IF p>len THEN RETURN END; a:=0; wp:=0; WHILE b[p]<>'"' DO c:=d64(b[p]); IF c=255 THEN RETURN END; IF c<64 THEN w:=w*64+c; INC(a) END; IF (c=64) OR (a>=4) THEN IF a=2 THEN w:=w DIV 16 ELSIF a=3 THEN w:=w DIV 4 END; IF a>=2 THEN DEC(a); INC(wp, a); wh:=wp-1; REPEAT b[wh]:=CHR(w MOD 256); w:=w DIV 256; DEC(wh); DEC(a); UNTIL a=0; a:=0; END; END; INC(p); IF p>len THEN RETURN END; END; INC(p); IF p>len THEN RETURN END; WHILE b[p]=" " DO INC(p); IF p>len THEN RETURN END; END; IF (b[p]='}') THEN bl:=wp END; END; END; END; END decodejson; PROCEDURE getaxudp2(chp:pCHIP); VAR fromport :UDPPORT; ip :IPNUM; crc1, crc2:CHAR; len :INTEGER; slen :CARDINAL; rb, showtext :ARRAY[0..1500] OF CHAR; udp2 :ARRAY[0..63] OF CHAR; (* axudp2 header *) ok, cont :BOOLEAN; i :CARDINAL; BEGIN cont:=chp^.atx<>NIL; IF NOT cont THEN chp^.atx:=chp^.ptx END; (* look for data on all tx *) len:=0; LOOP IF chp^.atx=NIL THEN RETURN END; IF chp^.atx^.udpbind<>0 THEN (* IF chp^.atx^.splitlen>0 THEN (* rawlora frame splitted, send part 2 *) len:=0; FOR i:=255 TO chp^.atx^.splitlen-1 DO rb[len]:=chp^.atx^.ftext[i]; INC(len); END; chp^.atx^.splitlen:=0; split:=TRUE; ELSIF chp^.atx^.ftextlen=0 THEN *) IF chp^.atx^.ftextlen=0 THEN (* buffer is sent complete *) len:=udp.udpreceive(chp^.atx^.udpsocket, rb, SIZE(rb), fromport, ip); IF len>0 THEN EXIT END; (* found udp for a tx context *) END; END; IF cont THEN chp^.atx:=NIL; RETURN ELSE chp^.atx:=chp^.atx^.next END; END; WITH chp^ DO ok:=FALSE; atx^.ftextlen:=0; decodejson(rb, len); IF (len>=2) & (len2) THEN WrStr("UDP:"); ShowFrame(ftext, ftextlen-2, CHR(chp^.num+ORD("0"))) END; IF rawlora & (ftextlen>=255) & (ftextlen+20 THEN DEC(ftextlen) END; (* remove cr *) WHILE (slen<=HIGH(showtext)) & (slen0, atx^.baud>0, cont, scrambler); END; ok:=ftextlen>2; END; IF verb THEN Wrchipnum(chp, FALSE); IF sendfsk THEN IF atx^.baud<>0 THEN IF rawfsk THEN WrStr(" tx raw fsk:["); showbits(ftext, ftextlen); WrStr("...] "); ELSIF atx^.baud>0 THEN WrStr(" tx g3ruh:"); ELSE WrStr(" tx hdlc fsk:") END; WrCard(ABS(atx^.baud),1); WrStr("Bd"); ELSE WrStr(" tx afsk:") END; ELSE WrStr(" tx:") END; WrStr(" port:"); WrCard(atx^.udpbind, 1); WrStr(" f:"); WrFixed(atx^.mhz, 4, 1); IF slen>2 THEN WrStr(" [");WrBytes(showtext, slen); WrStrLn("]"); ELSE WrStrLn("") END; END; END; ELSIF verb THEN WrStrLn(" axudp crc error "); END; END; IF ok THEN atx^.fskp:=0 ELSE atx:=NIL END; (* not decodable axudp *) END; END getaxudp2; PROCEDURE setsynth(chp:pCHIP; mhz:REAL); VAR synt:CARDINAL; BEGIN mhz:=mhz+mhz*chp^.ppm*0.000001; synt:=TRUNC(mhz*16384.0 + 0.5); scpo(chp^.gpio, RegFrMsb,synt DIV 65536); (* freq high *) scpo(chp^.gpio, RegFrMid,synt DIV 256 MOD 256); (* freq mid *) scpo(chp^.gpio, RegFrLsb,synt MOD 256); (* freq low *) END setsynth; PROCEDURE Setmode(chp:pCHIP; m:CARDINAL; check, tx:BOOLEAN); VAR n:CARDINAL; BEGIN IF tx & (chp^.atx<>NIL) THEN m:=m+8*ORD(chp^.atx^.mhz<=779.0) ELSE m:=m+8*ORD(chp^.rxmhz<=779.0) END; n:=0; LOOP scpo(chp^.gpio, RegOpMode, m); IF NOT check OR (scpi(chp^.gpio, RegOpMode)=m) THEN EXIT END; usleep(1000); INC(n); IF n MOD 256=0 THEN Wrchipnum(chp, FALSE); WrStr(" try set mode:");WrHex(m,2,0); WrStr(" chip has:");WrHex(scpi(chp^.gpio, RegOpMode),2,0); WrStrLn(""); END; END; END Setmode; PROCEDURE startfsk(chp:pCHIP); VAR i, bd, len, pow:CARDINAL; b:ARRAY[0..500] OF CHAR; BEGIN (* IF verb THEN Wrchipnum(chp, FALSE); WrStr(" afsk: port:"); WrCard(chp^.atx^.udpbind, 1); WrStr(" f:"); WrFixed(chp^.atx^.mhz, 4, 1); END; *) setsynth(chp, chp^.atx^.mhz); Setmode(chp, 0, TRUE, TRUE); (* sleep *) --Setmode(chp, 3, TRUE); --usleep(100000); Setmode(chp, 4, TRUE, TRUE); (* rx to clear fifo *) Setmode(chp, 0, TRUE, TRUE); (* sleep *) pow:=chp^.atx^.power; IF chp^.boost THEN -- IF pow=20 THEN scpo(chp^.gpio, RegPaDac,7) END; (* 20dBm switch send time too long*) IF pow>17 THEN pow:=17 ELSIF pow<2 THEN pow:=2 END; DEC(pow,2); ELSIF pow>15 THEN pow:=15 END; scpo(chp^.gpio, RegPaConfig,80H+16*7+pow); (* tx power *) scpo(chp^.gpio, RegPaRamp, 29H+40H*ORD(chp^.atx^.baud=0)); (* baseband lowpass 0.3B on afsk, pa ramp *) -- scpo(chp^.gpio, RegPllHf, CAST(CARDINAL, CAST(SET32, scpi(chp^.gpio, RegPllHf))*SET32{0..5})); (* 75khz pll bandwidth *) IF chp^.atx^.baud<>0 THEN bd:=TRUNC(XTAL)*16 DIV VAL(CARDINAL, ABS(chp^.atx^.baud)); ELSE bd:=TRUNC(XTAL)*16 DIV AFSKBAUD END; scpo(chp^.gpio, RegBitrateMsb, bd DIV (16*256)); scpo(chp^.gpio, RegBitrateLsb, bd DIV 16 MOD 256); scpo(chp^.gpio, RegBitrateFrac, bd MOD 16); bd:=chp^.atx^.deviation DIV TRUNC(FSTEP+0.5); scpo(chp^.gpio, RegFdevMsb, bd DIV 256); scpo(chp^.gpio, RegFdevLsb, bd MOD 256); scpo(chp^.gpio, RegPreampleMsb, 0H); scpo(chp^.gpio, RegPreampleLsb, 0H); scpo(chp^.gpio, RegSyncConfig, 0H); scpo(chp^.gpio, RegPacketConfig1, 0H); scpo(chp^.gpio, RegPacketConfig2, 40H); (*40H*) scpo(chp^.gpio, RegPayloadLengthFsk, 0H); bd:=64-FIFOFILL; IF bd>=chp^.atx^.ftextlen THEN bd:=chp^.atx^.ftextlen-1 END; (* fifo start tx threshold *) scpo(chp^.gpio, RegFifoThresh, bd); --chp^.atx^.fskp:=0; --WrStrLn(""); FOR i:=0 TO 3FH DO WrHex(scpi(chp^.gpio, i), 3) END; WrStrLn(""); --scpo(chp^.gpio, RegOpMode,3); (* use if sequencer dead *) --REPEAT WrHex(scpi(chp^.gpio, RegIrqFlags1),1) UNTIL scpi(chp^.gpio, RegIrqFlags1)>=128; (* mode ready *) --WrHex(scpi(chp^.gpio, RegSeqConfig1),3);WrStrLn("=seq"); -- scpo(chp^.gpio, RegSeqConfig1, 0B8H); (*B8*) (* start sequencer tx on fifo thres *) --WrHex(scpi(chp^.gpio, RegSeqConfig1),3);WrStrLn("=seq"); scpo(chp^.gpio, RegSeqConfig1, 0B8H); (*B8*) (* start sequencer tx on fifo thres *) END startfsk; PROCEDURE setppm(chp:pCHIP); VAR p:REAL; BEGIN p:=chp^.ppm; IF chp^.datarate<>0.0 THEN p:=chp^.datarate END; --WrInt(VAL(INT8, p*0.95+0.5), 1); WrStrLn(" = datarate"); scpo(chp^.gpio, 27H, VAL(INT8, p*0.95+0.5)); (* datarate correction *) END setppm; PROCEDURE startrx(chp:pCHIP; dcdonly:BOOLEAN); VAR synth, bw, sf, id:CARDINAL; BEGIN WITH chp^ DO bw:=rxbw; sf:=rxsf; id:=netid; IF dcdonly THEN (* look where we want to send next *) bw:=atx^.bw; sf:=atx^.sf; id:=atx^.netid; END; Setmode(chp, 80H, TRUE, FALSE); scpo(gpio, RegModemConfig1,16*bw+2*(5-4)+ORD(chp^.implicit)); (* bw cr explizit *) scpo(gpio, RegLna,32*(chp^.lnagain MOD 8) + 8*(lnaboost MOD 4)); (* lna gain, current *) Setmode(chp, 80H, FALSE, FALSE); (* sleep *) scpo(gpio, RegModemConfig2, sf*16+4); (* spread factor + crc on *) scpo(gpio, RegModemConfig3,ORD(agc)*4+ORD(optimize)*8); (* agc txoptimize *) scpo(gpio, RegDetectOptimice,03H+2*ORD(sf=6)); (* rxoptimize 3, on sf=6 5 *) scpo(gpio, RegDetectionThreshold,0AH+2*ORD(sf=6)); scpo(gpio, RegSyncWord, id); (* syncword *) scpo(chp^.gpio, RegPreambleMsb, chp^.preamblelimit DIV 256); (* rx preamble limir *) scpo(chp^.gpio, RegPreambleLsb, chp^.preamblelimit MOD 256); (* rx preamble limit *) IF swapiq THEN scpo(gpio, RegInvertIQ, CAST(CARDINAL, CAST(SET32, scpi(gpio, RegInvertIQ))+SET32{6})); scpo(gpio, RegInvertIQ2, 19H); ELSE scpo(gpio, RegInvertIQ, CAST(CARDINAL, CAST(SET32, scpi(gpio, RegInvertIQ))*SET32{0..5,7})); scpo(gpio, RegInvertIQ2, 1DH); END; IF chp^.rxbw=9 THEN (* 500khz optimize *) IF chp^.rxmhz<=779.0 THEN scpo(gpio, RegHighBwOptimize1, 02H); scpo(gpio, RegHighBwOptimize2, 7FH); ELSE scpo(gpio, RegHighBwOptimize1, 02H); scpo(gpio, RegHighBwOptimize2, 64H); END; ELSE scpo(gpio, RegHighBwOptimize1, 03H) END; setsynth(chp, rxmhz); Setmode(chp, 80H+5+2*ORD(dcdonly), FALSE,FALSE); (* continous rx or dcd detect *) END; END startrx; PROCEDURE send(chp:pCHIP); VAR i, j, len, pow:CARDINAL; b:ARRAY[0..500] OF CHAR; BEGIN Setmode(chp, 81H, TRUE, FALSE); IF chp^.cfgocp>=0 THEN scpo(chp^.gpio, RegOcp, chp^.cfgocp MOD 32) END; (* set overcurrent protect *) setsynth(chp, chp^.atx^.mhz); pow:=chp^.atx^.power; IF chp^.boost THEN -- IF pow=20 THEN scpo(chp^.gpio, RegPaDac,7) END; (* 20dBm switch send time too long*) IF pow>17 THEN pow:=17 ELSIF pow<2 THEN pow:=2 END; DEC(pow,2); ELSIF pow>15 THEN pow:=15 END; scpo(chp^.gpio, RegPaConfig,80H+16*7+pow); (* tx power *) IF chp^.cfgramp>=0 THEN scpo(chp^.gpio, RegPaRamp,chp^.cfgramp MOD 16) END; (* pa ramp *) scpo(chp^.gpio, RegModemConfig1,16*chp^.atx^.bw+2*(chp^.atx^.cr-4)+ORD(chp^.atx^.implicit)); (* bw cr explizit *) scpo(chp^.gpio, RegModemConfig2, chp^.atx^.sf*16+4); (* spread factor + crc on *) scpo(chp^.gpio, RegModemConfig3,ORD(chp^.agc)*4+ORD(chp^.atx^.optimize)*8); (* agc txoptimize *) scpo(chp^.gpio, RegPreambleMsb, chp^.atx^.preamb DIV 256); (* preamble length *) scpo(chp^.gpio, RegPreambleLsb, chp^.atx^.preamb MOD 256); (* preamble length *) scpo(chp^.gpio, RegSyncWord, chp^.atx^.netid); (* syncword *) IF chp^.atx^.swapiq THEN scpo(chp^.gpio, RegInvertIQ, CAST(CARDINAL, CAST(SET32, scpi(chp^.gpio, RegInvertIQ))*SET32{1..7})); ELSE scpo(chp^.gpio, RegInvertIQ, CAST(CARDINAL, CAST(SET32, scpi(chp^.gpio, RegInvertIQ))+SET32{0})); END; --scpo(chp^.gpio, RegInvertIQ, 27H); --WrHex(scpi(chp^.gpio, RegInvertIQ), 5); WrStrLn("=inv"); len:=0; IF NOT chp^.atx^.rawlora THEN b[0]:=CHR(3CH); (* for whatever *) b[1]:=CHR(0FFH); (* for whatever *) b[2]:=CHR(1); (* for whatever *) len:=3; END; i:=0; j:=chp^.atx^.ftextlen; IF j>255 THEN j:=255; IF NOT chp^.atx^.rawlora & verb THEN WrStrLn("---packet length stripped to 255") END; END; WHILE (i255) THEN (*second part of split frame *) IF verb THEN WrStrLn("send split frame part 1"); chp^.atx^.verbpart2:=TRUE; (* for verb only *) END; FOR i:=255 TO chp^.atx^.ftextlen-1 DO chp^.atx^.ftext[i-255]:=chp^.atx^.ftext[i] END; DEC(chp^.atx^.ftextlen, 255); ELSE chp^.atx^.ftextlen:=0 END; (* all data sent *) --IF verb THEN WrStr(" [");WrBytes(b, len); WrStrLn("]") END; scpo(chp^.gpio, RegPayloadLength,len); (* payload length *) scpo(chp^.gpio, RegFifoAddrPtr,scpi(chp^.gpio, RegFifoTxBaseAddr)); (* write pointer *) scpio(chp^.gpio, TRUE,RegFifo,len,b); scpo(chp^.gpio, RegIrqFlags,0FFH); (* clear all irq *) Setmode(chp, 80H+3, TRUE, TRUE); (* transmit *) END send; PROCEDURE txfill(chp:pCHIP); VAR b:ARRAY[0..FIFOFILL-1] OF CHAR; f:CARDINAL; r,i:INTEGER; BEGIN IF chp^.atx<>NIL THEN LOOP f:=scpi(chp^.gpio, RegIrqFlags2); --WrHex(f,1); WrStr("=f "); IF 5 IN CAST(SET8, f) THEN EXIT END; (* full, not refill fifo *) IF (chp^.atx^.fskp<>0) & (6 IN CAST(SET8, f)) THEN EXIT END; (* underrun or fifo out *) LOOP r:=VAL(INTEGER,chp^.atx^.ftextlen)-chp^.atx^.fskp; IF r>0 THEN EXIT END; (* out of data *) chp^.atx^.ftextlen:=0; getaxudp2(chp); (* more data as tx is on *) IF chp^.atx=NIL THEN EXIT END; END; IF r<=0 THEN EXIT END; IF r>FIFOFILL THEN r:=FIFOFILL END; FOR i:=0 TO r-1 DO b[i]:=chp^.atx^.ftext[chp^.atx^.fskp]; INC(chp^.atx^.fskp); END; scpio(chp^.gpio, TRUE,RegFifo, r, b); --WrStr("+"); END; END; END txfill; PROCEDURE startdcdcheck(chip:pCHIP); BEGIN scpo(chip^.gpio, RegIrqFlags, 0FFH); startrx(chip, TRUE); (* start dcd detect on tx mhz/mod *) IF verb2 THEN WrStr("start cad ");WrFixed(chip^.atx^.mhz,3,1); WrStrLn(""); END; END startdcdcheck; PROCEDURE dcddone(chip:pCHIP; VAR dcd:BOOLEAN):BOOLEAN; BEGIN IF NOT (2 IN CAST(SET8, scpi(chip^.gpio, RegIrqFlags))) THEN RETURN FALSE END; (* cad not done *) dcd:=0 IN CAST(SET8, scpi(chip^.gpio, RegIrqFlags)); IF verb2 THEN WrCard(ORD(dcd),1); WrStrLn(" cad done"); END; RETURN TRUE END dcddone; PROCEDURE showv2(chip:pCHIP; bandmap:SET8); BEGIN Wrchipnum(chip, FALSE); WrStr(" st:"); WrHex(scpi(chip^.gpio, RegOpMode),2,0); WrStr(" cnt:");WrInt(scpi(chip^.gpio, RegRxPacketCntValueLsb), 1); WrStr(" rssi:");WrInt(scpi(chip^.gpio, RegRssiValue), 1); WrStr(" stat:"); WrHex(scpi(chip^.gpio, RegModemStat), 2,0); WrStr(" flags:");WrHex(scpi(chip^.gpio, RegIrqFlags), 2,0); WrStr(" state:");WrCard(ORD(chip^.state),1); WrStr(" dcd:");WrCard(CAST(CARD8, bandmap),1); IF chip^.atx<>NIL THEN WrStr(" atx "); WrInt(chip^.atx^.ftextlen,1); WrStr("Bytes "); END; WrStrLn(""); END showv2; PROCEDURE chkpr(raw:ARRAY OF CHAR; rawlen:CARDINAL; VAR pr:ARRAY OF CHAR; VAR prlen:CARDINAL; VAR part2:BOOLEAN):BOOLEAN; (* try to find out if pr frame or lora *) VAR i:CARDINAL; BEGIN IF part2 THEN (* second part *) part2:=FALSE; AppCRC(raw, rawlen); IF (pr[253]=raw[rawlen]) & (pr[254]=raw[rawlen+1]) THEN (* join crc fits *) FOR i:=0 TO rawlen-1 DO pr[i+253]:=raw[i] END; (* append second part *) prlen:=rawlen+253; --IF verb THEN WrStr("pr part 2 join ok len="); WrInt(prlen,1); WrStrLn(""); END; RETURN TRUE END; (* so tread this frame as part 1 *) --IF verb THEN WrStrLn("pr part 2 join hash missmatch") END; END; i:=0; WHILE (i=13) & (i<=69) THEN (* is pr, not 2 to 10 shift up calls *) --IF verb THEN WrStr("pr part 1 len="); WrInt(rawlen,1); WrStrLn("") END; prlen:=rawlen; FOR i:=0 TO 254 DO pr[i]:=raw[i] END; IF rawlen<255 THEN RETURN TRUE END; (* pr ready *) (* split pr part 1 *) part2:=TRUE; (* next frame may be second part *) prlen:=0; (* not complete now *) RETURN TRUE END; (* not 2 to 10 shift up calls so not pr frame *) part2:=FALSE; prlen:=0; RETURN FALSE END chkpr; PROCEDURE decodemeshcom4(text-:ARRAY OF CHAR; textlen:CARDINAL):BOOLEAN; (* MESHCOM4 *) VAR i, te:CARDINAL; c:CHAR; BEGIN IF verb THEN ---fcs i:=0; te:=0; WHILE (te+20C)) DO INC(i, ORD(text[te])); INC(te) END; INC(i, ORD(text[te+1])); INC(i, ORD(text[te+2])); ---fcs (* WrStr("Meshcom4: FCS:"); IF i=ORD(text[te+3])*256 + ORD(text[te+4]) THEN WrStr("Ok") ELSE WrStr("ERROR") END; *) IF i=ORD(text[te+3])*256 + ORD(text[te+4]) THEN (* FCS ok *) WrStr("Meshcom4: FCS:Ok MID="); WrHex(ORD(text[1])+ORD(text[2])*100H+ORD(text[3])*10000H+ORD(text[4])*1000000H,8,0); WrStr(" MAX-HOP="); WrCard(ORD(text[5]) MOD 8,1); IF 7 IN CAST(SET8, text[5]) THEN WrStr(" viaMQTT") END; IF 6 IN CAST(SET8, text[5]) THEN WrStr(" +Traceroute") END; IF te+2<=textlen THEN WrStr(" HW-ID="); WrCard(ORD(text[te+1]),1); WrStr(" MOD="); WrCard(ORD(text[te+2]),1); END; IF te+6=80000H THEN ferr:=ferr-100000H END; afchz:=VAL(INTEGER, VAL(REAL,ferr)*(16777216.0/250.0/XTAL)*BWTAB[chip^.rxbw]*chip^.rxmhz*(0.001/0.95)); syncw:=scpi(chip^.gpio, RegSyncWord); snr:=CAST(INT8, scpi(chip^.gpio, RegPktSnrValue)) DIV 4; level:=snr+VAL(INTEGER, scpi(chip^.gpio, RegPacketRssi))-164; INC(level, chip^.rssicorr); scpo(chip^.gpio, RegFifoAddrPtr, scpi(chip^.gpio, RegFifoRxCurrentAddr)); len:=scpi(chip^.gpio, RegRxNbBytes); cr:=scpi(chip^.gpio, RegModemStat) DIV 32+4; IF verb THEN TimeToStr(time() MOD 86400, s); WrStr(s); WrStr(" "); Wrchipnum(chip,FALSE); IF hascrc THEN IF crcvalid THEN WrStr(" crc:ok") ELSE WrStr(" crc:err") END; ELSE WrStr(" crc:none") END; WrStr(" txd:"); WrCard(chip^.rxtxdel,1); WrStr(" df:");WrInt(afchz,1); WrStr(" net: ");WrHex(syncw, 2,0); WrStr(" ih/crc:");WrInt(ORD(rximplicit),1);WrInt(ORD(hascrc),1); WrStr(" rssi:");WrInt(level, 1); WrStr(" snr:");WrInt(snr, 1); WrStr(" cr:");WrInt(cr, 1); WrStr(" len:"); WrInt(len, 1); WrStrLn(""); END; IF (len>0) & (len255) OR (chip^.netid=syncw) THEN IF chkpr(h, len, chip^.splitb, prlen, chip^.issplit) THEN (* look if is pr and reassemble split frames *) IF hascrc & crcvalid THEN sendaxudp2(chip, chip^.splitb, prlen, chip^.rxtxdel, level, snr, afchz); (* pr frame ready *) END; IF verb & (prlen>2) THEN WrStr("LORA:"); ShowFrame(chip^.splitb, prlen-2, CHR(chip^.num+ORD("0"))); END; ELSIF hascrc & crcvalid (*& (chip^.netid=2BH)*) & (h[0]="!") & decodemeshcom4(h, len) THEN (* meshcom4 *) ELSE (* aprs *) FOR i:=0 TO len-1 DO IF (i>=3) & (i3 THEN hx[len-3]:=0C; IF hx[len-4]0 THEN sendjson(jipnum, judpport, syncw, h, len, hascrc, crcvalid, chip^.swapiq, chip^.rxsf, cr, chip^.rxtxdel, chip^.rxbw, level, FLOAT(snr), chip^.rxmhz, afchz); END; ELSIF verb THEN WrStrLn(""); WrStr("packet filtert, wrong sync word received="); WrHex(syncw,2,0); WrStr(" filter="); WrHex(chip^.netid, 2,0); END; -- END; IF verb THEN WrStrLn("") END; ELSIF verb THEN WrStrLn("zero len data") END; scpo(chip^.gpio, RegIrqFlags,255); Setmode(chip, 80H+5, FALSE, FALSE); (* rx continous *) ELSIF verb THEN Wrchipnum(chip,FALSE); WrStrLn(" implicit header") END; END rx; (* PROCEDURE calibrate(chp:pCHIP); VAR r:SET32; cur:CARDINAL; BEGIN cur:=scpi(chp^.gpio, RegOpMode); scpo(chp^.gpio, RegOpMode, 80H); (* sleep *) scpo(chp^.gpio, RegOpMode, 00H); (* fsk sleep *) scpo(chp^.gpio, RegOpMode, 4H); (* FSR *) usleep(500); -- scpo(chp^.gpio, RegImageCal, CALMASK+1); -- usleep(500); -- IF verb THEN WrStr("temp:"); WrInt(20-CAST(INT8, scpi(chp^.gpio, RegTemp)),1); WrStrLn("deg"); END; scpo(chp^.gpio, RegImageCal, CALMASK); r:=CAST(SET32, scpi(chp^.gpio, RegImageCal)); IF 3 IN r THEN (* temperature change occured *) scpo(chp^.gpio, RegOpMode, 1); (* fsk standby *) IF verb THEN WrStr("calibration ") END; INCL(r, 6); (* trigger calibration *) scpo(chp^.gpio, RegImageCal, CAST(CARDINAL,r)); REPEAT (* wait until done *) usleep(1000); IF verb THEN WrStr(".") END; UNTIL NOT (5 IN CAST(SET32, scpi(chp^.gpio, RegImageCal))); IF verb THEN WrStrLn(" done") END; END; scpo(chp^.gpio, RegOpMode, 80H); (* sleep *) scpo(chp^.gpio, RegOpMode, 84H); (* sleep *) scpo(chp^.gpio, RegOpMode, cur); END calibrate; *) <* IF __GEN_C__ THEN *> PROCEDURE ["C"] freegpio(signum:INTEGER); VAR i:CARDINAL; h:ARRAY[0..1] OF CHAR; fd:INTEGER; BEGIN FOR i:=0 TO HIGH(gpiofds) DO IF gpiofds[i]<>-2 THEN CardToStr(i, 1, h); fd:=OpenWrite(GPIOUNEXPORT); (* /sys/class/gpio/unexport *) IF fd>=0 THEN WrBin(fd, h, 1); Close(fd); END; END; END; WrStr("exit "); WrInt(signum,0); WrStrLn("!"); HALT(signum) END freegpio; <* END *> VAR syncw, flags, st:CARDINAL; chip:pCHIP; dcd, txfast:BOOLEAN; banddcdall, banddcd:SET8; BEGIN <* IF __GEN_C__ THEN *> signal(SIGTERM, freegpio); signal(SIGINT, freegpio); signal(SIGPIPE, freegpio); <* END *> Parms; chip:=chips; WHILE chip<>NIL DO (* set gpios *) dcd:=scp(chip^.gpio, FALSE, TRUE, FALSE, FALSE); (* NSS off *) chip^.state:=stSLEEP; chip:=chip^.next; END; chip:=chips; usleep(10000); WHILE chip<>NIL DO usleep(1000); IF verb2 THEN Setmode(chip, 0, TRUE, FALSE); Showregs(chip); Setmode(chip, 80H, TRUE, FALSE); Showregs(chip); END; Setmode(chip, 0, TRUE, FALSE); scpo(chip^.gpio, RegSeqConfig1, 40H); (* stop sequencer *) scpo(chip^.gpio, RegSeqConfig1, 00H); (* 83H why ever *) --scpo(chip^.gpio, RegFifoThresh, 1); Setmode(chip, 0, TRUE, FALSE); Setmode(chip, 1, TRUE, FALSE); Setmode(chip, 4, TRUE, FALSE); (* clear fifo *) Setmode(chip, 0, TRUE, FALSE); setppm(chip); chip:=chip^.next; END; txfast:=FALSE; LOOP IF chip=NIL THEN chip:=chips; banddcdall:=banddcd; banddcd:=SET8{}; INC(tcnt); IF txfast THEN usleep(loopdelayfast) ELSE usleep(loopdelay) END; txfast:=FALSE; END; IF (chip^.atx<>NIL) & (chip^.atx^.sendfsk) THEN txfast:=TRUE END; INC(chip^.calcnt); st:=scpi(chip^.gpio, RegOpMode); IF (CAST(SET8, st)*SET8{1..2}=SET8{}) & (chip^.state=stTX) THEN (* sleep or standby *) --WrHex(scpi(chip^.gpio, RegOpMode),1); WrStr(" "); WrHex(scpi(chip^.gpio, RegIrqFlags),1); WrStrLn("=sleep/stby"); IF st=0 THEN Setmode(chip, 80H, TRUE, FALSE); setppm(chip); IF verb THEN Wrchipnum(chip, FALSE); WrStrLn(" reseted") END; END; IF chip^.state<>stWAITDCD THEN IF (chip^.state=stTX) & (chip^.atx<>NIL) & (chip^.atx^.ftextlen=0) THEN chip^.atx:=NIL END; chip^.state:=stSLEEP; END; END; IF chip^.state=stSLEEP THEN IF chip^.rxon THEN setppm(chip); startrx(chip, FALSE); chip^.state:=stRX; END; -- ELSE Setmode(chip, 80H, TRUE, FALSE) END; (* sleep *) END; IF chip^.rxon & (chip^.state=stRX) THEN flags:=scpi(chip^.gpio, RegIrqFlags); chip^.stato:=chip^.statu; chip^.statu:=scpi(chip^.gpio, RegModemStat); IF ODD(chip^.statu) THEN (* dcd *) INCL(banddcd, chip^.band); (* set dcd for this band *) IF NOT ODD(chip^.stato) THEN chip^.mso:=monotonicms(); (* rising dcd *) ELSIF (3 IN CAST(SET8, chip^.statu)) & (chip^.mso<>0) THEN (* header ok *) chip^.rxtxdel:=(monotonicms()-chip^.mso); chip^.mso:=0; END; END; IF 6 IN CAST(SET8, flags) THEN rx(chip) END; (* rx done *) END; IF (chip^.state=stWAITDCD) THEN dcd:=FALSE; IF (chip^.atx<>NIL) & NOT chip^.atx^.usedcd OR dcddone(chip, dcd) THEN IF dcd THEN startdcdcheck(chip); ELSE setppm(chip); send(chip); chip^.state:=stTX; END; END; ELSIF (chip^.atx<>NIL) & (chip^.atx^.ftextlen>0) & (chip^.state<>stTX) & NOT (chip^.band IN (banddcd+banddcdall)) THEN IF chip^.atx^.sendfsk THEN startfsk(chip); chip^.state:=stTX; ELSE IF chip^.atx^.usedcd THEN startdcdcheck(chip) END; chip^.state:=stWAITDCD; END; END; IF chip^.state=stTX THEN IF (chip^.atx<>NIL) & (chip^.atx^.ftextlen>0) & chip^.atx^.sendfsk THEN txfill(chip); ELSIF 3 IN CAST(SET8, scpi(chip^.gpio, RegIrqFlags)) THEN (* tx done *) IF (chip^.atx=NIL) OR (chip^.atx^.ftextlen=0) THEN (* for continous send *) chip^.atx:=NIL; getaxudp2(chip); END; IF (chip^.atx<>NIL) & (chip^.atx^.ftextlen>0) THEN --Setmode(chip, 81H, TRUE, FALSE); (* stop tx *) send(chip); ELSE Setmode(chip, 81H, TRUE, FALSE) END; (* stop tx *) END; END; IF (chip^.atx<>NIL) & (chip^.atx^.ftextlen=0) & NOT chip^.atx^.sendfsk THEN chip^.atx:=NIL END; IF verb2 & (tcnt MOD 8=0) THEN showv2(chip, banddcdall+banddcd) END; -- IF (chip^.state<>stTX) & (chip^.atx=NIL) THEN getaxudp2(chip) END; IF (chip^.state<>stTX) & ((chip^.atx=NIL) OR (chip^.atx^.ftextlen=0)) THEN getaxudp2(chip) END; --IF chip^.atx<>NIL THEN WrInt(chip^.atx^.ftextlen,5); WrStrLn("=atx") ELSE WrStrLn(" no atx") END; chip:=chip^.next; END; END ra02.