/* Generated by XDS Modula-2 to ANSI C v4.20 translator */ #define X2C_int32 #define X2C_index32 #ifndef X2C_H_ #include "X2C.h" #endif #define lorarx_C_ #ifndef osi_H_ #include "osi.h" #endif #include #ifndef mlib_H_ #include "mlib.h" #endif #ifndef udp_H_ #include "udp.h" #endif #ifndef aprsstr_H_ #include "aprsstr.h" #endif #include #ifndef loraprotocols_H_ #include "loraprotocols.h" #endif #include /* iq downsample, shift, (auto)notch lora demodulator with axudp, json out and packet radio, aprs, lorawan, fanet viewer */ /*-------------------------------------------------------------------------------- Synchronisation simple: Sampling preamble upchirps give independent of sample time constant fft frequency. So sample at any time with normal chirprate and, if it looks like an upchrip, jump as many samples as the found frequency differs from zero. As not known exact frequency and not at all sample time but frequency is proportional to time, we first say we are (+-25%) on frequency so we get a 75% exact sample time. This is good enough for decoding the 2 sync chirps and switch to reverse chirps. After fft of the 2 reverse chirps we get another new zero frequency. The median of upchirps and downchirps frequencies makes the true receive frequency. As we know now how far we are away from real frequency, we jump in sampletime half of the upchirp-downchirp frequency difference (only full samples) + the quarter downchirp (thanks to the quarter chirp, we never need back jumps) and add the frequency change from the jump to the median of the upchirps frequencys. Now we are 1 sample exact on sampletime and (as exact as the median of the preamble) on frequency and can decode data. Further drifts in frequency and time (samplerate error) may be corrected with AFC. Sampletime needs no further correction. frequency stability (short/longterm) of rtl is ok rtl's fast AGC up/down on pulsing outband signals modulates carrier and spreads fft-bin same as mobile fading ---------------------------------------------------------------------------------*/ #define lorarx_PI 3.1415926535 #define lorarx_PI2 6.283185307 #define lorarx_LF "\012" #define lorarx_MAXSF 4096 #define lorarx_TIMEOUT 3 /* chirps with no dcd is end of unkown lenght data */ #define lorarx_MAXBINS 3 /* look at weaker bins for fitting parity */ #define lorarx_FRAMELEN 256 #define lorarx_DATASQUELCH 11.0 #define lorarx_DATASQUELCHFACT (-0.79) /* adapt squelch to sf */ #define lorarx_MAXNEST 4 /* start new demodulator if other(s) in frame */ #define lorarx_MAXINBUF 2048 #define lorarx_MINSF 5 #define lorarx_SHIFTSTEPS 65536 #define lorarx_LEVELCORR 6.0206 static uint8_t lorarx_WHITEN[255] = {255U,254U,252U,248U,240U,225U,194U,133U,11U,23U,47U,94U,188U,120U,241U,227U,198U, 141U,26U,52U,104U,208U,160U,64U,128U,1U,2U,4U,8U,17U,35U,71U,142U,28U,56U,113U,226U,196U,137U,18U,37U, 75U,151U,46U,92U,184U,112U,224U,192U,129U,3U,6U,12U,25U,50U,100U,201U,146U,36U,73U,147U,38U,77U,155U, 55U,110U,220U,185U,114U,228U,200U,144U,32U,65U,130U,5U,10U,21U,43U,86U,173U,91U,182U,109U,218U,181U, 107U,214U,172U,89U,178U,101U,203U,150U,44U,88U,176U,97U,195U,135U,15U,31U,62U,125U,251U,246U,237U,219U, 183U,111U,222U,189U,122U,245U,235U,215U,174U,93U,186U,116U,232U,209U,162U,68U,136U,16U,33U,67U,134U,13U, 27U,54U,108U,216U,177U,99U,199U,143U,30U,60U,121U,243U,231U,206U,156U,57U,115U,230U,204U,152U,49U,98U, 197U,139U,22U,45U,90U,180U,105U,210U,164U,72U,145U,34U,69U,138U,20U,41U,82U,165U,74U,149U,42U,84U,169U, 83U,167U,78U,157U,59U,119U,238U,221U,187U,118U,236U,217U,179U,103U,207U,158U,61U,123U,247U,239U,223U, 191U,126U,253U,250U,244U,233U,211U,166U,76U,153U,51U,102U,205U,154U,53U,106U,212U,168U,81U,163U,70U, 140U,24U,48U,96U,193U,131U,7U,14U,29U,58U,117U,234U,213U,170U,85U,171U,87U,175U,95U,190U,124U,249U,242U, 229U,202U,148U,40U,80U,161U,66U,132U,9U,19U,39U,79U,159U,63U,127U}; static uint8_t lorarx_HAMMTAB8[256] = {128U,192U,192U,3U,192U,5U,6U,135U,192U,9U,10U,139U,12U,141U,142U,15U,128U,1U, 2U,199U,4U,199U,199U,135U,8U,137U,138U,11U,140U,13U,14U,199U,128U,1U,2U,131U,4U,133U,206U,7U,8U,137U, 206U,11U,206U,13U,142U,206U,0U,201U,130U,3U,132U,5U,6U,135U,201U,137U,10U,201U,12U,201U,142U,15U,128U, 1U,2U,203U,4U,133U,134U,7U,8U,203U,203U,139U,140U,13U,14U,203U,0U,129U,130U,3U,204U,5U,6U,135U,204U,9U, 10U,139U,140U,204U,204U,15U,0U,197U,130U,3U,197U,133U,6U,197U,136U,9U,10U,139U,12U,197U,142U,15U,194U, 1U,130U,194U,4U,133U,194U,7U,8U,137U,194U,11U,140U,13U,14U,143U,128U,1U,2U,131U,4U,205U,134U,7U,8U,205U, 138U,11U,205U,141U,14U,205U,0U,129U,202U,3U,132U,5U,6U,135U,202U,9U,138U,202U,12U,141U,202U,15U,0U,195U, 195U,131U,132U,5U,6U,195U,136U,9U,10U,195U,12U,141U,142U,15U,196U,1U,2U,131U,132U,196U,196U,7U,8U,137U, 138U,11U,196U,13U,14U,143U,0U,129U,198U,3U,198U,5U,134U,198U,136U,9U,10U,139U,12U,141U,198U,15U,193U, 129U,2U,193U,4U,193U,134U,7U,8U,193U,138U,11U,140U,13U,14U,143U,200U,1U,2U,131U,4U,133U,134U,7U,136U, 200U,200U,11U,200U,13U,14U,143U,0U,129U,130U,3U,132U,5U,6U,207U,136U,9U,10U,207U,12U,207U,207U,143U}; static uint8_t lorarx_HAMMTAB7[128] = {128U,192U,192U,131U,192U,205U,134U,135U,192U,205U,138U,139U,205U,141U,142U, 205U,128U,129U,202U,199U,132U,199U,199U,135U,202U,137U,138U,202U,140U,141U,202U,199U,128U,195U,195U, 131U,132U,133U,206U,195U,136U,137U,206U,195U,206U,141U,142U,206U,196U,201U,130U,131U,132U,196U,196U, 135U,201U,137U,138U,201U,196U,201U,142U,143U,128U,129U,198U,203U,198U,133U,134U,198U,136U,203U,203U, 139U,140U,141U,198U,203U,193U,129U,130U,193U,204U,193U,134U,135U,204U,193U,138U,139U,140U,204U,204U, 143U,200U,197U,130U,131U,197U,133U,134U,197U,136U,200U,200U,139U,200U,197U,142U,143U,194U,129U,130U, 194U,132U,133U,194U,207U,136U,137U,194U,207U,140U,207U,207U,143U}; static uint8_t lorarx_HAMMTAB6[64] = {128U,1U,2U,3U,4U,5U,134U,7U,8U,9U,10U,139U,12U,141U,14U,15U,0U,129U,2U,3U,4U,5U, 6U,135U,8U,9U,138U,11U,140U,13U,14U,15U,0U,1U,2U,131U,4U,133U,6U,7U,136U,9U,10U,11U,12U,13U,142U,15U,0U, 1U,130U,3U,132U,5U,6U,7U,8U,137U,10U,11U,12U,13U,14U,143U}; struct Complex; struct Complex { float Re; float Im; }; struct CB { struct Complex * Adr; size_t Len0; }; typedef struct CB * pCB; struct BIN; struct BIN { float lev; float freq; }; struct BINS; struct BINS { struct BIN b[4]; float noise; float splt; uint32_t halfnoisc; int32_t fecnbr; }; typedef uint8_t NIBBBLOCK[12]; typedef uint8_t NIBBS[523]; enum STATES {lorarx_sSLEEP, lorarx_sHUNT, lorarx_sSYNRAW, lorarx_sID, lorarx_sREV1, lorarx_sREV2, lorarx_sDATA}; typedef struct BINS BINTAB[8]; struct FFRAME; struct FFRAME { BINTAB bintab; NIBBS nibbs; char fecinfo[96]; NIBBBLOCK oneerr; uint32_t chirpc; uint32_t nibbc; uint32_t crfromhead; uint32_t dlen; uint32_t idfound; uint32_t illid; uint32_t cnt; uint32_t dcnt; uint32_t txdel; uint32_t jp; uint32_t cfgsf; uint32_t cfgcr; uint32_t synfilter; uint32_t timeout; uint32_t cfgdatalen; uint32_t iqread; uint32_t label; uint32_t fp; uint32_t fasecorrs; uint32_t oneerrs; uint32_t fecbits; float fc; float fci; float fcstart; float fcfix; float sigsum; float sigmin; float sigmax; float noisenow; float noissum; float noismax; float noismin; float eye; float lastbin; float lastsq; float afcspeed; float datasquelch; float dataratecorr; char optimize; char withhead; char withcrc; char implicitcrc; char nodcdlost; char udpcrcok; char invertiq; char ax25long; char needsjunk; char done; int32_t df; uint8_t state; uint32_t ipnumraw; uint32_t udprawport; char axjoin; char axpart[255]; uint32_t ipnum; uint32_t udpport; char udp2; }; struct DEM; typedef struct DEM * pDEM; struct DEM { pDEM next; int32_t cfgopt; uint32_t coldet; char dcdstate; char done; float noisepeak; float noisesum; uint32_t noisesumcnt; uint32_t noisereports; struct FFRAME frames[4]; }; static pDEM dems; static char iqfn[1024]; static int32_t outdechirped; static int32_t outfiltered; static int32_t iqfd; static uint32_t firlen; static uint32_t globfilt; static uint32_t iqwrite; static uint32_t binsview; static uint32_t isize; static char notexitonbrokenpipe; static char u8signed; static char sendjudpdcd; static char nocrcfec; static char nofec; static struct Complex iqbuf[8192]; static pCB fftbufs[13]; static float DDS[65536]; static float cfglevel; static float globallevelcor; static float globdrate; static float SINTAB[25]; #define lorarx_MAXINFIRLEN 4096 #define lorarx_FIRMAX 4096 #define lorarx_SUBSAMPBITS 4 #define lorarx_SUBSAMP 16 struct _0 { struct Complex * Adr; size_t Len0; }; typedef struct _0 * pFIRTAB; struct _1 { struct Complex * Adr; size_t Len0; }; typedef struct _1 * pFIR; struct NOTCH; typedef struct NOTCH * pNOTCH; struct NOTCH { pNOTCH next; float f1; float f2; }; struct _2 { float * Adr; size_t Len0; }; typedef struct _2 * pFREQMASK; struct FIXFIR { float * Adr; size_t Len0; }; typedef struct FIXFIR * pFIXFIR; static pFIR pfir; static pFIXFIR pfixfir; static pNOTCH pnotches; static float pknoisemed; static float pknoiseup; static float pknoisedown; static float notchthres; static float downsample; static uint32_t notchcnt; static uint32_t autonotch; static uint32_t samprate; static uint32_t firwp; static uint32_t sampc; static uint32_t shiftstep; static uint32_t birdpos; static uint32_t phasereg; static char noisblanker; static char complexfir; static pFREQMASK pbirdhist; static pFIRTAB ptmpfir; static pFIRTAB pbirdbuf; static pFIRTAB pfirtab; static void Error(char text[], uint32_t text_len) { X2C_PCOPY((void **)&text,text_len); osi_Werr("lorarx:", 8ul); osi_Werr(text, text_len); osi_Werr(" error abort\012", 14ul); X2C_ABORT(); X2C_PFREE(text); } /* end Error() */ static char hex(uint32_t n, char cap) { n = n&15UL; if (n<=9UL) return (char)(n+48UL); if (cap) return (char)(n+55UL); return (char)(n+87UL); } /* end hex() */ static void HexStr(uint32_t x, uint32_t digits, uint32_t len, char cap, char s[], uint32_t s_len) { uint32_t i0; if (digits>s_len-1) digits = s_len-1; i0 = digits; while (i00UL) { --digits; s[digits] = hex(x, cap); x = x/16UL; } } /* end HexStr() */ static void WrHexCap(uint32_t x, uint32_t digits, uint32_t len) { char s[256]; HexStr(x, digits, len, 1, s, 256ul); osi_WrStr(s, 256ul); } /* end WrHexCap() */ /* PROCEDURE sqr(x:REAL):REAL; BEGIN RETURN x*x END sqr; */ static float lim(float x, float max0) { if (x>max0) return max0; if (x<-max0) return -max0; return x; } /* end lim() */ static float ftrunc(float x) { if (x<0.0f) return (-1.0f)-(float)(uint32_t)X2C_TRUNCC(-x,0UL,X2C_max_longcard); return (float)(uint32_t)X2C_TRUNCC(x,0UL,X2C_max_longcard); } /* end ftrunc() */ static float fsign(float x) { if (x<0.0f) return (-1.0f); return 1.0f; } /* end fsign() */ static float flmin(float x, float min0) { if (xh) return d-m; if (d<-h) return d+m; return d; } /* end freqmod() */ /* abs difference a-b in cycle */ /*------ fft */ /*-not level correct fft and dc part same level */ static void buttf(struct Complex * R, struct Complex * A, struct Complex * B) { struct Complex h; h.Re = A->Re*B->Re-A->Im*B->Im; h.Im = A->Re*B->Im+A->Im*B->Re; B->Re = R->Re-h.Re; B->Im = R->Im-h.Im; R->Re = R->Re+h.Re; R->Im = R->Im+h.Im; } /* end buttf() */ static void Transform(struct Complex feld[], uint32_t feld_len, uint32_t logsize, char INVERS) { uint32_t n2; uint32_t ri; uint32_t N; uint32_t id; uint32_t idd2; uint32_t z; uint32_t j1; uint32_t i0; struct Complex wcpx; struct Complex h; float sko; float sn; float cs; float sk; float r; float ck; struct Complex * anonym; uint32_t tmp; uint32_t tmp0; N = (uint32_t)(1UL<Re-h.Re; feld[i0+idd2].Im = anonym->Im-h.Im; anonym->Re = anonym->Re+h.Re; anonym->Im = anonym->Im+h.Im; } i0 += id; } if (z!=1UL) { tmp0 = idd2-1UL; j1 = 1UL; if (j1<=tmp0) for (;; j1++) { ck = r*cs+ck; cs = cs+ck; sk = r*sn+sk; sn = sn+sk; wcpx.Re = cs; wcpx.Im = sn; i0 = j1; while (i0Adr[i0]; if (vAdr[i0]; if (i0>=2UL) v1 = p->Adr[i0-2UL]; return lim(X2C_DIVR(v2-v1,v), 1.0f); } /* end smoothnotch() */ static void shownotches(char s[], uint32_t s_len) { uint32_t m; uint32_t nc; int32_t ii; char h[21]; int32_t tmp; s[0UL] = 0; if (pbirdhist) { if (loraprotocols_verb2) aprsstr_Append(s, s_len, " notch at:", 11ul); else aprsstr_Append(s, s_len, " notches:", 10ul); nc = 0UL; m = (uint32_t)X2C_TRUNCC((X2C_DIVR((float)firlen,downsample))*0.5f+0.5f,0UL,X2C_max_longcard); if (m>=firlen/2UL) m = firlen/2UL-1UL; tmp = (int32_t)m; ii = -(int32_t)m; if (ii<=tmp) for (;; ii++) { if (smoothnotch(pbirdhist, (uint32_t)((int32_t)(firlen/2UL)+ii), notchthres)>=(-1.0f)) { if (loraprotocols_verb2) { if (nc) aprsstr_Append(s, s_len, ",", 2ul); aprsstr_IntToStr(ii, 0UL, h, 21ul); aprsstr_Append(s, s_len, h, 21ul); } ++nc; } if (ii==tmp) break; } /* end for */ if (!loraprotocols_verb2) { aprsstr_IntToStr((int32_t)nc, 0UL, h, 21ul); aprsstr_Append(s, s_len, h, 21ul); } } } /* end shownotches() */ static float manualnotch(int32_t fi) { pNOTCH p; float v; float f; f = (float)fi; p = pnotches; v = 1.0f; while (p) { if (p->f1>=f) v = flmin(v, (p->f1-f)*0.5f); else if (p->f2f2)*0.5f); else v = 0.0f; p = p->next; } return flmax(0.0f, (v*v-0.25f)*1.33333333f); } /* end manualnotch() */ static void joinfirs(int32_t i0, float w0) { uint32_t j1; /*WrFixed(w,3,1); WrStrLn("=w"); */ if ((float)fabs(w0)<=1.0f) { if (i0<0L) j1 = (uint32_t)((int32_t)(ptmpfir->Len0-1)+1L+i0); else j1 = (uint32_t)i0; ptmpfir->Adr[j1].Im = 0.0f; --i0; if (i0<0L) j1 = (uint32_t)((int32_t)(ptmpfir->Len0-1)+1L+i0); else j1 = (uint32_t)i0; ptmpfir->Adr[j1].Im = ptmpfir->Adr[j1].Im*(w0*0.25f+0.25f); i0 += 2L; if (i0<0L) j1 = (uint32_t)((int32_t)(ptmpfir->Len0-1)+1L+i0); else j1 = (uint32_t)i0; ptmpfir->Adr[j1].Im = ptmpfir->Adr[j1].Im*(0.25f-w0*0.25f); } } /* end joinfirs() */ #define lorarx_DECNOTCH 10 static void wrnotch(uint32_t * j1, int32_t f) { if (*j1>0UL) osi_WrStr(",", 2ul); else osi_WrStr("manual notches at:", 19ul); osic_WrINT32((uint32_t)f, 1UL); ++*j1; } /* end wrnotch() */ static void makefir(float fg, pFIRTAB pfir0, pFREQMASK pbird, float thres) { uint32_t subsamp; uint32_t flen; uint32_t logfl; uint32_t m; uint32_t j1; uint32_t i0; int32_t ii; struct Complex u; float l; float w0; uint32_t tmp; int32_t tmp0; flen = (pfir0->Len0-1)+1UL; subsamp = flen/firlen; if (pbird==0) { tmp = firlen/2UL-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { pfixfir->Adr[firlen/2UL+i0] = manualnotch((int32_t)i0); pfixfir->Adr[(firlen/2UL-i0)-1UL] = manualnotch(-(int32_t)(i0+1UL)); if (i0==tmp) break; } /* end for */ if (loraprotocols_verb) { j1 = 0UL; for (i0 = firlen/2UL-1UL; i0>=1UL; i0--) { if (pfixfir->Adr[(firlen/2UL-i0)-1UL]<0.5f) wrnotch(&j1, -(int32_t)i0); } /* end for */ tmp = firlen/2UL-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { if (pfixfir->Adr[firlen/2UL+i0]<0.5f) wrnotch(&j1, (int32_t)i0); if (i0==tmp) break; } /* end for */ if (j1>0UL) osi_WrStrLn("", 1ul); } } tmp = ptmpfir->Len0-1; i0 = 0UL; if (i0<=tmp) for (;; i0++) { ptmpfir->Adr[i0].Re = 0.0f; ptmpfir->Adr[i0].Im = 0.0f; if (i0==tmp) break; } /* end for */ w0 = (X2C_DIVR((float)firlen,fg))*0.5f+0.5f; /* downsample bandfilter */ m = (uint32_t)X2C_TRUNCC(w0,0UL,X2C_max_longcard); w0 = w0-(float)m; if (m>=firlen/2UL) m = firlen/2UL-1UL; tmp0 = (int32_t)m; ii = -(int32_t)m; if (ii<=tmp0) for (;; ii++) { /* manual notches */ if (ii<0L) j1 = (uint32_t)((int32_t)(ptmpfir->Len0-1)+1L+ii); else j1 = (uint32_t)ii; ptmpfir->Adr[j1].Im = pfixfir->Adr[(int32_t)(firlen/2UL)+ii]; if (ii==tmp0) break; } /* end for */ ptmpfir->Adr[m].Im = w0; ptmpfir->Adr[(ptmpfir->Len0-1)-m].Im = w0; if (pbird) { /* adative notches */ tmp0 = (int32_t)m; ii = -(int32_t)m; if (ii<=tmp0) for (;; ii++) { joinfirs(ii, smoothnotch(pbird, (uint32_t)((int32_t)(firlen/2UL)+ii), thres)); if (ii==tmp0) break; } /* end for */ } /* FOR i:=0 TO firlen-1 DO WrFixed(ptmpfir^[i].Im,2,5) END; WrStrLn(""); FOR i:=0 TO firlen-1 DO WrFixed(ptmpfir^[HIGH(ptmpfir^)-i].Im,2,5) END; WrStrLn(""); */ logfl = 1UL; do { ++logfl; } while (flen>(uint32_t)(1UL<Adr, ptmpfir->Len0, logfl, 1); m = flen/2UL; tmp = m-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { u = ptmpfir->Adr[i0]; ptmpfir->Adr[i0] = ptmpfir->Adr[i0+m]; ptmpfir->Adr[i0+m] = u; if (i0==tmp) break; } /* end for */ l = X2C_DIVR(2.0f,(float)flen); tmp = flen-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { /* hamming window */ w0 = (float)(0.54+0.46*cos((double)(3.1415926535f*((float)i0*l-1.0f)))); ptmpfir->Adr[i0].Re = ptmpfir->Adr[i0].Re*w0; ptmpfir->Adr[i0].Im = ptmpfir->Adr[i0].Im*w0; if (i0==tmp) break; } /* end for */ l = 0.00001f; tmp = flen-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { u = ptmpfir->Adr[(((i0%firlen)*subsamp+subsamp)-1UL)-i0/firlen]; /* rearange table for better memory cashing */ /* u:=ptmpfir^[(firlen-1-i MOD firlen)*subsamp + i DIV firlen]; (* rearange table for better memory cashing *) */ pfir0->Adr[i0] = u; w0 = CABS(u); if (w0>l) l = w0; if (i0==tmp) break; } /* end for */ l = X2C_DIVR(1.0f,l); tmp = flen-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { pfir0->Adr[i0].Re = l*pfir0->Adr[i0].Re; /* make uniq gain */ pfir0->Adr[i0].Im = l*pfir0->Adr[i0].Im; if (i0==tmp) break; } /* end for */ } /* end makefir() */ static void MakeDDS(void) { uint32_t i0; float r; r = 9.5873799240112E-5f; for (i0 = 0UL; i0<=65535UL; i0++) { DDS[i0] = (float)sin((double)((float)i0*r)); } /* end for */ } /* end MakeDDS() */ static uint32_t _cnst[10] = {64UL,48UL,32UL,24UL,16UL,12UL,8UL,4UL,2UL,1UL}; static float baud(uint32_t sf, uint32_t bwnum) { return X2C_DIVR(5.E+5f,(float)(_cnst[bwnum]*(uint32_t)(1UL<=3UL || h[0UL]!=':') { n = 0UL; ok0 = 0; while ((uint8_t)h[p]>='0' && (uint8_t)h[p]<='9') { ok0 = 1; n = (n*10UL+(uint32_t)(uint8_t)h[p])-48UL; ++p; } if (!ok0) { GetIp_ret = -1L; goto label; } } if (i0<3UL) { if (h[0UL]!=':') { if (h[p]!='.' || n>255UL) { GetIp_ret = -1L; goto label; } *ip = *ip*256UL+n; } } else if (i0==3UL) { if (h[0UL]!=':') { *ip = *ip*256UL+n; if (h[p]!=':' || n>255UL) { GetIp_ret = -1L; goto label; } } else { p = 0UL; *ip = 2130706433UL; } } else if (n>65535UL) { GetIp_ret = -1L; goto label; } *port = n; ++p; } /* end for */ GetIp_ret = 0L; label:; X2C_PFREE(h); return GetIp_ret; } /* end GetIp() */ static char StrToHex(const char s[], uint32_t s_len, uint32_t * n) { uint32_t i0; char c; i0 = 0UL; *n = 0UL; while (i0<=s_len-1 && s[i0]) { *n = *n*16UL; c = X2C_CAP(s[i0]); if ((uint8_t)c>='0' && (uint8_t)c<='9') *n += (uint32_t)(uint8_t)c-48UL; else if ((uint8_t)c>='A' && (uint8_t)c<='F') *n += (uint32_t)(uint8_t)c-55UL; else return 0; ++i0; } return 1; } /* end StrToHex() */ static void newdem(void) { pDEM dem; struct FFRAME * anonym; osic_alloc((char * *) &dem, sizeof(struct DEM)); if (dem==0) Error("out of memory", 14ul); memset((char *)dem,(char)0,sizeof(struct DEM)); dem->cfgopt = -1L; dem->coldet = 3UL; { /* with */ struct FFRAME * anonym = &dem->frames[0U]; anonym->cfgsf = 0UL; anonym->cfgcr = 0UL; anonym->synfilter = globfilt; anonym->afcspeed = (-1.0f); anonym->dataratecorr = globdrate; anonym->datasquelch = (-1.0f); } dem->next = dems; dems = dem; } /* end newdem() */ static void Parms(void) { char hassf; char hasbw; char hasudp; char err; loraprotocols_pJDESTS jd; float afcspd; float rh; float insamplerate; int32_t ih; uint32_t globcr; uint32_t globsf; char h[1024]; char pushback[1024]; uint32_t i0; pDEM pd0; pNOTCH pnotch; float configoffsethz; float offs; struct NOTCH * anonym; pnotch = 0; complexfir = 0; shiftstep = 0UL; configoffsethz = 0.0f; autonotch = 0UL; noisblanker = 0; pknoisemed = 0.0f; loraprotocols_jdests0 = 0; outdechirped = -1L; outfiltered = -1L; binsview = 0UL; firlen = 0UL; loraprotocols_jmhz = 0.0f; iqfn[0] = 0; isize = 1UL; loraprotocols_verb = 0; loraprotocols_verb2 = 0; loraprotocols_quietcrc = 0; loraprotocols_newline = 0; err = 0; cfglevel = 0.0f; nofec = 0; nocrcfec = 0; hasudp = 0; loraprotocols_udpsock = -1L; loraprotocols_bwnum = 7UL; globfilt = 0UL; globsf = 12UL; globcr = 0UL; afcspd = (-1.0f); hasbw = 0; hassf = 0; notexitonbrokenpipe = 0; loraprotocols_jpipename[0] = 0; globdrate = 0.0f; insamplerate = 0.0f; newdem(); dems->frames[0U].synfilter = globfilt; u8signed = 0; loraprotocols_hexformat = X2C_max_longcard; pushback[0] = 0; for (;;) { if (pushback[0U]) { memcpy(h,pushback,1024u); pushback[0] = 0; } else osi_NextArg(h, 1024ul); if (h[0U]==0) break; if ((h[0U]=='-' && h[1U]) && h[2U]==0) { if (h[1U]=='i') { osi_NextArg(iqfn, 1024ul); if (iqfn[0U]=='-' && iqfn[1U]==0) strncpy(iqfn,"/dev/stdin",1024u); else if (iqfn[0U]==0 || iqfn[0U]=='-') Error("-i ", 16ul); } else if (h[1U]=='f') { osi_NextArg(h, 1024ul); if ((h[0U]=='i' && h[1U]=='1') && h[2U]=='6') isize = 2UL; else if (h[0U]=='u' && h[1U]=='8') isize = 1UL; else if (h[0U]=='i' && h[1U]=='8') { isize = 1UL; u8signed = 1; } else if ((h[0U]=='f' && h[1U]=='3') && h[2U]=='2') isize = 4UL; else Error("-f u8|i8|i16|f32", 17ul); } else if (h[1U]=='s') { if (hassf) newdem(); hassf = 1; osi_NextArg(h, 1024ul); if ((!aprsstr_StrToInt(h, 1024ul, &ih) || labs(ih)>12L) || labs(ih)<5L) { Error("-s [-]5..[-]12", 20ul); } dems->frames[0U].cfgsf = (uint32_t)labs(ih); dems->frames[0U].invertiq = ih<0L; if (!hasudp) globsf = dems->frames[0U].cfgsf; } else if (h[1U]=='a') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&dems->frames[0U].afcspeed, h, 1024ul)) { Error("-a (0.15)", 21ul); } if (!hasudp) afcspd = dems->frames[0U].afcspeed; } else if (h[1U]=='c') { osi_NextArg(h, 1024ul); if ((!aprsstr_StrToCard(h, 1024ul, &dems->frames[0U].cfgcr) || dems->frames[0U].cfgcr>8UL) || dems->frames[0U].cfgcr<4UL) { Error("-c 4..8", 13ul); } if (!hasudp) globcr = dems->frames[0U].cfgcr; } else if (h[1U]=='b') { osi_NextArg(h, 1024ul); if (hasbw) { osi_WrStrLn("Warning: only one bw = input samplerate!", 41ul); } if (!aprsstr_StrToCard(h, 1024ul, &loraprotocols_bwnum) || loraprotocols_bwnum>9UL) { Error("-b 0..9", 13ul); } hasbw = 1; } else if (h[1U]=='l') { osi_NextArg(h, 1024ul); if ((!aprsstr_StrToCard(h, 1024ul, &dems->frames[0U].cfgdatalen) || dems->frames[0U].cfgdatalen>255UL) || dems->frames[0U].cfgdatalen<2UL) { Error("-l 2..255", 20ul); } } else if (h[1U]=='g') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&cfglevel, h, 1024ul)) Error("-g ", 8ul); } else if (h[1U]=='r') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&insamplerate, h, 1024ul)) Error("-r ", 19ul); } else if (h[1U]=='w') { osi_NextArg(h, 1024ul); if ((!aprsstr_StrToCard(h, 1024ul, &firlen) || firlen>4096UL) || firlen<2UL) { Error("-w 2..4096", 20ul); } } else if (h[1U]=='o') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&configoffsethz, h, 1024ul)) Error("-o ", 15ul); } else if (h[1U]=='Z') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&pknoiseup, h, 1024ul)) { Error("-Z (0.01 0.9999)", 39ul); } osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&pknoisedown, h, 1024ul)) { Error("-Z (0.01 0.9999)", 39ul); } noisblanker = 1; } else if (h[1U]=='S') { /* synsquelch sf10 31 sf7 33 sf12 34 */ osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&dems->frames[0U].datasquelch, h, 1024ul)) { Error("-S ", 11ul); } } else if (h[1U]=='X') { osi_NextArg(h, 1024ul); if (!StrToHex(h, 1024ul, &dems->frames[0U].synfilter)) Error("-X ", 11ul); if (!hasudp) globfilt = dems->frames[0U].synfilter; } else if (h[1U]=='O') { osi_NextArg(h, 1024ul); if ((!aprsstr_StrToInt(h, 1024ul, &dems->cfgopt) || dems->cfgopt<0L) || dems->cfgopt>1L) { Error("-o 0..1 (-1)", 21ul); } } else if (h[1U]=='M') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&loraprotocols_jmhz, h, 1024ul)) Error("-M ", 9ul); } else if (h[1U]=='P') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&dems->frames[0U].dataratecorr, h, 1024ul)) { Error("-P ", 9ul); } if (!hassf) globdrate = dems->frames[0U].dataratecorr; } else if (h[1U]=='n') { osic_alloc((char * *) &pnotch, sizeof(struct NOTCH)); if (pnotch==0) { Error("out of memory", 14ul); } { /* with */ struct NOTCH * anonym = pnotch; osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&anonym->f1, h, 1024ul)) Error("-n ", 13ul); osi_NextArg(h, 1024ul); if (!aprsstr_StrToFix(&anonym->f2, h, 1024ul)) Error("-n ", 13ul); if (anonym->f1>anonym->f2) { rh = anonym->f1; anonym->f1 = anonym->f2; anonym->f2 = rh; } } pnotch->next = pnotches; pnotches = pnotch; complexfir = 1; } else if (h[1U]=='W') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToCard(h, 1024ul, &autonotch)) { Error("-W (0 = off)", 34ul); } complexfir = 1; } else if (h[1U]=='d') dems->coldet = 0UL; else if (h[1U]=='E') nocrcfec = 1; else if (h[1U]=='F') nofec = 1; else if (h[1U]=='C') dems->frames[0U].implicitcrc = 1; else if (h[1U]=='D') dems->frames[0U].nodcdlost = 1; else if (h[1U]=='v') loraprotocols_verb = 1; else if (h[1U]=='Q') loraprotocols_quietcrc = 1; else if (h[1U]=='N') { loraprotocols_newline = 1; loraprotocols_verb = 1; } else if (h[1U]=='V') { loraprotocols_verb = 1; loraprotocols_verb2 = 1; } else if (h[1U]=='q') dems->frames[0U].invertiq = 1; else if (h[1U]=='A') dems->frames[0U].ax25long = 1; else if (h[1U]=='y') { dems->frames[0U].needsjunk = 1; loraprotocols_hamview = 1; /* if same netid show the ham protokoll version */ } else if (h[1U]=='K') notexitonbrokenpipe = 1; else if (h[1U]=='H') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToCard(h, 1024ul, &loraprotocols_hexformat)) { loraprotocols_hexformat = 1UL; /* for compatibility to -H without parameter */ memcpy(pushback,h,1024u); } } else if (h[1U]=='U' || h[1U]=='L') { hasudp = 1; dems->frames[0U].udp2 = h[1U]=='L'; /* switch on axudp2 */ osi_NextArg(h, 1024ul); if (GetIp(h, 1024ul, &dems->frames[0U].ipnum, &dems->frames[0U].udpport)<0L) { Error("-U or -L ip:port number", 24ul); } } else if (h[1U]=='T') { sendjudpdcd = 1; osi_NextArg(h, 1024ul); if (!aprsstr_StrToCard(h, 1024ul, &dems->noisereports)) Error("-T ", 12ul); } else if (h[1U]=='t' || h[1U]=='u') { hasudp = 1; dems->frames[0U].udpcrcok = h[1U]=='t'; osi_NextArg(h, 1024ul); if (GetIp(h, 1024ul, &dems->frames[0U].ipnumraw, &dems->frames[0U].udprawport)<0L) { Error("-u ip:port number", 18ul); } } else if (h[1U]=='J') { hasudp = 1; osi_NextArg(h, 1024ul); osic_alloc((char * *) &jd, sizeof(struct loraprotocols_JDESTS)); if (jd==0) Error("-J out of memory", 17ul); if (GetIp(h, 1024ul, &jd->jipnum, &jd->judpport)<0L) { Error("-J ip:port number", 18ul); } jd->next = loraprotocols_jdests0; loraprotocols_jdests0 = jd; } else if (h[1U]=='Y') { osi_NextArg(h, 1024ul); if (h[0U]=='d') { osi_NextArg(h, 1024ul); outdechirped = osi_OpenWrite(h, 1024ul); if (outdechirped<0L) Error("-Y d|f iq-filename create", 26ul); } else if (h[0U]=='f') { osi_NextArg(h, 1024ul); outfiltered = osi_OpenWrite(h, 1024ul); if (outfiltered<0L) Error("-Y d|f iq-filename create", 26ul); } else if (h[0U]=='b') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToCard(h, 1024ul, &binsview)) { Error("-Y b ", 22ul); } } else Error("-Y d|f|b iq-filename", 21ul); dems->coldet = 0UL; /* not get mixed up more demods */ } else { if (h[1U]=='h') { osi_WrStrLn(" Decode lora sf5..12 +reverse, 7.8..500khz out of IQ-File/Pipe, 8 16 32bit, shift and downsa\ mple (samplerate must be exact +/-0.00001)", 135ul); osi_WrStrLn(" output data in raw udp, axudp or json, view (and if possible generate aprs axudp) aprs, pr,\ lorawan, fanet, meshcore, meshtastic...", 133ul); osi_WrStrLn("", 1ul); osi_WrStrLn(" -A (*) enable frame chaining for ax25 longframes", 66ul); osi_WrStrLn(" -a (*)follow frequency drift, 0 off (0.15), try other on hard to decode fra\ me from iq-file", 108ul); osi_WrStrLn(" -b 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)", 95ul); osi_WrStrLn(" -C (*)use crc on implicit header", 50ul); osi_WrStrLn(" -c (*)coding rate and enable implicit header (4..8) (else from header)", 88ul); osi_WrStrLn(" -D (*)if dcd lost go on decoding until frame length limit (for external FEC\ or monitoring)", 108ul); osi_WrStrLn(" -d (*)switch off collision detection (less cpu but loose stronger frames st\ arting inside weaker", 113ul); osi_WrStrLn(" -E switch off using crc to repair 1 chirp (stresses crc, does not repair mu\ ch) (on)", 101ul); osi_WrStrLn(" -F max. block energy FEC off (hamming code fec remains on) (on), try on/off\ for decode iq file", 112ul); osi_WrStrLn(" -f u8|i8|i16|f32 IQ data format", 38ul); osi_WrStrLn(" -g add this to measured signal level for absolute values (no autogain in sd\ r) (0.0)", 101ul); osi_WrStrLn(" -H show payload in ascii if printable else in [hex] same as -H 1", 82ul); osi_WrStrLn(" 0:show no payload, 2:in hex, 3:hex with kommas", 69ul); osi_WrStrLn(" 4:tries decoding payload, 5:with ascii/hex, 6:with hex, 7:with hex and\ kommas", 100ul); osi_WrStrLn(" -h this", 25ul); osi_WrStrLn(" -i IQ-filename or pipe", 40ul); osi_WrStrLn(" -J send demodulated data(base64) with metadata in json, may be repeated\ ", 93ul); osi_WrStrLn(" -j write demodulated data(base64) with metadata in json to file or (unbreak\ able) pipe", 103ul); osi_WrStrLn(" -K do not exit on broken iq pipe", 50ul); osi_WrStrLn(" -L (*)same as -U but AXUDPv2 with metadata for igate", 74ul); osi_WrStrLn(" individual destinations per sf: -L 127.0.0.1:9012 -s 12 -L 127.0.0.1:9\ 010 -s 10", 102ul); osi_WrStrLn(" -l (*)fixed data length for implicit header else guess from dcd", 81ul); osi_WrStrLn(" -M pass through rx frequency to json metadata -M 433.775", 74ul); osi_WrStrLn(" -N if verbous add empty line after data line", 62ul); osi_WrStrLn(" -n <[-]Hz> <[-]Hz> notchfilter baseband from to Hz (may be repeatet)", 70ul); osi_WrStrLn(" -O <0..1> (*)optimize on off else automatic on sf/bw (-1)", 68ul); osi_WrStrLn(" -o shift input iq band +-Hz", 45ul); osi_WrStrLn(" -P <+/-ppm> (*)tune datarate (chirp samplerate) or preset for auto (-a) in ppm (0)", 91ul); osi_WrStrLn(" -Q verbous and -u sending only for frames with crc and crc ok, see -v", 87ul); osi_WrStrLn(" -q (*)invers chirps or swapped I/Q (prefer negative spread factor)", 84ul); osi_WrStrLn(" -r downsample input, give exact input samplerate in Hz (off)", 78ul); osi_WrStrLn(" -S (*)modifiy squelch level critical for implicit header frame length guess\ (automatic)", 105ul); osi_WrStrLn(" -s [-] (*)spread factor (5..12) (12) and start a new demodulator", 78ul); osi_WrStrLn(" negativ value (-s -12) for invers chirps or swapped I/Q", 78ul); osi_WrStrLn(" -T send json udp with DCD-state+sf valid for this sf and every send\ noisefloor and peak", 113ul); osi_WrStrLn(" -t (*)send raw frame bytes in udp frame only if has crc and crc ok", 88ul); osi_WrStrLn(" -U (*)send frame in AXUDP", 47ul); osi_WrStrLn(" -u (*)send raw frame bytes in udp frame, -Q for crc check", 79ul); osi_WrStrLn(" -V very verbous for debugging frames", 54ul); osi_WrStrLn(" -v verbous ====: cr=4(no fec), +++++: hamming ok, -:hamming error, h:by ham\ ming corrected,", 108ul); osi_WrStrLn(" ~:weakest chirp replaced, b:noisy chirp replaced, c/C:tried until crc \ ok/not ok,", 103ul); osi_WrStrLn(" ^:bins with decending power sum tried until hamming ok and presets -H \ 5", 94ul); osi_WrStrLn(" -W every n*firlen samples update notch filter 0=off, ok:50 (0), less for pu\ lsing narrowband noise", 115ul); osi_WrStrLn(" -w downsample fir length (higher is sharper/more cpu) else automatic (4..40\ 96) (0)", 100ul); osi_WrStrLn(" -X (*)filter network-id (sync), 1xx stops decode on wrong id so fast ready \ for new frame if set -d", 116ul); osi_WrStrLn(" 0 is wildcard, 20 will pass 2*, 03 for *3, 00 pass all (00)", 82ul); osi_WrStrLn(" -Y d|f|b iq debug output in float32-iq (d)echirped or only (f)iltered, view spe\ ctrum, or bins , sets -d", 125ul); osi_WrStrLn(" -y (*)not view decoded protocols and for aprs needs 3c,ff,01 header else al\ l junk removed until first letter", 126ul); osi_WrStrLn(" -Z add pulse noise filter (noise blanker) (0.05 0.999)", 79ul); osi_WrStrLn("(*) may be repeated for more demodulators, to start next demodulator apply -s before ot\ her pramaeters", 107ul); osi_WrStrLn("", 1ul); osi_WrStrLn("examples: aprs with autonotch for narrowband interference:", 59ul); osi_WrStrLn(" rtl_sdr -f 433.775m -s 1000000 - | ./lorarx -i /dev/stdin -f u8 -r 1000000 -W 50 -v -H 1 -\ N -b 7 -s 12 -w 64", 111ul); osi_WrStrLn("lorawan all modulations:", 25ul); osi_WrStrLn(" rtl_sdr -f 869.525m -s 1000000 - | ./lorarx -i /dev/stdin -f u8 -r 1000000 -Q -v -H 6 -b 7\ -s 12 -s 11 -s 10 -s 9 -s 8 -s 7 -s -12 -s -11 -s -10 -s -9 -s -8 -s -7", 165ul); osi_WrStrLn("fanet with plutosdr axudp to aprsmap:", 38ul); osi_WrStrLn(" rx_sdr -f 868.2 -s 1000000 -d driver=plutosdr -F CS16 - | ./lorarx -i /dev/stdin -f i16 -r\ 1000000 -Q -v -H 6 -L 127.0.0.1:9002 -b 8 -s 7", 140ul); osi_WrStrLn("Tianqi-Sats 400.260MHz:", 24ul); osi_WrStrLn(" rtl_sdr -f 400.0m -s 1000000 - | ./lorarx -i /dev/stdin -f u8 -r 1000000 -o 260000 -v -b 7\ -s 10 -O 1 -N -H 2", 112ul); osi_WrStrLn("meshtastic + meshcore and frames in json via udp to decypter:", 62ul); osi_WrStrLn(" mknod iqpipe p", 17ul); osi_WrStrLn(" rtl_sdr -f 869.5m -s 1000000 - | tee iqpipe | ./lorarx -i /dev/stdin -f u8 -r 1000000 -o 1\ 18000 -b 6 -s 8 -v -N -Q -M 869.618 -J 127.0.0.1:7001", 146ul); osi_WrStrLn(" ./lorarx -i iqpipe -K -f u8 -r 1000000 -o 25000 -b 8 -s 11 -v -N -Q -M 869.525 -J 127.0.0.1\ :7002", 98ul); osi_WrStrLn("", 1ul); osi_WrStrLn("example: decode payload from udp json with python3: -J 127.0.0.1:5100", 71ul); osi_WrStrLn("import json, base64, socket", 28ul); osi_WrStrLn("IP=(\"0.0.0.0\",5100)", 20ul); osi_WrStrLn("sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)", 53ul); osi_WrStrLn("sock.bind(IP)", 14ul); osi_WrStrLn("while True:", 12ul); osi_WrStrLn(" data, addr=sock.recvfrom(1500)", 33ul); osi_WrStrLn(" obj = json.loads(data.decode())", 34ul); osi_WrStrLn(" print(obj)", 13ul); osi_WrStrLn(" try:", 7ul); osi_WrStrLn(" payload=base64.b64decode(obj[\"payload\"])", 45ul); osi_WrStrLn(" print(\"payload=\",payload)", 30ul); osi_WrStrLn(" except: pass", 15ul); X2C_ABORT(); } err = 1; } } else err = 1; if (err) break; } if (err) { osi_Werr(">", 2ul); osi_Werr(h, 1024ul); osi_Werr("< use -h\012", 10ul); X2C_ABORT(); } if (hasudp) { if (loraprotocols_udpsock<0L) loraprotocols_udpsock = openudp(); if (loraprotocols_udpsock<0L) Error("cannot open udp socket", 23ul); } if (insamplerate==0.0f && (autonotch>0UL || firlen)) { insamplerate = X2C_DIVR(5.E+5f,(float)_cnst[loraprotocols_bwnum]); } downsample = X2C_DIVR(insamplerate,X2C_DIVR(5.E+5f,(float)_cnst[loraprotocols_bwnum])); if (insamplerate!=0.0f && firlen==0UL) { /* make default fir length */ firlen = 32UL; if (downsample>2.0f) { firlen = 64UL; if (downsample>4.0f) { firlen = 128UL; if (downsample>8.0f) firlen = 256UL; } } } if (firlen==0UL && complexfir) Error("enable FIR (-r) for notches (-n)", 33ul); if (firlen>0UL) { /* make it 2^n */ i0 = 1UL; do { ++i0; } while (firlen>(uint32_t)(1UL<=0L && firlen==0UL) Error("no FIR (-w) set so no filtert output", 37ul); /*- offset */ if (configoffsethz!=0.0f && insamplerate!=0.0f) { offs = (X2C_DIVR(configoffsethz,insamplerate))*65536.0f*65536.0f; if (offs<0.0f) offs = offs+4.294967295E+9f; if (offs<0.0f || offs>=4.294967295E+9f) Error("-o shift outside iq band", 25ul); shiftstep = (uint32_t)X2C_TRUNCC(offs,0UL,X2C_max_longcard); } /*- offset */ globallevelcor = 0.0f; if (isize==1UL) globallevelcor = (-42.0f); else if (isize==2UL) globallevelcor = (-90.3f); globallevelcor = cfglevel+globallevelcor; if (loraprotocols_verb) { if (firlen) { osi_WrStr("FIR length=", 12ul); osic_WrINT32(firlen, 1UL); osi_WrStr(" ratio=", 8ul); osic_WrFixed(downsample, 6L, 1UL); if (configoffsethz!=0.0f) { osi_WrStr(" offset=", 9ul); osic_WrFixed(configoffsethz, 2L, 1UL); osi_WrStr("Hz", 3ul); } if (pnotches) { osi_WrStr(" notches:", 10ul); pnotch = pnotches; while (pnotch) { osi_WrStr(" ", 2ul); osic_WrFixed(pnotch->f1, 0L, 1UL); osi_WrStr("..", 3ul); osic_WrFixed(pnotch->f2, 0L, 1UL); pnotch = pnotch->next; } } osi_WrStrLn("", 1ul); } } if (insamplerate!=0.0f) { pnotch = pnotches; while (pnotch) { pnotch->f1 = X2C_DIVR(pnotch->f1*(float)firlen,insamplerate); pnotch->f2 = X2C_DIVR(pnotch->f2*(float)firlen,insamplerate); pnotch = pnotch->next; } } if (loraprotocols_hexformat==X2C_max_longcard) { if (loraprotocols_verb) loraprotocols_hexformat = 5UL; else loraprotocols_hexformat = 0UL; } pd0 = dems; while (pd0) { if (pd0->cfgopt==0L) pd0->frames[0U].optimize = 0; else if (pd0->cfgopt==1L || baud(pd0->frames[0U].cfgsf, loraprotocols_bwnum)<62.5f) { pd0->frames[0U].optimize = 1; } if (pd0->frames[0U].afcspeed<0.0f) { /* automatic afc on */ if (afcspd<0.0f) afcspd = 0.15f; pd0->frames[0U].afcspeed = afcspd; } if (pd0->frames[0U].cfgsf==0UL) pd0->frames[0U].cfgsf = globsf; if (pd0->frames[0U].cfgcr==0UL) pd0->frames[0U].cfgcr = globcr; if (pd0->frames[0U].datasquelch<0.0f) { pd0->frames[0U].datasquelch = 11.0f+(float)pd0->frames[0U].cfgsf*(-0.79f); } pd0->frames[0U].dataratecorr = pd0->frames[0U].dataratecorr*1.E-6f*(float)(uint32_t) (1UL<frames[0U].cfgsf); if (loraprotocols_verb) { osi_WrStr("bw=", 4ul); osic_WrFixed(X2C_DIVR(5.E+5f,(float)_cnst[loraprotocols_bwnum]), 1L, 1UL); osi_WrStr(" cr=", 5ul); if (pd0->frames[0U].cfgcr==0UL) osi_WrStr("from header", 12ul); else osic_WrINT32(pd0->frames[0U].cfgcr, 1UL); osi_WrStr(" sf=", 5ul); osic_WrINT32(pd0->frames[0U].cfgsf, 1UL); osi_WrStr(" id=", 5ul); if (pd0->frames[0U].synfilter==0UL) osi_WrStr("Off", 4ul); else WrHexCap(pd0->frames[0U].synfilter, 2UL, 0UL); osi_WrStr(" optimize=", 11ul); osic_WrINT32((uint32_t)pd0->frames[0U].optimize, 1UL); osi_WrStr(" drpll=", 8ul); osic_WrFixed(pd0->frames[0U].afcspeed, 3L, 1UL); osi_WrStr(" drc=", 6ul); osic_WrFixed(X2C_DIVR(pd0->frames[0U].dataratecorr*1.E+6f,(float)(uint32_t)(1UL<frames[0U].cfgsf)), 2L, 1UL); osi_WrStr("ppm", 4ul); if (pd0->frames[0U].datasquelch>0.0f) { osi_WrStr(" squelch=", 10ul); osic_WrFixed(pd0->frames[0U].datasquelch, 1L, 1UL); } if (pd0->frames[0U].invertiq) osi_WrStr(" inverted", 10ul); osi_WrStrLn("", 1ul); if (pd0->frames[0U].cfgcr==0UL && pd0->frames[0U].cfgsf<7UL) { osi_WrStrLn("warning: sf<7 needs implizit header", 36ul); } } /* pd^.frames[0].afcspeed:=pd^.frames[0].afcspeed*0.00025*FLOAT(CAST(CARDINAL, SET32{pd^.frames[0].cfgsf})); */ /* i:=pd^.frames[0].cfgsf; */ /* IF i<9 THEN i:=9 END; */ /* pd^.frames[0].afcspeed:=pd^.frames[0].afcspeed*4096.0/FLOAT(CAST(CARDINAL, SET32{i})); */ /* IF pd^.frames[0].cfgsf<=8 THEN pd^.frames[0].afcspeed:=pd^.frames[0].afcspeed*0.5 END; */ /* IF pd^.frames[0].cfgsf<=6 THEN pd^.frames[0].afcspeed:=0.0 END; */ for (i0 = 1UL; i0<=3UL; i0++) { pd0->frames[i0] = pd0->frames[0U]; /* copy parameters to all demodulators */ pd0->frames[i0].label = i0; } /* end for */ pd0 = pd0->next; } } /* end Parms() */ static float db(float r) { return ln0(r)*4.342944819f; } /* end db() */ static void frameout(struct FFRAME * frame, const char finf[], uint32_t finf_len, char hascrc, char crc0, char dcdlost, char opt, uint32_t cr, char text[], uint32_t text_len) { uint32_t td; uint32_t blocksize; float cor; char notchtxt[512]; struct loraprotocols_FPAR par; X2C_PCOPY((void **)&text,text_len); if (frame->dlencfgsf); par.snr = 0.0f; par.maxnf = 0.0f; par.minnf = 0.0f; par.maxlev = 0.0f; par.minlev = 0.0f; par.nf = 0.0f; if (frame->noissum!=0.0f) { par.snr = db(X2C_DIVR(X2C_DIVR(frame->sigsum,frame->noissum)-1.0f,(float)blocksize)); } par.qual = 100UL; par.level = 0.0f; cor = globallevelcor-(float)frame->cfgsf*6.0206f; /* repair level from simplified fft */ if (frame->dcnt>1UL) { par.level = db(X2C_DIVR(frame->sigsum,(float)(frame->dcnt+1UL)))+cor; par.maxlev = db(frame->sigmax)+cor; par.minlev = db(frame->sigmin)+cor; par.nf = db(X2C_DIVR(frame->noissum,(float)(frame->dcnt+1UL)))+cor; par.maxnf = db(frame->noismax)+cor; par.minnf = db(frame->noismin)+cor; par.qual -= (uint32_t)(int32_t)X2C_TRUNCI((X2C_DIVR(frame->eye,(float)frame->dcnt))*200.0f, X2C_min_longint,X2C_max_longint); } if (par.qual<0UL) par.qual = 0UL; if (frame->cfgcr) td = 0UL; else td = 56UL/frame->cfgsf; par.txd = (uint32_t)(int32_t)X2C_TRUNCI(X2C_DIVR((float)(frame->txdel+td)*1000.0f,baud(frame->cfgsf, loraprotocols_bwnum)),X2C_min_longint,X2C_max_longint); par.frametime = (uint32_t)(int32_t)X2C_TRUNCI(X2C_DIVR((float)frame->cnt*1000.0f,baud(frame->cfgsf, loraprotocols_bwnum)),X2C_min_longint,X2C_max_longint); par.drift = 0.0f; if (frame->cnt>3UL) { par.drift = (X2C_DIVR(frame->fc,(float)frame->cnt*(float)(uint32_t)(1UL<cfgsf)))*1.E+6f; } if (frame->invertiq) par.truedf = -frame->df; else par.truedf = frame->df; shownotches(notchtxt, 512ul); par.hascrc = hascrc; par.crc = crc0; par.dcdlost = dcdlost; par.invers = frame->invertiq; par.ax25long = frame->ax25long; par.udpcrcok = frame->udpcrcok; par.axjoin = frame->axjoin; par.needsjunk = frame->needsjunk; par.cr = cr; par.cfgsf = frame->cfgsf; par.synfilter = frame->synfilter; par.label = frame->label; par.idfound = frame->idfound; par.illid = frame->illid; par.fasecorrs = frame->fasecorrs; par.fecbits = frame->fecbits; loraprotocols_sendframe(text, text_len, frame->dlen, par, frame->axpart, 255ul, notchtxt, 512ul, finf, finf_len, frame->ipnum, frame->ipnumraw, frame->udpport, frame->udprawport, frame->udp2); } X2C_PFREE(text); } /* end frameout() */ static void deint(uint32_t sf, uint32_t cr, const uint16_t rb[], uint32_t rb_len, uint8_t hb[], uint32_t hb_len) { uint32_t j1; uint32_t i0; uint32_t tmp; uint32_t tmp0; memset((char *)hb,(char)0,hb_len); tmp = sf-1UL; j1 = 0UL; if (j1<=tmp) for (;; j1++) { tmp0 = cr-1UL; i0 = 0UL; if (i0<=tmp0) for (;; i0++) { if (X2C_IN(j1,16,rb[i0])) hb[(j1+i0)%sf] |= (1U<=5UL) { tmp = sf-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { /* repair bits */ s = hn[i0]; if (cr==5UL) { if ((0x1U & (s^X2C_LSH(s,8,-1)^X2C_LSH(s,8,-2)^X2C_LSH(s,8,-3)^X2C_LSH(s,8,-4)))==0) { hn[i0] |= 0x80U; } } else { b = (uint8_t)s; if (cr==6UL) b = _cnst0[b]; else if (cr==7UL) b = _cnst1[b]; else b = _cnst2[b]; hn[i0] = (uint8_t)b; if ((0x40U & hn[i0])) *hamcorr = 1; } if ((0x80U & hn[i0])==0) *hamok = 0; if (i0==tmp) break; } /* end for */ } } /* end chkhamm() */ static uint16_t gray(uint16_t x) { return x^X2C_LSH(x,16,-1); } /* end gray() */ /* WrInt(CAST(CARDINAL,c),4); WrStr(" "); FOR j:=0 TO sf-1 DO WrInt(ORD(j IN d0[i]),1) END; WrStr(" "); FOR j:=0 TO sf-1 DO WrInt(ORD(j IN d1[i]),1) END; WrStr(" "); FOR j:=0 TO sf-1 DO WrInt(ORD(j IN d2[i]),1) END; WrStr(" "); WrStrLn(""); */ /* FOR i:=0 TO sf-1 DO FOR j:=0 TO cr-1 DO WrInt(ORD(j IN hn0[i]),1); END; WrStr("."); END; WrStrLn(""); FOR i:=0 TO sf-1 DO FOR j:=0 TO cr-1 DO WrInt(ORD(j IN hn1[i]),1); END; WrStr("-"); END; WrStrLn(""); FOR i:=0 TO sf-1 DO FOR j:=0 TO cr-1 DO WrInt(ORD(j IN hn2[i]),1); END; WrStr("+"); END; WrStrLn(""); */ /* FOR i:=0 TO sf-1 DO WrInt(ORD(7 IN hnh[i]),1) END; WrStrLn("=errs"); WrInt(ORD(hamok),1); WrStrLn("=ok1 "); */ /* wrong hamm column */ /*WrInt(i,3); WrInt(j2,3);WrStr("b2 "); */ /* FOR i:=0 TO sf-1 DO FOR j:=0 TO cr-1 DO WrInt(ORD(j IN hn0[i]),1); END; WrStr(":"); END; WrStrLn(""); */ /*WrInt(ORD(hamok),1); WrStrLn("=ok2 --------------------"); */ static uint8_t _cnst3[255] = {255U,254U,252U,248U,240U,225U,194U,133U,11U,23U,47U,94U,188U,120U,241U,227U,198U,141U, 26U,52U,104U,208U,160U,64U,128U,1U,2U,4U,8U,17U,35U,71U,142U,28U,56U,113U,226U,196U,137U,18U,37U,75U, 151U,46U,92U,184U,112U,224U,192U,129U,3U,6U,12U,25U,50U,100U,201U,146U,36U,73U,147U,38U,77U,155U,55U, 110U,220U,185U,114U,228U,200U,144U,32U,65U,130U,5U,10U,21U,43U,86U,173U,91U,182U,109U,218U,181U,107U, 214U,172U,89U,178U,101U,203U,150U,44U,88U,176U,97U,195U,135U,15U,31U,62U,125U,251U,246U,237U,219U,183U, 111U,222U,189U,122U,245U,235U,215U,174U,93U,186U,116U,232U,209U,162U,68U,136U,16U,33U,67U,134U,13U,27U, 54U,108U,216U,177U,99U,199U,143U,30U,60U,121U,243U,231U,206U,156U,57U,115U,230U,204U,152U,49U,98U,197U, 139U,22U,45U,90U,180U,105U,210U,164U,72U,145U,34U,69U,138U,20U,41U,82U,165U,74U,149U,42U,84U,169U,83U, 167U,78U,157U,59U,119U,238U,221U,187U,118U,236U,217U,179U,103U,207U,158U,61U,123U,247U,239U,223U,191U, 126U,253U,250U,244U,233U,211U,166U,76U,153U,51U,102U,205U,154U,53U,106U,212U,168U,81U,163U,70U,140U,24U, 48U,96U,193U,131U,7U,14U,29U,58U,117U,234U,213U,170U,85U,171U,87U,175U,95U,190U,124U,249U,242U,229U, 202U,148U,40U,80U,161U,66U,132U,9U,19U,39U,79U,159U,63U,127U}; static char decodechirp(struct FFRAME * frame, const struct BINS bins, char opti) { int32_t o; uint32_t burst; uint32_t crctry; uint32_t datalen; uint32_t cr; uint32_t sf; uint32_t st; uint32_t try0; uint32_t fulllen; uint32_t j1; uint32_t i0; int32_t bursttry; int32_t mintry; int32_t maxtry; float lv; float v; float minsnr; float maxlev; char bt; /* c:SET16; */ uint8_t s; /* b:CARD8; */ char dcd; char explicit; char crcok; char burstcorr; char hamcorr; char hamok; char ishead; NIBBBLOCK hnofec; NIBBBLOCK hn; char text[261]; uint16_t chirps[8]; char br[2]; struct FFRAME * anonym; uint32_t tmp; { /* with */ struct FFRAME * anonym = frame; sf = anonym->cfgsf; cr = anonym->cfgcr; datalen = anonym->cfgdatalen; explicit = cr==0UL; ishead = explicit && anonym->dcnt<8UL; /* we are in header */ opti = opti || ishead; /* header is always optimized */ o = 0L; if (opti) o = 2L; sf -= (uint32_t)o; if (ishead) cr = 8UL; else if (explicit) cr = anonym->crfromhead; else anonym->crfromhead = cr; if (cr<4UL) cr = 4UL; else if (cr>8UL) cr = 8UL; burstcorr = 0; if (anonym->dcnt==0UL) { /* start new frame */ anonym->chirpc = 0UL; anonym->nibbc = 0UL; anonym->dlen = datalen; /* for implicit header */ anonym->withcrc = anonym->implicitcrc; anonym->fecinfo[0] = 0; anonym->oneerrs = 0UL; anonym->fecbits = 0UL; } anonym->bintab[anonym->chirpc] = bins; ++anonym->chirpc; if (anonym->chirpc>=cr) { /* block complete */ dcd = anonym->timeoutchirpc = 0UL; /*-fec */ tmp = cr-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { chirps[i0] = gray((uint16_t)(uint32_t)X2C_TRUNCC(anonym->bintab[i0].b[0U].freq,0UL,X2C_max_longcard)); /* only for corr bit count */ if (i0==tmp) break; } /* end for */ /* IF NOT opti THEN fecneighbour(bintab, cr, sf) END; */ try0 = 0UL; maxlev = 0.0f; maxtry = -1L; minsnr = X2C_max_real; mintry = -1L; bursttry = -1L; burst = 0UL; st = 0UL; deint(sf, cr, chirps, 8ul, hnofec, 12ul); /* deint block for corrected bits count */ for (;;) { lv = 0.0f; tmp = cr-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { if (try0/4UL==i0) j1 = try0&3UL; else j1 = 0UL; chirps[i0] = gray((uint16_t)(uint32_t)X2C_TRUNCC(anonym->bintab[i0].b[j1].freq,0UL, X2C_max_longcard)); if (try0==0UL) { v = anonym->bintab[i0].noise; /* noise */ if (v!=0.0f) { v = X2C_DIVR(anonym->bintab[i0].b[0U].lev,v); /* snr of best bin */ } if (vbintab[i0].halfnoisc) { burst = anonym->bintab[i0].halfnoisc; bursttry = (int32_t)i0; } } else lv = anonym->bintab[i0].b[j1].lev; if (i0==tmp) break; } /* end for */ if (burst>=8UL) { mintry = bursttry; burstcorr = 1; } deint(sf, cr, chirps, 8ul, hn, 12ul); /* deint block */ chkhamm(hn, cr, sf, &hamok, &hamcorr); if (st>0UL) { /* final try */ if (st==2UL) { /* repair weekest chirp */ if (!nocrcfec) { if (anonym->oneerrs==0UL) { /* save block for later tries to fit crc */ memcpy(anonym->oneerr,hn,12u); anonym->oneerrs = anonym->nibbc; } else anonym->oneerrs = 1UL; } tmp = sf-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { /* invert wrong bits */ bt = X2C_IN(mintry,8,hn[i0]); hn[i0] &= ~(1U<maxlev) { /* best bin with check ok */ maxlev = lv; maxtry = (int32_t)try0; } } ++try0; if (try0>=4UL*cr) { /* all combinations tested */ try0 = 0UL; st = 1UL; if (maxtry<0L) { /* no valid checkbits found */ if (mintry>=0L) { try0 = 0UL; st = 2UL; } } else try0 = (uint32_t)maxtry; } } if (st==2UL) { if (burstcorr) aprsstr_Append(anonym->fecinfo, 96ul, "b", 2ul); else aprsstr_Append(anonym->fecinfo, 96ul, "~", 2ul); } else if (hamok) { if (st==1UL) aprsstr_Append(anonym->fecinfo, 96ul, "^", 2ul); else if (hamcorr) aprsstr_Append(anonym->fecinfo, 96ul, "h", 2ul); else if (cr==4UL) aprsstr_Append(anonym->fecinfo, 96ul, "=", 2ul); else aprsstr_Append(anonym->fecinfo, 96ul, "+", 2ul); } else aprsstr_Append(anonym->fecinfo, 96ul, "-", 2ul); tmp = sf-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { /* count changed bits */ for (j1 = 0UL; j1<=3UL; j1++) { if (X2C_IN(j1,8,hn[i0]^hnofec[i0])) ++anonym->fecbits; } /* end for */ if (i0==tmp) break; } /* end for */ /*-fec */ if (loraprotocols_verb2) { if (isize==1UL) v = 8.0f; else if (isize==2UL) v = 0.03125f; else v = 4.0f; tmp = cr-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { for (j1 = 0UL; j1<=3UL; j1++) { strncpy(br,"()",2u); if (st==1UL) { /* best bin sum */ if (try0/3UL!=i0 && j1==0UL || try0/3UL==i0 && try0%3UL==j1) { strncpy(br,"[]",2u); } } else if (st==2UL) { /* weekest bin */ if (mintry!=(int32_t)i0 && j1==0UL) { strncpy(br,"[]",2u); } } else if (j1==0UL) strncpy(br,"[]",2u); if (j1==0UL && anonym->bintab[i0].splt<0.0f) { osic_WrFixed((float) -(sqrt((double)(float)fabs(anonym->bintab[i0].splt)) *(double)v), 1L, 5UL); } else { osic_WrFixed((float)(sqrt((double)anonym->bintab[i0].b[j1].lev)*(double)v), 1L, 5UL); } osi_WrStr((char *) &br[0U], 1u/1u); osic_WrFixed(anonym->bintab[i0].b[j1].freq, 2L, 5UL); osi_WrStr((char *) &br[1U], 1u/1u); } /* end for */ osi_WrStr(" n=", 4ul); osic_WrFixed((float)(sqrt((double)anonym->bintab[i0].noise)*(double)v), 1L, 1UL); if (anonym->bintab[i0].fecnbr==1L) osi_WrStr(" f+1", 5ul); else if (anonym->bintab[i0].fecnbr==-1L) osi_WrStr(" f-1", 5ul); osi_WrStr(" ", 2ul); osic_WrFixed((X2C_DIVR((float)anonym->bintab[i0].halfnoisc, (float)(uint32_t)(1UL<cfgsf)))*100.0f, 1L, 1UL); osi_WrStrLn("%", 2ul); if (i0==tmp) break; } /* end for */ } if (loraprotocols_verb2) osi_WrStrLn("", 1ul); if (ishead) { /* head block */ if (headcrc(hn, 12ul)) { anonym->dlen = (uint32_t)(uint8_t)(X2C_LSH(hn[0U]&0xFU,8,4)|hn[1U]&0xFU); anonym->withcrc = (0x1U & hn[2U])!=0; anonym->crfromhead = 4UL+(uint32_t)(uint8_t)(X2C_LSH(hn[2U],8,-1)&0x7U); if (anonym->crfromhead>8UL) anonym->crfromhead = 8UL; tmp = sf-1UL; i0 = 5UL; if (i0<=tmp) for (;; i0++) { /* 5 header nibbles copy rest to data */ anonym->nibbs[anonym->nibbc] = hn[i0]&0xFU; ++anonym->nibbc; if (i0==tmp) break; } /* end for */ } else { if (loraprotocols_verb2) osi_WrStrLn("head crc error", 15ul); anonym->dlen = 0UL; /* show metadata and stop frame soon */ anonym->withcrc = 0; } } else if (dcd) { /* data block */ tmp = sf-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { anonym->nibbs[anonym->nibbc] = hn[i0]&0xFU; if (anonym->nibbc<522UL) ++anonym->nibbc; if (i0==tmp) break; } /* end for */ } } if (anonym->chirpc==0UL) { /* block complete dcd-loss over 1 block */ if (explicit) { /* len from header */ if (datalen && anonym->dlen>datalen) anonym->dlen = datalen; fulllen = anonym->dlen; if (anonym->withcrc) fulllen += 2UL; } else if (datalen==0UL) { /* len from dcd */ anonym->dlen = anonym->nibbc/2UL; if (dcd) fulllen = 255UL; else fulllen = anonym->dlen; /* fulllen:=dlen; */ if (anonym->withcrc && anonym->dlen>=2UL) anonym->dlen -= 2UL; } else { /* fixed len */ anonym->dlen = datalen; fulllen = datalen; if (anonym->withcrc) fulllen += 2UL; } if (!dcd || anonym->nibbc>=fulllen*2UL) { /* frame complete or implicit variable len dcd out */ if (anonym->nibbc>1UL) { crctry = 0UL; for (;;) { tmp = anonym->nibbc/2UL-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { s = anonym->nibbs[i0*2UL]&0xFU|X2C_LSH(anonym->nibbs[i0*2UL+1UL],8,4)&0xF0U; if (i0dlen) s = s^(uint8_t)_cnst3[i0]; text[i0] = (char)s; if (i0==tmp) break; } /* end for */ if (anonym->dlen>anonym->nibbc/2UL) { anonym->dlen = anonym->nibbc/2UL; /* remove dcd lost junk */ } crcok = 0; if (!anonym->withcrc) break; i0 = 0UL; if (anonym->dlen>2UL) { i0 = crc(text, 261ul, 0UL, anonym->dlen-2UL, 0UL); } if (anonym->dlen>1UL) { i0 = (uint32_t)((uint16_t)i0^(uint16_t)((uint32_t)(uint8_t)text[anonym->dlen-2UL]*256UL)) ; } if (anonym->dlen>0UL) { i0 = (uint32_t)((uint16_t)i0^(uint16_t)(uint32_t)(uint8_t)text[anonym->dlen-1UL]); } crcok = (char)(i0&255UL)==text[anonym->dlen] && (char)(i0/256UL)==text[anonym->dlen+1UL]; if ((crcok || anonym->oneerrs<=1UL) || crctry>=4UL) break; trycrc(anonym->nibbs, anonym->oneerr, 12ul, &anonym->oneerrs, &crctry, sf); } if (crctry>0UL) ++anonym->fecbits; if (anonym->oneerrs>1UL && crctry>0UL) { i0 = 0UL; for (;;) { if (anonym->fecinfo[i0]==0) break; if (anonym->fecinfo[i0]=='~') { anonym->fecinfo[i0] = 'c'; break; } if (anonym->fecinfo[i0]=='b') { anonym->fecinfo[i0] = 'C'; break; } ++i0; } } frameout(frame, anonym->fecinfo, 96ul, anonym->withcrc, crcok, !dcd, opti, cr, text, 261ul); } return 1; } } } return 0; } /* end decodechirp() */ #define lorarx_BIRDSPEED 0.01 /* floating median speed */ #define lorarx_MINBIRDYLEV 0.7 /* minimal sqr level of a birdy */ static void findbirdies(uint32_t from, uint32_t to, const struct Complex fir[], uint32_t fir_len) { uint32_t optbirds; uint32_t nc; uint32_t len; uint32_t f1; uint32_t f0; uint32_t hsize; uint32_t j1; uint32_t i0; int32_t n; float iv; float v; float med; struct Complex * anonym; uint32_t tmp; len = (pbirdbuf->Len0-1)+1UL; while (birdposAdr[birdpos] = fir[from]; ++from; ++birdpos; } if (birdpos>=len) { /* fft buffer full */ ++notchcnt; if (notchcnt>autonotch) { notchcnt = 0UL; birdpos = 0UL; i0 = 1UL; do { ++i0; } while (len>(uint32_t)(1UL<Adr, pbirdbuf->Len0, i0, 0); hsize = len/2UL; tmp = len-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { { /* with */ struct Complex * anonym = &pbirdbuf->Adr[i0]; anonym->Re = anonym->Re*anonym->Re+anonym->Im*anonym->Im; } if (i0==tmp) break; } /* end for */ tmp = len-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { /* reorder freq */ if (i0<=hsize) j1 = hsize-i0; else j1 = hsize*3UL-i0; pbirdbuf->Adr[i0].Im = pbirdbuf->Adr[j1].Re; if (i0==tmp) break; } /* end for */ i0 = (uint32_t)X2C_TRUNCC(X2C_DIVR((float)len*0.5f,downsample),0UL,X2C_max_longcard); /* use only passband area of filter */ if (i0=len) f1 = len-1UL; med = 1.E-7f; tmp = f1; i0 = f0; if (i0<=tmp) for (;; i0++) { med = med+pbirdbuf->Adr[i0].Im; /* noise level */ if (i0==tmp) break; } /* end for */ med = X2C_DIVR(med,(float)((f1-f0)+1UL)); iv = X2C_DIVR(1.0f,med); tmp = f1; i0 = f0; if (i0<=tmp) for (;; i0++) { v = pbirdhist->Adr[i0]; pbirdhist->Adr[i0] = v+((pbirdbuf->Adr[i0].Im-med)*iv-v)*0.01f; if (i0==tmp) break; } /* end for */ /*- find notch start level */ optbirds = ((f1-f0)+5UL)/5UL; /* limit notches */ n = 0L; for (;;) { if (notchthres<0.7f) { notchthres = 0.7f; break; } nc = 0UL; tmp = f1; i0 = f0; if (i0<=tmp) for (;; i0++) { if (pbirdhist->Adr[i0]>notchthres) ++nc; if (i0==tmp) break; } /* end for */ /*WrStr("(");WrInt(nc,1);WrStr(")"); */ if (nc>optbirds) { if (n<0L) break; notchthres = notchthres+0.05f; /*WrFixed(notchthres, 2,10); */ n = 1L; } else { if (n>0L) break; notchthres = notchthres-0.05f; /*WrFixed(notchthres, 2,10); */ n = -1L; } } /*WrFixed(notchthres, 2,12); WrStrLn("=tres"); */ makefir(downsample, pfirtab, pbirdhist, notchthres); } } } /* end findbirdies() */ static void viewhotmap(uint32_t imax, uint32_t bufsize, const float amp[], uint32_t amp_len) /* show bins around best */ { uint32_t i0; float v; uint32_t tmp; osic_WrINT32(imax, 4UL); /* IF rev THEN WrStr("- ") ELSIF sort THEN WrStr("> ") ELSE WrStr(": ") END; */ osi_WrStr(": ", 3ul); v = X2C_DIVR(1.0f,amp[imax]+1.E-6f); tmp = binsview; i0 = 0UL; if (i0<=tmp) for (;; i0++) { osic_WrFixed((float)sqrt((double)(amp[((bufsize+i0+imax)-binsview/2UL)%bufsize]*v)), 2L, 4UL); osi_WrStr(" ", 2ul); if (i0==tmp) break; } /* end for */ } /* end viewhotmap() */ static void fasejumps(struct Complex b[], uint32_t b_len, uint32_t guess, uint32_t sf, float * am, float * fm) { uint32_t m; uint32_t j1; uint32_t i0; struct Complex l; struct Complex o; float fsf; float bw; float al; float cor; float f; float co; float si; uint16_t wgi; struct Complex * anonym; uint32_t tmp; m = sf-guess; j1 = (m*65536UL)/sf; --m; wgi = 0U; f = 0.0f; o.Re = 0.0f; o.Im = 0.0f; l = o; al = 0.0f; fsf = (float)sf; bw = X2C_DIVR(5.0f,fsf); /* lowpass bandwidth */ tmp = sf-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { if (i0==m) { l.Re = 0.0f; /* notch out fase jump point */ l.Im = 0.0f; o = l; } si = DDS[wgi]; co = DDS[(uint16_t)((uint32_t)wgi+16384UL)]; { /* with */ struct Complex * anonym = &b[i0]; l.Re = l.Re+((anonym->Im*co-anonym->Re*si)-l.Re)*bw; /* rotate input with sin/cos and filter 1st order lowpass i and q */ l.Im = l.Im+((anonym->Re*co+anonym->Im*si)-l.Im)*bw; } al = al+l.Im*l.Im+l.Re*l.Re; /* sum up absolute value from lowpass */ f = (f+l.Im*o.Re)-l.Re*o.Im; /* sum up frequency deviation from zero */ o = l; wgi += (uint16_t)j1; if (i0==tmp) break; } /* end for */ cor = X2C_DIVR((float)m,fsf)-0.5f; al = al*(1.85f-cor*cor*2.57f); /* correct level from delay loss of lowpass */ *fm = 0.0f; if (al!=0.0f) *fm = X2C_DIVR(f*fsf*0.17f,al); if (*fm>0.99f) *fm = 0.99f; else if (*fm<(-0.99f)) *fm = (-0.99f); /*WrStr(" f="); WrInt(guess,4); WrStr("/");WrFixed(fm,2,5); WrStr("/");WrFixed(al*fsf/am,2,5); WrStr(" "); */ *am = al*fsf; } /* end fasejumps() */ static void getbin(struct Complex c[], uint32_t c_len, struct BINS * bins, uint32_t sf, float offset, char rev, char opt, char sort, char invers, char inframe, uint32_t * corrcnt) { uint32_t bufsize; uint32_t imax; uint32_t jj; uint32_t j1; uint32_t i0; uint16_t wgi; int32_t ii; float fm1; float am1; float fm; float am; float mnois; float vv; float v; float co; float si; float max0; char ok0; float amp[4096]; struct Complex tmp[4096]; struct Complex * anonym; struct Complex * anonym0; struct Complex * anonym1; uint32_t tmp0; bufsize = (uint32_t)(1UL<Re*co-anonym->Im*si; anonym->Im = anonym->Im*co+anonym->Re*si; anonym->Re = v; } wgi += (uint16_t)j1; j1 += (uint32_t)ii; if (i0==tmp0) break; } /* end for */ } else { tmp0 = bufsize-1UL; i0 = 0UL; if (i0<=tmp0) for (;; i0++) { /* dechirp */ si = DDS[wgi]; co = DDS[(uint16_t)((uint32_t)wgi+16384UL)]; { /* with */ struct Complex * anonym0 = &c[i0]; v = anonym0->Im*co-anonym0->Re*si; anonym0->Im = anonym0->Re*co+anonym0->Im*si; anonym0->Re = v; } wgi += (uint16_t)j1; j1 += (uint32_t)ii; if (i0==tmp0) break; } /* end for */ } if (outdechirped>=0L) { osi_WrBin(outdechirped, (char *)c, (c_len*sizeof(struct Complex))/1u, c_len*sizeof(struct Complex)); } X2C_MOVE((char *)c,(char *)tmp,c_len*sizeof(struct Complex)); Transform(c, c_len, sf, 0); memset((char *)bins,(char)0,sizeof(struct BINS)); bins->noise = 0.0f; max0 = (-1.0f); tmp0 = bufsize-1UL; i0 = 0UL; if (i0<=tmp0) for (;; i0++) { { /* with */ struct Complex * anonym1 = &c[i0]; v = anonym1->Re*anonym1->Re+anonym1->Im*anonym1->Im; } amp[i0] = v; bins->noise = bins->noise+v; if (v>max0) { max0 = v; /* find strongest bin */ imax = i0; } if (i0==tmp0) break; } /* end for */ mnois = max0*0.7f; v = X2C_DIVR(bins->noise,(float)bufsize); for (i0 = 0UL; i0<=4UL; i0++) { bins->noise = (bins->noise+v)-amp[(((imax+bufsize)-2UL)+i0)%bufsize]; /* subtract data bins from signal sum (noise + data) */ } /* end for */ if (bins->noise<0.0f) bins->noise = 0.0f; bins->noise = X2C_DIVR(bins->noise,(float)bufsize); /* IF binsview>0 THEN viewhotmap(imax, bufsize, amp) END; (* show bins around best *) */ /*- find fase jump */ fm = 2.0f; if (inframe) { ok0 = 1; fasejumps(tmp, 4096ul, imax, bufsize, &am, &fm); /* with fft found peak */ if (sort) { i0 = (imax+1UL)%bufsize; fasejumps(tmp, 4096ul, i0, bufsize, &am1, &fm1); /* try next higher freq */ if ((float)fabs(fm1)<(float)fabs(fm)) ok0 = 0; else { i0 = ((imax+bufsize)-1UL)%bufsize; fasejumps(tmp, 4096ul, i0, bufsize, &am1, &fm1); if ((float)fabs(fm1)<(float)fabs(fm)) { ok0 = 0; /* fft was too high */ } } if (!ok0) { /* got different result with split parts so modify fft bins */ imax = i0; fm = fm1; am = am1; bins->splt = -am; /* for -V view only */ ++*corrcnt; /* for monitoring only */ } } /*WrStr(" ------- "); */ amp[imax] = am; if (binsview>0UL) { viewhotmap(imax, bufsize, amp, 4096ul); /* show corrected bins around best */ osi_WrStr(" p", 3ul); osic_WrFixed(offset, 2L, 5UL); osi_WrStrLn("", 1ul); } } bins->halfnoisc = 0UL; jj = 0UL; max0 = amp[imax]; for (;;) { bins->b[jj].lev = max0; if (fm<=1.0f) v = fm; else { v = 0.0f; if (max0>0.0f) { v = lim(X2C_DIVR(amp[(imax+1UL)%bufsize]-amp[((imax+bufsize)-1UL)%bufsize],max0), 0.999f); } v = (float)(0.5*sqrt((double)(float)fabs(v))*(double)fsign(v)); } /*WrStr(" -----------["); WrFixed(v,2,0); WrStr("] "); */ v = v+0.5f+(float)imax; if (opt) v = v*0.25f+0.375f; bins->b[jj].freq = v; if (!sort || jj>=3UL) break; ++jj; vv = max0; max0 = (-1.0f); tmp0 = bufsize-1UL; i0 = 0UL; if (i0<=tmp0) for (;; i0++) { v = amp[i0]; if (v>max0 && vmnois) ++bins->halfnoisc; if (i0==tmp0) break; } /* end for */ } } /* end getbin() */ union _3; union _3 { struct Complex c[2048]; short i0[8192]; uint8_t b[16384]; }; static char inreform(struct Complex b[], uint32_t b_len, uint32_t * wp) { uint32_t rs; uint32_t bs; uint32_t i0; int32_t res; union _3 ib; char * p; uint32_t tmp; bs = isize*4096UL; rs = 0UL; do { p = (char *) &ib.b[rs]; res = osi_RdBin(iqfd, p, 65536ul, bs-rs); if (res<=0L) { /* eof or broken pipe */ if (!notexitonbrokenpipe || !osi_IsFifo(iqfd)) return 0; /* do not loop in normal file */ osic_Close(iqfd); usleep(10000000UL); iqfd = osi_OpenRead(iqfn, 1024ul); res = 0L; } rs += (uint32_t)res; } while (rsAdr, pfir->Len0, &firwp)) return 0; if (firwp>firlen) { if (shiftstep) { tmp = firwp-1UL; i0 = firlen; if (i0<=tmp) for (;; i0++) { { /* with */ struct Complex * anonym = &pfir->Adr[i0]; w0 = phasereg/65536UL; si = DDS[w0]; co = DDS[(uint16_t)(w0+16384UL)]; sum.Re = anonym->Re*si-anonym->Im*co; anonym->Im = anonym->Re*co+anonym->Im*si; anonym->Re = sum.Re; } phasereg += shiftstep; if (i0==tmp) break; } /* end for */ } if (autonotch) findbirdies(firlen, firwp, pfir->Adr, pfir->Len0); /*fir resample, interpolate, notch */ w0 = iqwrite; frd = 0UL; do { sum.Re = 0.0f; sum.Im = 0.0f; /* fp:=(SUBSAMP-1-ASH(sampc,SUBSAMPBITS-24) MOD SUBSAMP) * firlen; (* interpolate *) */ fp = (sampc>>20&15UL)*firlen; /* interpolate */ if (complexfir) { tmp = (frd+firlen)-1UL; i0 = frd; if (i0<=tmp) for (;; i0++) { fc = pfirtab->Adr[fp]; ++fp; sum.Re = (sum.Re+pfir->Adr[i0].Re*fc.Re)-pfir->Adr[i0].Im*fc.Im; sum.Im = sum.Im+pfir->Adr[i0].Re*fc.Im+pfir->Adr[i0].Im*fc.Re; if (i0==tmp) break; } /* end for */ } else { /* symmetric fir, save cpu if no notches */ tmp = (frd+firlen)-1UL; i0 = frd; if (i0<=tmp) for (;; i0++) { f = pfirtab->Adr[fp].Im; ++fp; sum.Re = sum.Re+pfir->Adr[i0].Re*f; sum.Im = sum.Im+pfir->Adr[i0].Im*f; if (i0==tmp) break; } /* end for */ } if (noisblanker) { f = sum.Re*sum.Re+sum.Im*sum.Im; pknoisemed = pknoisemed*pknoisedown+(f-pknoisemed)*pknoiseup; if (f>pknoisemed*2.0f) { /* limit to median level */ f = X2C_DIVR(pknoisemed*2.0f,f); /* raw sqrt */ sum.Re = sum.Re*f; sum.Im = sum.Im*f; } } iqbuf[iqwrite] = sum; iqwrite = iqwrite+1UL&8191UL; sampc += samprate; frd += sampc>>24; sampc = (uint32_t)((uint32_t)sampc&0xFFFFFFUL); } while (frd+firlen=0L) { /* debug out */ if (iqwrite0UL) { osi_WrBin(outfiltered, (char *)iqbuf, sizeof(struct Complex [8192])/1u, iqwrite*sizeof(struct Complex)); } } if (firwp>frd) { firwp -= frd; X2C_MOVE((char *) &pfir->Adr[frd],(char *) &pfir->Adr[0UL],firwp*sizeof(struct Complex)); } } return 1; } /* end readsampsfir() */ #define lorarx_IQSIZE 8 static char getsamps(struct Complex c[], uint32_t c_len, uint32_t * iqread, uint32_t jump) { uint32_t i0; uint32_t newsamps; newsamps = (iqwrite+8192UL)-*iqread&8191UL; if (newsamps8192UL) { /* wraps around */ i0 = 8192UL-*iqread; X2C_MOVE((char *) &iqbuf[*iqread],(char *)c,i0*8UL); if (i0<=c_len-1) X2C_MOVE((char *)iqbuf,(char *) &c[i0],(((c_len-1)+1UL)-i0)*8UL); } else X2C_MOVE((char *) &iqbuf[*iqread],(char *)c,((c_len-1)+1UL)*8UL); *iqread = *iqread+(c_len-1)+1UL&8191UL; return 1; } /* end getsamps() */ static float squelch(const struct BINS bins) { return X2C_DIVR(bins.b[0U].lev,bins.noise+1.E-9f); } /* end squelch() */ static char nextchirp(struct FFRAME * frame) { struct BINS bins; uint32_t blocksize; uint32_t i0; float sq; float fi; char opt; pCB anonym; pCB anonym0; blocksize = (uint32_t)(1UL<cfgsf); /* LOOP */ if (frame->state==lorarx_sSLEEP) { frame->jp = blocksize; frame->cnt = 0UL; frame->dcnt = 0UL; frame->iqread = iqwrite; /* start decode not from old data */ frame->state = lorarx_sHUNT; frame->fc = 0.0f; frame->fci = 0.0f; frame->fcfix = 0.0f; } if (frame->jp==0UL) frame->jp = blocksize; if (!(anonym = fftbufs[frame->cfgsf],getsamps(anonym->Adr, anonym->Len0, &frame->iqread, frame->jp))) return 1; /* try later to get enough samples */ frame->jp = blocksize; opt = frame->state==lorarx_sDATA && (frame->optimize || frame->cfgcr==0UL && frame->dcnt<8UL); anonym0 = fftbufs[frame->cfgsf]; getbin(anonym0->Adr, anonym0->Len0, &bins, frame->cfgsf, frame->fci+frame->fc+frame->fcfix, frame->state==lorarx_sREV1 || frame->state==lorarx_sREV2, opt, frame->state==lorarx_sDATA, frame->invertiq, frame->state>=lorarx_sSYNRAW, &frame->fasecorrs); frame->fcfix = frame->fcfix+frame->dataratecorr; /* correct known samplerate error */ /*- afc */ if (frame->state>=lorarx_sSYNRAW) { fi = bins.b[0U].freq-0.5f; if (frame->state==lorarx_sSYNRAW || frame->state==lorarx_sID) { if ((float)(uint32_t)(1UL<cfgsf)-fi<=4.0f) { fi = fi-(float)(uint32_t)(1UL<cfgsf); } else { fi = fi-fsign(fi)*(float)(uint32_t)X2C_TRUNCC(((float)fabs(fi)+4.0f)*0.125f,0UL, X2C_max_longcard)*8.0f; } if (frame->state==lorarx_sID && (float)fabs(fi)>1.0f) fi = 0.0f; } else if (opt) fi = (fi-ftrunc(fi+0.5f))*4.0f; else fi = fi-ftrunc(fi+0.5f); if (frame->state>=lorarx_sDATA && !opt) fi = lim(fi, 1.0f); else fi = lim(fi, 4.0f); /*IF verb2 THEN WrStr("f,fc,fci="); WrFixed(bins.b[0].freq, 2,1); WrStr(" "); WrFixed(frame.fc, 2,1); WrStr(" "); WrFixed(frame.fci, 2,1); WrStr(" "); END; */ if (frame->state>=lorarx_sDATA) { frame->eye = frame->eye+(float)fabs(X2C_DIVR(fi,(float)(1UL+3UL*(uint32_t)opt))); /* for statistics */ } fi = fi*frame->afcspeed*(1.0f-flmin(1.0f, X2C_DIVR(18.0f*bins.noise,bins.b[0U].lev))); /* lower afc speed on noisy signal */ /*WrFixed(bins.b[0].lev/bins.noise,2,1); WrStr(" "); */ if (frame->state==lorarx_sREV1 || frame->state==lorarx_sREV2) fi = 0.0f; /* IF (frame.state>=sDATA) & NOT opt THEN fi:=fi*0.1 END; */ fi = fi*(X2C_DIVR(16.0f,(float)(frame->cnt+16UL))); /* 12 12 */ /* fast lock with sync and optimized chirps */ frame->fc = (frame->fc-frame->fci)-fi*12.0f; /*12.0*/ /* datarate lead-lag loop filter stability*/ frame->fci = frame->fci+fi; } /*- afc */ if (frame->state==lorarx_sHUNT) { if (frame->cnt==1UL && (float)fabs(freqmod(frame->lastbin-bins.b[0U].freq, (int32_t)blocksize))<=1.0f) { /* 2 good preamble chirps */ frame->jp = blocksize-(uint32_t)X2C_TRUNCC(bins.b[0U].freq,0UL,X2C_max_longcard); frame->state = lorarx_sSYNRAW; frame->idfound = 0UL; frame->eye = 0.0f; /* frame.fcfix:=-(bins.b[0].freq-VAL(REAL, TRUNC(bins.b[0].freq))); */ frame->fc = 0.0f; frame->fci = 0.0f; if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStr(" jump:", 7ul); osic_WrINT32(frame->jp, 1UL); osi_WrStrLn("", 1ul); } } frame->cnt = 0UL; frame->lastbin = bins.b[0U].freq; } else if (frame->state==lorarx_sSYNRAW) { /*IF frame.cnt=10 THEN frame.fcfix:=frame.fcfix-0.47 END; (* stress test datarate pll *) */ fi = bins.b[0U].freq; if ((float)blocksize-fi<=4.0f) fi = fi-(float)blocksize; if ((float)fabs(fi)>=4.0f) { i0 = (uint32_t)X2C_TRUNCC((bins.b[0U].freq+3.5f)*0.125f,0UL,X2C_max_longcard); if (i0>15UL || (frame->synfilter>=256UL && (frame->synfilter&255UL)>=16UL) && i0!=(frame->synfilter&255UL) /16UL) { if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStr(" ", 2ul); osi_WrStrLn("wrong first syn nibble ", 24ul); osic_WrINT32(1UL, 0UL); } if (frame->idfound) { /* second wrong id */ frame->state = lorarx_sHUNT; } frame->idfound = 1UL; /* set is not first sync exception */ } else { if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStr(" ", 2ul); osic_WrFixed(fi-0.5f, 2L, 1UL); osi_WrStrLn(" state=SYN 1 OK", 16ul); } frame->idfound = i0; frame->state = lorarx_sID; } } else { /* good syn frame */ frame->idfound = 0UL; /*IF frame.cnt=2 THEN frame.fcfix:=frame.fcfix-fi+0.5 END; */ if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStr(" ", 2ul); osic_WrFixed(fi-0.5f, 2L, 1UL); osi_WrStrLn(" state=SYN", 11ul); } } } else if (frame->state==lorarx_sID) { if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStr(" ", 2ul); osic_WrFixed(bins.b[0U].freq-0.5f, 2L, 1UL); osi_WrStrLn(" state=NETID", 13ul); } i0 = (uint32_t)X2C_TRUNCC((bins.b[0U].freq+3.5f)*0.125f,0UL,X2C_max_longcard); if (i0==0UL) { frame->state = lorarx_sSYNRAW; /* syn sequence with 1 exception */ frame->idfound = 0UL; } else { frame->state = lorarx_sREV1; fi = (float)(i0*8UL); /* use sync pattern for median zero freq */ frame->illid = i0/16UL; /* some chips send second id chirp >15 */ i0 = i0&15UL; frame->idfound = frame->idfound*16UL+i0; if (i0>255UL || (frame->synfilter>=256UL && (frame->synfilter&15UL)>0UL) && i0!=(frame->synfilter&15UL)) { frame->state = lorarx_sHUNT; if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStrLn(" wrong second syn nibble", 25ul); } } } } else if (frame->state==lorarx_sREV1) { if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStrLn(" state=REVERS1", 15ul); } frame->lastbin = freqmod(bins.b[0U].freq, (int32_t)blocksize)-0.5f; frame->lastsq = squelch(bins); frame->state = lorarx_sREV2; } else if (frame->state==lorarx_sREV2) { if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStr(" ", 2ul); osic_WrFixed(bins.b[0U].freq-0.5f, 2L, 1UL); osi_WrStrLn(" state=REVERS2", 15ul); } fi = freqmod(bins.b[0U].freq, (int32_t)blocksize)-0.5f; sq = squelch(bins); if ((float)fabs(freqmod(frame->lastbin-fi, (int32_t)blocksize))>1.0f) { /* 2 good rev chirps */ if (frame->lastsq>squelch(bins)) { /* else use best of the 2 */ fi = frame->lastbin; sq = frame->lastsq; } } else fi = freqmod((fi+frame->lastbin)*0.5f, (int32_t)blocksize); if (sq>frame->datasquelch) { /* usable reverse chirp */ fi = fi*0.5f; /* real freq halfway between forward & rev frames */ frame->df = (int32_t)X2C_TRUNCI(fi*baud(frame->cfgsf, loraprotocols_bwnum),X2C_min_longint,X2C_max_longint); frame->jp = (uint32_t)((int32_t)(blocksize+(blocksize>>2))+(int32_t)X2C_TRUNCI(fi,X2C_min_longint, X2C_max_longint)); if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStr(" jump/4:", 9ul); osic_WrINT32(frame->jp, 1UL); osi_WrStrLn("", 1ul); } frame->fcfix = (frame->fcfix-(float)(int32_t)X2C_TRUNCI(fi,X2C_min_longint,X2C_max_longint))-1.0f; frame->state = lorarx_sDATA; frame->dcnt = 0UL; frame->txdel = frame->cnt; /* store for show preamble time */ frame->timeout = 0UL; frame->fp = frame->iqread; frame->fasecorrs = 0UL; frame->sigsum = 0.0f; frame->sigmin = X2C_max_real; frame->sigmax = 0.0f; frame->noissum = 0.0f; frame->noismax = 0.0f; frame->noismin = X2C_max_real; } else { frame->state = lorarx_sHUNT; if (loraprotocols_verb2) osi_WrStrLn("rev chirp timeout", 18ul); } } else { /* data */ if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStr(" ", 2ul); osic_WrINT32(frame->cnt, 1UL); osi_WrStrLn(" state=DATA", 12ul); } sq = squelch(bins); if (!frame->nodcdlost && sq<=frame->datasquelch) { ++frame->timeout; if (loraprotocols_verb2) { osic_WrINT32(frame->label, 1UL); osi_WrStr(" ", 2ul); osi_WrStr(" dcd-lost-count=", 17ul); osic_WrINT32(frame->timeout, 1UL); osi_WrStrLn("", 1ul); } } else frame->timeout = 0UL; frame->lastbin = bins.b[0U].freq; frame->sigsum = frame->sigsum+bins.b[0U].lev; if (bins.b[0U].lev>frame->sigmax) frame->sigmax = bins.b[0U].lev; if (bins.b[0U].levsigmin) frame->sigmin = bins.b[0U].lev; frame->noissum = frame->noissum+bins.noise; if (bins.noise>frame->noismax) frame->noismax = bins.noise; if (bins.noisenoismin) frame->noismin = bins.noise; if (decodechirp(frame, bins, opt)) frame->state = lorarx_sSLEEP; ++frame->dcnt; } frame->noisenow = bins.noise; /* for noisefloor report */ ++frame->cnt; return 0; } /* end nextchirp() */ static void jsonpipebroken(int32_t); static void jsonpipebroken(int32_t signum) { osi_WrStr("got signal ", 12ul); osic_WrINT32((uint32_t)signum, 0UL); osi_WrStrLn("!", 2ul); } /* end jsonpipebroken() */ static uint32_t i; static uint32_t j; static char alldone; static char allcol; static pDEM pd; static float w; static float nf; static float nfp; X2C_STACK_LIMIT(8000000l) extern int main(int argc, char **argv) { size_t tmp[1]; uint32_t tmp0; X2C_BEGIN(&argc,argv,1,20000000l,32000000l); if (sizeof(NIBBBLOCK)!=12) X2C_ASSERT(0); if (sizeof(NIBBS)!=523) X2C_ASSERT(0); loraprotocols_BEGIN(); aprsstr_BEGIN(); osi_BEGIN(); Parms(); if (loraprotocols_jpipename[0UL]) signal(SIGPIPE, jsonpipebroken); w = 3.1415926535f; for (i = 0UL; i<=24UL; i++) { SINTAB[i] = (float)sin((double)w); w = w*0.5f; } /* end for */ pbirdbuf = 0; notchthres = 0.0f; pbirdhist = 0; if (firlen) { sampc = 0UL; firwp = 0UL; birdpos = 0UL; X2C_DYNALLOCATE((char **) &pfir,sizeof(struct Complex),(tmp[0] = 4096UL+firlen,tmp),1u); if (pfir==0) Error(" out of memory", 15ul); if (autonotch) { X2C_DYNALLOCATE((char **) &pbirdbuf,sizeof(struct Complex),(tmp[0] = firlen,tmp),1u); if (pbirdbuf==0) Error(" out of memory", 15ul); X2C_DYNALLOCATE((char **) &pbirdhist,sizeof(float),(tmp[0] = firlen,tmp),1u); if (pbirdhist==0) Error(" out of memory", 15ul); tmp0 = pbirdhist->Len0-1; i = 0UL; if (i<=tmp0) for (;; i++) { pbirdhist->Adr[i] = 0.0f; if (i==tmp0) break; } /* end for */ } X2C_DYNALLOCATE((char **) &pfirtab,sizeof(struct Complex),(tmp[0] = firlen*16UL,tmp),1u); if (pfirtab==0) Error(" out of memory", 15ul); X2C_DYNALLOCATE((char **) &ptmpfir,sizeof(struct Complex),(tmp[0] = firlen*16UL,tmp),1u); if (ptmpfir==0) Error(" out of memory", 15ul); X2C_DYNALLOCATE((char **) &pfixfir,sizeof(float),(tmp[0] = firlen,tmp),1u); if (pfixfir==0) Error(" out of memory", 15ul); makefir(downsample, pfirtab, 0, 0.0f); } MakeDDS(); for (i = 5UL; i<=12UL; i++) { X2C_DYNALLOCATE((char **) &fftbufs[i],sizeof(struct Complex),(tmp[0] = (uint32_t)(1UL<done = 0; pd = pd->next; } allcol = 1; do { /* do till no demodulator can fill fft buffer */ alldone = 1; pd = dems; while (pd) { /* all demodulators 1 chirp */ if (i<=pd->coldet && ((i==0UL || pd->frames[i].state>=lorarx_sSYNRAW) || pd->frames[i-1UL].state>=lorarx_sID)) { /* start next demod or keep on running */ if (i>0UL && pd->frames[i].state>=lorarx_sDATA) { /* check if earlier demod works on same frame */ tmp0 = i-1UL; j = 0UL; if (j<=tmp0) for (;; j++) { if (pd->frames[j].state>=lorarx_sDATA && labs((int32_t)pd->frames[i].fp-(int32_t) pd->frames[j].fp)<=5L) { /* if both are on nearby samples */ pd->frames[i].state = lorarx_sSLEEP; /* discontinue working on this frame */ } if (j==tmp0) break; } /* end for */ } allcol = 0; if (nextchirp(&pd->frames[i])) pd->done = 1; else { /* noisefloor reporting */ pd->noisepeak = flmax(pd->noisepeak, pd->frames[i].noisenow); pd->noisesum = pd->noisesum+pd->frames[i].noisenow; ++pd->noisesumcnt; } alldone = alldone && pd->done; } pd = pd->next; } } while (!alldone); ++i; } while (!allcol); if (sendjudpdcd) { /* check if change in dcd state */ pd = dems; while (pd) { { /* with */ struct DEM * anonym = pd; allcol = 0; tmp0 = anonym->coldet; i = 0UL; if (i<=tmp0) for (;; i++) { allcol = allcol || anonym->frames[i].state>=lorarx_sSYNRAW; /* if one modem has dcd then sf/inv has dcd */ if (i==tmp0) break; } /* end for */ nf = (-1000.0f); if (anonym->noisereports && anonym->noisesumcnt>=anonym->noisereports) { nf = (db(X2C_DIVR(anonym->noisesum, (float)anonym->noisesumcnt))+globallevelcor)-(float)anonym->frames[0U].cfgsf*6.0206f; /* repair level from simplified fft */ nfp = (db(anonym->noisepeak)+globallevelcor)-(float)anonym->frames[0U].cfgsf*6.0206f; anonym->noisesumcnt = 0UL; anonym->noisesum = 0.0f; anonym->noisepeak = 0.0f; if (loraprotocols_verb2) { osi_WrStr("noise=", 7ul); osic_WrFixed(nf, 2L, 1UL); osi_WrStr("dB peak=", 9ul); osic_WrFixed(nfp, 2L, 1UL); osi_WrStrLn("dB", 3ul); } } if (anonym->dcdstate!=allcol || nf>(-999.0f)) { loraprotocols_senddcd((int32_t)anonym->frames[0U].cfgsf, anonym->frames[0U].invertiq, allcol, nf, nfp); } anonym->dcdstate = allcol; pd = anonym->next; } } } } while (readsampsfir()); if (outdechirped>=0L) osic_Close(outdechirped); X2C_EXIT(); return 0; } X2C_MAIN_DEFINITION