/* 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 loratx_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 /* encode beacon-text to lora iq file and apply distortions for demodulator tests */ #define loratx_DDSSIZE 65536 #define loratx_SUBSAMPBITS 8 #define loratx_FIRMAX 4096 #define loratx_PI 3.1415926535 #define loratx_PI2 6.283185307 #define loratx_SUBSAMP 256 #define loratx_LF "\012" #define loratx_REVCHIRP 31 #define loratx_QUARTERCHIRP 30 #define loratx_TESTCHIRP 29 #define loratx_TESTZERO 28 #define loratx_OPTIMIZE 2 #define loratx_BASEGAIN 127.0 #define loratx_LIMLEV 127.4 #define loratx_DB 4.342944819 #define loratx_MAXSYMS 9999 static uint8_t loratx_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}; #define loratx_MAXBW 5.E+5 static uint32_t loratx_BWTAB[10] = {64UL,48UL,32UL,24UL,16UL,12UL,8UL,4UL,2UL,1UL}; struct Complex; struct Complex { float Im; float Re; }; struct BIRDY; typedef struct BIRDY * pBIRDY; struct BIRDY { pBIRDY next; float w0; float level; float hz; }; struct PARMS; struct PARMS { float noisegain; float outgain; float shift; double sample; double bw; int32_t cfgopt; char sendcrc; char implicitheader0; char invers; uint32_t sf; uint32_t cr; uint32_t preamble; uint32_t netid; uint32_t payloadlen; char acktext[8]; char payload[1501]; }; static char as[4096]; static char fni[4096]; static char fno[4096]; static char hh[4096]; static uint8_t ob[32768]; struct _0; struct _0 { uint32_t nsym; float add; }; static struct _0 tests[256]; static uint8_t nib[12]; static uint32_t sb[10000]; static double finetest[10000]; struct _1 { struct Complex * Adr; size_t Len0; }; static struct _1 * echofifo; static int32_t ret; static int32_t ufd; static int32_t fo; static int32_t fi; static int32_t inlen; static char ok0; static char verb; static char verb2; static char implicitheader; static char addjunk; static char swapiq; static char overdriven; static float noisgain; static float amp; static float val; static float oi; static float oq; static float pow0; static float pows; static float echodelay; static float echo0; static float echo1; static float headzeros; static float headzerosfrac; static float radardense; static float radarlevel; static double w; static double fr; static double shifts; static double symf; static double baud; static double bind; static double frac; static double bws; static double rnd; static double upsamp; static double fro; static uint32_t echop; static uint32_t echosize; static uint32_t i; static uint32_t j; static uint32_t paylen; static uint32_t crc; static uint32_t sp; static uint32_t powc; static uint32_t bins; static uint32_t samp; static uint32_t optimize; static uint32_t wpp; static uint32_t wpfo; static uint32_t outform; static uint32_t sym; static uint32_t testc; static uint32_t addzeros; static uint32_t radarduration; static uint32_t radarn; static uint32_t radarc; static uint32_t payloadenc; static uint32_t fromip; static uint32_t checkip; static uint32_t fromport; static uint32_t bindport; static uint32_t infp; static pBIRDY birdies; static pBIRDY bird; static struct PARMS parms; static char inbuf[4096]; static void Err(const char text[], uint32_t text_len) { osi_Werr(text, text_len); osi_WerrLn(" error abort", 13ul); X2C_ABORT(); } /* end Err() */ 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 WrHex(uint32_t x, uint32_t digits, uint32_t len) { char s[256]; HexStr(x, digits, len, 0, s, 256ul); osi_Werr(s, 256ul); } /* end WrHex() */ /* PROCEDURE mkdds; VAR i,q:CARDINAL; r:REAL; BEGIN r:=2.0*PI/FLOAT(HIGH(DDS)+1); q:=(HIGH(DDS)+1) DIV 4; FOR i:=0 TO HIGH(DDS) DO DDS[i].si:=sin(FLOAT(i)*r); DDS[(i+q) MOD (HIGH(DDS)+1)].co:=DDS[i].si; END; END mkdds; */ static double Random(void) { rnd = rnd+3.1415926535; rnd = rnd*rnd; rnd = rnd*rnd; rnd = rnd*rnd; rnd = rnd-(double)(uint32_t)X2C_TRUNCC(rnd,0UL,X2C_max_longcard); return rnd; } /* end Random() */ static float Noise12(void) { uint32_t i0; float r; r = 0.0f; for (i0 = 0UL; i0<=11UL; i0++) { r = r+(float)Random(); } /* end for */ return r*8.3333333333333E-2f-0.5f; } /* end Noise12() */ static void applyecho(float * si, float * sq) { struct Complex es; es = echofifo->Adr[echop]; echofifo->Adr[echop].Re = *si; echofifo->Adr[echop].Im = *sq; *si = *si*echo0+es.Re*echo1; *sq = *sq*echo0+es.Im*echo1; echop = (echop+1UL)%((echofifo->Len0-1)+1UL); } /* end applyecho() */ static void applynoise(float * si, float * sq) { float nq; float ni; ni = Noise12()*noisgain; nq = Noise12()*noisgain; pow0 = pow0+ni*ni+nq*nq; *si = *si+ni; *sq = *sq+nq; pows = pows+ *si* *si+ *sq* *sq; ++powc; } /* end applynoise() */ static void applyradar(float * si, float * sq) { if (radarn==0UL) { if (Noise12()+radardense*0.5f>0.5f) radarn = radarduration; } else { *si = *si+radarlevel; *sq = *sq+radarlevel; ++radarc; --radarn; } } /* end applyradar() */ static void WrSN(float pow1, float pows0, float sig) { char h[100]; osi_Werr(" noise:", 8ul); aprsstr_FixToStr(osic_ln(pow1)*4.342944819f, 2UL, h, 100ul); osi_Werr(h, 100ul); osi_Werr("dB", 3ul); osi_Werr(" s/n:", 6ul); aprsstr_FixToStr(osic_ln(X2C_DIVR(sig*sig,pow1))*4.342944819f, 2UL, h, 100ul); osi_Werr(h, 100ul); osi_Werr("dB", 3ul); osi_Werr(" (s+n)/n:", 10ul); aprsstr_FixToStr(osic_ln(X2C_DIVR(sig*sig+pow1,pow1))*4.342944819f, 2UL, h, 100ul); osi_Werr(h, 100ul); osi_Werr("dB", 3ul); } /* end WrSN() */ static void WrSamp(float s) { int32_t n; if (s<(-127.4f)) { s = (-127.4f); overdriven = 1; } else if (s>127.4f) { s = 127.4f; overdriven = 1; } if (outform==0UL) { ob[wpfo] = (uint8_t)(uint32_t)X2C_TRUNCC(s+128.0f,0UL,X2C_max_longcard); ++wpfo; } else if (outform==1UL) { ob[wpfo] = (uint8_t)(signed char)X2C_TRUNCI(s,-128,127); ++wpfo; } else if (outform==2UL) { s = s*256.0f; n = (int32_t)X2C_TRUNCI(s,X2C_min_longint,X2C_max_longint); ob[wpfo] = (uint8_t)n; ++wpfo; ob[wpfo] = (uint8_t)(n>>8); ++wpfo; } else { s = s*7.8740157480315E-3f; /* float is -1 to 1 */ n = (int32_t)*X2C_CAST(&s,float,uint32_t,uint32_t *); ob[wpfo] = (uint8_t)n; ++wpfo; ob[wpfo] = (uint8_t)(n>>8); ++wpfo; ob[wpfo] = (uint8_t)(n>>16); ++wpfo; ob[wpfo] = (uint8_t)(n>>24); ++wpfo; } if (wpfo>32767UL && fo>=0L) { osi_WrBin(fo, (char *)ob, 32768u/1u, wpfo); wpfo = 0UL; } } /* end WrSamp() */ static uint32_t crc16(const char b[], uint32_t b_len, uint32_t from, uint32_t len, uint32_t ini) { uint16_t ic; uint16_t i0; uint16_t poli; uint16_t crc0; uint8_t d; uint16_t tmp; crc0 = (uint16_t)ini; poli = 0x1021U; tmp = (uint16_t)(len-1UL); i0 = (uint16_t)from; if (i0<=tmp) for (;; i0++) { d = (uint8_t)(uint8_t)b[i0]; for (ic = 0U; ic<=7U; ic++) { if (((0x8000U & crc0)!=0)!=X2C_IN(7UL-(uint32_t)ic,8,d)) crc0 = X2C_LSH(crc0,16,1)^poli; else crc0 = X2C_LSH(crc0,16,1); } /* end for */ if (i0==tmp) break; } /* end for */ return (uint32_t)(uint16_t)crc0; } /* end crc16() */ static void setheadcrc(uint8_t b[], uint32_t b_len) { uint8_t crc0; crc0 = (X2C_LSH(b[0UL],8,1)^X2C_LSH(b[0UL],8,2)^X2C_LSH(b[0UL],8,3)^X2C_LSH(b[0UL],8, 4))&0x10U|(b[0UL]^b[1UL]^X2C_LSH(b[1UL],8,1)^X2C_LSH(b[1UL],8,2)^X2C_LSH(b[2UL],8, 3))&0x8U|(b[0UL]^X2C_LSH(b[1UL]^b[2UL],8,-1)^X2C_LSH(b[1UL],8,2)^X2C_LSH(b[2UL],8, 1))&0x4U|(b[0UL]^b[2UL]^X2C_LSH(b[1UL]^b[2UL],8,-1)^X2C_LSH(b[1UL]^b[2UL],8, 1))&0x2U|(b[0UL]^b[2UL]^X2C_LSH(b[1UL]^b[2UL],8,-1)^X2C_LSH(b[2UL],8,-3)^X2C_LSH(b[2UL],8,-2))&0x1U; b[3UL] = X2C_LSH(crc0,8,-4)&0x1U; b[4UL] = crc0&0xFU; } /* end setheadcrc() */ static void sethamm(uint32_t bits, uint8_t * b) { if (bits>1UL) { *b = *b&0xFU|(X2C_LSH(*b,8,4)^X2C_LSH(*b,8,3)^X2C_LSH(*b,8,2))&0x30U|(X2C_LSH(*b,8,6)^X2C_LSH(*b,8,5)^X2C_LSH(*b, 8,3))&0x40U|(X2C_LSH(*b,8,7)^X2C_LSH(*b,8,5)^X2C_LSH(*b,8,4))&0x80U; } else if (bits>0UL) { /* b4=0/1/2 b5=1/2/3 */ /* b6=0/1/3 */ /* b7=0/2/3 */ *b = *b|(X2C_LSH(*b,8,4)^X2C_LSH(*b,8,3)^X2C_LSH(*b,8,2)^X2C_LSH(*b,8,1))&0x10U; } } /* end sethamm() */ static void interleav(uint32_t sf, uint32_t cr, uint32_t lsb, uint32_t * start, uint32_t rb[], uint32_t rb_len, const uint8_t hb[], uint32_t hb_len) { uint32_t j1; uint32_t i0; uint32_t gx; uint32_t g; uint32_t tmp; uint32_t tmp0; /* FILL(ADR(rb),0C,SIZE(rb)); */ tmp = sf-1UL; j1 = 0UL; if (j1<=tmp) for (;; j1++) { tmp0 = cr-1UL; i0 = 0UL; if (i0<=tmp0) for (;; i0++) { if (X2C_IN(i0,8,(uint8_t)hb[(((sf-1UL)-j1)+i0)%sf])) rb[*start+i0] |= (1UL<<(sf-1UL)-j1); if (i0==tmp0) break; } /* end for */ if (j1==tmp) break; } /* end for */ tmp = cr-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { g = rb[*start]; gx = g; tmp0 = sf-1UL; j1 = 1UL; if (j1<=tmp0) for (;; j1++) { /* gray */ gx = X2C_LSH(gx,32,-1); g = g^gx; if (j1==tmp0) break; } /* end for */ rb[*start] = X2C_LSH(g,32,(int32_t)lsb); /*+ CAST(SET32,lsb DIV 1*/ /* peculiarity, 1 bin shift */ rb[*start] = (uint32_t)((uint32_t)rb[*start]+1UL)&0x7FFFFFFFUL; ++*start; if (i0==tmp) break; } /* end for */ } /* end interleav() */ static uint8_t nibble(uint32_t wp, const char text[], uint32_t text_len) { if (!(wp&1)) return (uint8_t)(uint8_t)text[wp/2UL]&0xFU; return X2C_LSH((uint8_t)(uint8_t)text[wp/2UL],8,-4)&0xFU; } /* end nibble() */ 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 int32_t GetIp(char h[], uint32_t h_len, uint32_t * ip, uint32_t * port) { uint32_t p; uint32_t n; uint32_t i0; char ok1; int32_t GetIp_ret; X2C_PCOPY((void **)&h,h_len); p = 0UL; h[h_len-1] = 0; *ip = 0UL; for (i0 = 0UL; i0<=4UL; i0++) { n = 0UL; ok1 = 0; while ((uint8_t)h[p]>='0' && (uint8_t)h[p]<='9') { ok1 = 1; n = (n*10UL+(uint32_t)(uint8_t)h[p])-48UL; ++p; } if (!ok1) { GetIp_ret = -1L; goto label; } if (i0<3UL) { if (h[p]!='.' || n>255UL) { GetIp_ret = -1L; goto label; } *ip = *ip*256UL+n; } else if (i0==3UL) { *ip = *ip*256UL+n; if (h[p]!=':' || n>255UL) { GetIp_ret = -1L; goto label; } } 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() */ /*------------------------ simple json reader */ static char skip(const char s[], uint32_t s_len, uint32_t * p) { if ((uint8_t)s[*p]<' ') return 0; if (s[*p]=='\"') { do { ++*p; if ((uint8_t)s[*p]<' ') return 0; } while (s[*p]!='\"'); ++*p; if ((uint8_t)s[*p]<' ') return 0; } else { do { ++*p; if ((uint8_t)s[*p]<' ') return 0; } while (!(s[*p]==',' || s[*p]=='}')); } return 1; } /* end skip() */ static char getstr(char b[], uint32_t b_len, uint32_t * p, char s[], uint32_t s_len) { uint32_t i0; do { if ((uint8_t)b[*p]<' ') return 0; ++*p; } while (b[*p-1UL]!='\"'); i0 = 0UL; for (;;) { if ((uint8_t)b[*p]<' ') return 0; if (b[*p]=='\"') { if (i0='0' && (uint8_t)s[*p]<='9') { if (f==0.0f) *v = *v*10.0f+(float)((uint32_t)(uint8_t)s[*p]-48UL); else { *v = *v+f*(float)((uint32_t)(uint8_t)s[*p]-48UL); f = f*0.1f; } } else break; ++*p; } if (neg) *v = -*v; return 1; } /* end getfix() */ static char recodehex(char text[], uint32_t text_len, uint32_t * len) { uint32_t ii; uint32_t i0; char hb[2]; *len = *len/2UL; i0 = 0UL; for (;;) { if (i0>=*len) break; hb[0U] = text[i0*2UL]; hb[1U] = text[i0*2UL+1UL]; if ((uint8_t)hb[0U]<'0' || (uint8_t)hb[1U]<'0') return 0; if (!StrToHex(hb, 2ul, &ii)) return 0; text[i0] = (char)ii; ++i0; } *len = i0; return 1; } /* end recodehex() */ static uint32_t d64(char c) { if (c=='=') return 64UL; if (c=='+') return 62UL; if (c=='/') return 63UL; if ((uint8_t)c>='0' && (uint8_t)c<='9') return ((uint32_t)(uint8_t)c+52UL)-48UL; if ((uint8_t)c>='A' && (uint8_t)c<='Z') return (uint32_t)(uint8_t)c-65UL; if ((uint8_t)c>='a' && (uint8_t)c<='z') return ((uint32_t)(uint8_t)c+26UL)-97UL; return 255UL; } /* end d64() */ static char base64(char text[], uint32_t text_len, uint32_t * txtlen) { uint32_t e; uint32_t n; uint32_t w0; uint32_t len; uint32_t j1; uint32_t i0; len = *txtlen; *txtlen = 0UL; e = 0UL; i0 = 0UL; while (e==0UL && i0+3UL64UL) return 0; if (n==64UL) ++e; w0 = (w0<<6)+n; } /* end for */ for (j1 = 0UL; j1<=2UL; j1++) { text[*txtlen] = (char)(w0>>16&255UL); ++*txtlen; w0 = w0<<8; } /* end for */ i0 += 4UL; } *txtlen -= e; if (*txtlen<=text_len-1) text[*txtlen] = 0; return i0==len; } /* end base64() */ static uint32_t _cnst[10] = {64UL,48UL,32UL,24UL,16UL,12UL,8UL,4UL,2UL,1UL}; static char jsonframe(struct PARMS * parms0) { uint32_t p; char h[100]; char key[100]; char s[1501]; float v; parms0->payloadlen = 0UL; p = 0UL; while ((p<=1500UL && p<1500UL) && parms0->payload[p]) { s[p] = parms0->payload[p]; ++p; } s[p] = 0; p = 0UL; do { if ((uint8_t)s[p]<' ') return 0; ++p; } while (s[p-1UL]!='{'); for (;;) { if (!getstr(s, 1501ul, &p, key, 100ul) || s[p]!=':') break; if (verb2) { osi_Werr("json[", 6ul); osi_Werr(key, 100ul); osi_WerrLn("]", 2ul); } if (aprsstr_StrCmp(key, 100ul, "shift", 6ul)) { if (!getfix(s, 1501ul, &p, &parms0->shift)) break; } else if (aprsstr_StrCmp(key, 100ul, "sf", 3ul)) { if ((!getfix(s, 1501ul, &p, &v) || v<=5.0f) || v>12.0f) break; parms0->sf = (uint32_t)X2C_TRUNCC(v,0UL,X2C_max_longcard); } else if (aprsstr_StrCmp(key, 100ul, "cr", 3ul)) { if ((!getfix(s, 1501ul, &p, &v) || v<4.0f) || v>8.0f) break; parms0->cr = (uint32_t)X2C_TRUNCC(v,0UL,X2C_max_longcard); } else if (aprsstr_StrCmp(key, 100ul, "bw", 3ul)) { if (!getfix(s, 1501ul, &p, &v) || v<0.0f) break; if (v>9.0f) parms0->bw = (double)v; else { parms0->bw = X2C_DIVL(5.E+5,(double)_cnst[(uint32_t)X2C_TRUNCC(v,0UL,X2C_max_longcard)]); } } else if (aprsstr_StrCmp(key, 100ul, "opt", 4ul)) { if (!getfix(s, 1501ul, &p, &v)) break; parms0->cfgopt = (int32_t)X2C_TRUNCI(v,X2C_min_longint,X2C_max_longint); } else if (aprsstr_StrCmp(key, 100ul, "crc", 4ul)) { if (!getfix(s, 1501ul, &p, &v)) break; parms0->sendcrc = v!=0.0f; } else if (aprsstr_StrCmp(key, 100ul, "impl", 5ul)) { if (!getfix(s, 1501ul, &p, &v)) break; parms0->implicitheader0 = v!=0.0f; } else if (aprsstr_StrCmp(key, 100ul, "inv", 4ul)) { if (!getfix(s, 1501ul, &p, &v)) break; parms0->invers = v!=0.0f; } else if (aprsstr_StrCmp(key, 100ul, "preamble", 9ul)) { if (!getfix(s, 1501ul, &p, &v) || v<1.0f) break; parms0->preamble = (uint32_t)X2C_TRUNCC(v,0UL,X2C_max_longcard); } else if (aprsstr_StrCmp(key, 100ul, "gain", 5ul)) { if (!getfix(s, 1501ul, &p, &parms0->outgain)) break; } else if (aprsstr_StrCmp(key, 100ul, "id", 3ul)) { if (!getstr(s, 1501ul, &p, h, 100ul)) break; if (!StrToHex(h, 100ul, &parms0->netid)) break; } else if (aprsstr_StrCmp(key, 100ul, "payload", 8ul)) { if (!getstr(s, 1501ul, &p, parms0->payload, 1501ul)) break; parms0->payloadlen = aprsstr_Length(parms0->payload, 1501ul); if (!base64(parms0->payload, 1501ul, &parms0->payloadlen)) break; } else if (aprsstr_StrCmp(key, 100ul, "ack", 4ul)) { if (!getstr(s, 1501ul, &p, parms0->acktext, 8ul)) break; } else if (!skip(s, 1501ul, &p)) break; if ((uint8_t)s[p]<' ') break; if (s[p]=='}') return 1; } return 0; } /* end jsonframe() */ /*------------------------ simple json reader */ static uint8_t _cnst0[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}; 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); aprsstr_BEGIN(); osi_BEGIN(); verb = 0; verb2 = 0; overdriven = 0; outform = 0UL; parms.outgain = 1.0f; parms.sf = 12UL; parms.cr = 5UL; parms.bw = 1.25E+5; parms.sample = 0.0; parms.sendcrc = 0; parms.preamble = 8UL; parms.cfgopt = -1L; fno[0] = 0; fni[0] = 0; parms.implicitheader0 = 0; parms.shift = 0.0f; parms.netid = 18UL; testc = 0UL; parms.noisegain = 0.0f; addzeros = 0UL; headzeros = 0.0f; addjunk = 0; swapiq = 0; echofifo = 0; echo1 = 0.0f; echop = 0UL; birdies = 0; radarduration = 0UL; radarn = 0UL; radarc = 0UL; ufd = -1L; fi = -1L; fo = -1L; payloadenc = 0UL; for (;;) { osi_NextArg(as, 4096ul); if (as[0U]==0) break; if ((as[0U]=='-' && as[1U]) && as[2U]==0) { if (as[0U]=='-') { if (as[1U]=='i') { osi_NextArg(fni, 4096ul); if (GetIp(fni, 4096ul, &checkip, &bindport)>=0L) { ufd = openudp(); if (ufd>=0L && bindudp(ufd, bindport)<0L) { Err("cannot bind inport", 19ul); } } else { fi = osi_OpenRead(fni, 4096ul); if (fi<0L) Err("input file open", 16ul); } } else if (as[1U]=='o') osi_NextArg(fno, 4096ul); else if (as[1U]=='C') parms.sendcrc = 1; else if (as[1U]=='I') implicitheader = 1; else if (as[1U]=='v') verb = 1; else if (as[1U]=='V') { verb = 1; verb2 = 1; } else if (as[1U]=='j') addjunk = 1; else if (as[1U]=='q') swapiq = 1; else if (as[1U]=='H') payloadenc = 1UL; else if (as[1U]=='J') payloadenc = 2UL; else if (as[1U]=='O') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToInt(as, 4096ul, &parms.cfgopt)) { Err("-O 0..1", 19ul); } } else if (as[1U]=='r') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&val, as, 4096ul)) Err("-r ", 19ul); if (val<=0.0f) Err("iq-samplerate range Hz", 23ul); parms.sample = (double)val; } else if (as[1U]=='S') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&val, as, 4096ul)) Err("-S ", 14ul); parms.shift = val; } else if (as[1U]=='g') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&val, as, 4096ul)) { Err("-g ", 25ul); } parms.outgain = val; } else if (as[1U]=='w') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&parms.noisegain, as, 4096ul)) { Err("-g ", 25ul); } } else if (as[1U]=='R') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&val, as, 4096ul)) Err("-R ", 10ul); rnd = (double)val; } else if (as[1U]=='E') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&echodelay, as, 4096ul)) { Err("-E ", 18ul); } osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&echo1, as, 4096ul)) Err("-E ", 18ul); } else if (as[1U]=='f') { osi_NextArg(as, 4096ul); if (as[0U]=='u' && as[1U]=='8') outform = 0UL; else if (as[0U]=='i' && as[1U]=='8') outform = 1UL; else if ((as[0U]=='i' && as[1U]=='1') && as[2U]=='6') outform = 2UL; else if ((as[0U]=='f' && as[1U]=='3') && as[2U]=='2') outform = 3UL; else Err("-f output formats u8 i8 i16 f32", 32ul); } else if (as[1U]=='b') { osi_NextArg(as, 4096ul); if (aprsstr_StrToCard(as, 4096ul, &i)) { if (i>9UL) parms.bw = (double)i; else parms.bw = X2C_DIVL(5.E+5,(double)_cnst[i]); } else Err("-b 0..9 or -b ", 30ul); } else if (as[1U]=='s') { osi_NextArg(as, 4096ul); if ((!aprsstr_StrToInt(as, 4096ul, &ret) || labs(ret)<5L) || labs(ret)>12L) { Err("-s [-]5..[-]12", 20ul); } parms.sf = (uint32_t)labs(ret); if (ret<0L) swapiq = 1; } else if (as[1U]=='z') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToCard(as, 4096ul, &addzeros)) Err("-z ", 7ul); } else if (as[1U]=='Z') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&headzeros, as, 4096ul)) Err("-Z ", 7ul); } else if (as[1U]=='N') { osi_NextArg(as, 4096ul); if (!StrToHex(as, 4096ul, &parms.netid)) Err("-N ", 11ul); } else if (as[1U]=='c') { osi_NextArg(as, 4096ul); if ((!aprsstr_StrToCard(as, 4096ul, &parms.cr) || parms.cr<4UL) || parms.cr>8UL) { Err("-c 4..8", 13ul); } } else if (as[1U]=='T') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToCard(as, 4096ul, &tests[testc].nsym)) { Err("-T [-]", 18ul); } osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&tests[testc].add, as, 4096ul)) { Err("-T [-]", 18ul); } if (testc<255UL) ++testc; } else if (as[1U]=='p') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToCard(as, 4096ul, &parms.preamble)) { Err("-p ", 13ul); } } else if (as[1U]=='B') { osi_NextArg(as, 4096ul); osic_alloc((char * *) &bird, sizeof(struct BIRDY)); if (bird==0) Err("-B out of memory", 17ul); if (!aprsstr_StrToFix(&bird->hz, as, 4096ul)) Err("-B ", 16ul); osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&bird->level, as, 4096ul)) { Err("-B ", 16ul); } bird->next = birdies; birdies = bird; } else if (as[1U]=='P') { osi_NextArg(as, 4096ul); if (!aprsstr_StrToCard(as, 4096ul, &radarduration)) { Err("-P ", 32ul); } osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&radardense, as, 4096ul)) { Err("-P ", 32ul); } osi_NextArg(as, 4096ul); if (!aprsstr_StrToFix(&radarlevel, as, 4096ul)) { Err("-P ", 32ul); } } else if (as[1U]=='h') { osi_WrStrLn("Make iq file/pipe with lora encoded text and, if desired, apply noise, dropouts and wrong bi\ ts for tests", 105ul); osi_WrStrLn("some parameters may be changed frame by frame using json (-J) input and udp feedback frame d\ one", 96ul); osi_WrStrLn("", 1ul); osi_WrStrLn(" -B add a tone +-hz with gain -B may be repeatet", 74ul); osi_WrStrLn(" -b or index kHz 0:7.8 1:10.4 2:15.6 3:20.8 4:31.25 5:41.7 6:62.5 7:12\ 5 8:250 9:500 (7)", 110ul); osi_WrStrLn(" -C send CRC", 30ul); osi_WrStrLn(" -c 4..8 (5)", 30ul); osi_WrStrLn(" -E add radiopath echo with delay (s) and gain e.g. 0.0005 0.5", 81ul); osi_WrStrLn(" only whole sample delay steps so use oversampling", 73ul); osi_WrStrLn(" -f u8 i8 i16 f32 (u8)", 40ul); osi_WrStrLn(" -g output level 0.0..1.0, with -f f32 more (1.0)", 67ul); osi_WrStrLn(" -H input file is in HEX, 1 line for 1 frame", 62ul); osi_WrStrLn(" -h this...", 29ul); osi_WrStrLn(" -I implicit header on", 40ul); osi_WrStrLn(" -i or text to send from udp or file, ip=0.0.0.0 for no check of source", 92ul); osi_WrStrLn(" -J input data is in JSON, 1 line or 1 udp frame for 1 lora frame, payload \ in base64", 102ul); osi_WrStrLn(" keywords: \"shift\",\"sf\",\"cr\",\"bw\",\"opt\",\"crc\",\"impl\",\"i\ nv\",\"preamble\",\"gain\",\"id\",\"payload\",\"ack\"", 120ul); osi_WrStrLn(" example: {\"payload\": \"MTIzNDU2Nzg5\", \"cr\": 7, \"shift\": -15000\ , \"gain\": 0.5, \"ack\":\"123\"}", 112ul); osi_WrStrLn(" -j insert \'3C FF 01\' (hex) before text", 57ul); osi_WrStrLn(" -N Sync symbols, network-id in hex (12)", 58ul); osi_WrStrLn(" -O <0..1> optimize on off else automatic (-1)", 57ul); osi_WrStrLn(" -o iq file name", 34ul); osi_WrStrLn(" -P add delta pulse noise (4 0.5 0.9)", 83ul); osi_WrStrLn(" -p preamble length (8)", 41ul); osi_WrStrLn(" -q invert IQ", 31ul); osi_WrStrLn(" -R random seed for noise (0.0)", 49ul); osi_WrStrLn(" -r iq sampelrate Hz >=bandwidth (125000.0)", 61ul); osi_WrStrLn(" -S shift signal frequency inside iq-band (Hz) (0)", 68ul); osi_WrStrLn(" -s spread factor (5..12) (12)", 48ul); osi_WrStrLn(" -T for FEC tests set n\'th chirp to zero level (shift=0)", 74ul); osi_WrStrLn(" or shift chirp, may be repeatet", 55ul); osi_WrStrLn(" -V more verbous", 34ul); osi_WrStrLn(" -v verbous", 29ul); osi_WrStrLn(" -w add white noise", 37ul); osi_WrStrLn(" -Z zero or noise chirps before data (0.0)", 60ul); osi_WrStrLn(" -z add zero or noise chirps at end (0)", 57ul); osi_WrStrLn("loratx -i beacon.txt -j -f i16 -r 2600000 -C -o /tmp/lora.iq -z 10 -s 12 -c 5 -b 7", 83ul); X2C_ABORT(); } else Err(as, 4096ul); } else Err("use -h", 7ul); } else Err("use -h", 7ul); } fo = osi_OpenWrite(fno, 4096ul); /* IF fo<0 THEN Err("iq file write") END; */ wpfo = 0UL; if (parms.sample==0.0) parms.sample = parms.bw; if (parms.sample==0.0) Err("samplerate not set", 19ul); /*- prepare birdies */ bird = birdies; while (bird) { bird->hz = (float)((X2C_DIVL((double)bird->hz,parms.sample))*6.283185307); bird->level = bird->level*127.0f; bird = bird->next; } /*- prepare echos */ if (echo1!=0.0f) { /* aply echo */ echo0 = X2C_DIVR(1.0f,1.0f+(float)fabs(echo1)); echo1 = 1.0f-echo0; if (echo1<0.0f) echo1 = -echo1; if (echodelay<=0.0f) Err("echo delay >0.0", 16ul); echodelay = (float)((double)echodelay*parms.sample); if (echodelay>1.E+8f) Err("echo delay too high", 20ul); echosize = (uint32_t)X2C_TRUNCC(echodelay+0.5f,0UL,X2C_max_longcard); if (echosize>0UL) { X2C_DYNALLOCATE((char **) &echofifo,sizeof(struct Complex),(tmp[0] = echosize,tmp),1u); } } /*- get data to be sent */ infp = 0UL; inlen = 0L; for (;;) { parms.payloadlen = 0UL; ok0 = 0; do { if (fi>=0L) { do { if ((int32_t)infp>=inlen) { do { inlen = osi_RdBin(fi, (char *)inbuf, 4096u/1u, 4096UL); if (inlen<=0L) goto loop_exit; } while (inlen<=0L); infp = 0UL; } if (inbuf[infp]!='\012') { if (parms.payloadlen<1499UL) { parms.payload[parms.payloadlen] = inbuf[infp]; ++parms.payloadlen; } } ++infp; } while (inbuf[infp]!='\012'); parms.payload[parms.payloadlen] = 0; } else if (ufd>=0L) { do { inlen = udpreceive(ufd, parms.payload, 1501L, &fromport, &fromip); if (inlen<0L) usleep(5000UL); } while (!(inlen>=0L && (checkip==0UL || fromip==checkip))); parms.payloadlen = (uint32_t)inlen; } else Err("no input data", 14ul); /*- recode input data */ if (payloadenc==1UL) ok0 = recodehex(parms.payload, 1501ul, &parms.payloadlen); else if (payloadenc==2UL) ok0 = jsonframe(&parms); else ok0 = 1; if (!ok0) osi_WerrLn("data decode error", 18ul); } while (!ok0); /*-WerrLn(parms.payload); */ /*- data frame ready */ if (!parms.implicitheader0 && parms.sf<=6UL) { parms.implicitheader0 = 1; osi_WerrLn("sf<=6 needs implicit header", 28ul); } if ((double)((float)fabs(parms.shift)*2.0f)+parms.bw>parms.sample*1.001) { osi_WerrLn("WARNING: signal does not fit in iq-bandwidth", 45ul); } /* shift:=shift/bw*PI2; */ shifts = (X2C_DIVL((double)parms.shift,parms.sample))*6.283185307; optimize = 0UL; if (parms.cfgopt==1L || parms.cfgopt && X2C_DIVL((double)(float)(uint32_t)X2C_LSH(0x1UL,32, (int32_t)parms.sf),parms.bw)>0.016) optimize = 2UL; if (verb) { osi_WerrLn("", 1ul); osi_Werr("opt:", 5ul); aprsstr_CardToStr(optimize, 1UL, hh, 4096ul); osi_WerrLn(hh, 4096ul); osi_Werr("bandwidth Hz:", 14ul); aprsstr_FixToStr((float)parms.bw, 3UL, hh, 4096ul); osi_WerrLn(hh, 4096ul); osi_Werr("sf:", 4ul); aprsstr_IntToStr((int32_t)parms.sf, 1UL, hh, 4096ul); osi_WerrLn(hh, 4096ul); osi_Werr("cr:", 4ul); aprsstr_CardToStr(parms.cr, 1UL, hh, 4096ul); osi_WerrLn(hh, 4096ul); osi_Werr("crc:", 5ul); aprsstr_CardToStr((uint32_t)parms.sendcrc, 1UL, hh, 4096ul); osi_WerrLn(hh, 4096ul); osi_Werr("chirptime s:", 13ul); aprsstr_FixToStr((float)(X2C_DIVL((double)(float)(uint32_t)(1UL<0UL) { osi_Werr("echo delay samples:", 20ul); aprsstr_CardToStr(echosize, 1UL, hh, 4096ul); osi_WerrLn(hh, 4096ul); } } if (addjunk) { if (parms.payloadlen>0UL) { for (i = parms.payloadlen-1UL;; i--) { parms.payload[i+3UL] = parms.payload[i]; if (i==0UL) break; } /* end for */ } parms.payload[0U] = '<'; /* for whatever */ parms.payload[1U] = '\377'; /* for whatever */ parms.payload[2U] = '\001'; /* for whatever */ parms.payloadlen += 3UL; } if (parms.payloadlen>255UL) parms.payloadlen = 255UL; if (verb) { osi_Werr("payloadlen:", 12ul); aprsstr_CardToStr(parms.payloadlen, 1UL, hh, 4096ul); osi_WerrLn(hh, 4096ul); } paylen = parms.payloadlen; if (parms.sendcrc) { crc = 0UL; if (paylen>2UL) crc = crc16(parms.payload, 1501ul, 0UL, paylen-2UL, 0UL); if (paylen>1UL) { crc = (uint32_t)((uint16_t)crc^(uint16_t)((uint32_t)(uint8_t)parms.payload[paylen-2UL]*256UL)); } if (paylen>0UL) { crc = (uint32_t)((uint16_t)crc^(uint16_t)(uint32_t)(uint8_t)parms.payload[paylen-1UL]); } parms.payload[paylen] = (char)(crc&255UL); parms.payload[paylen+1UL] = (char)(crc/256UL); paylen += 2UL; } for (i = paylen; i<=1500UL; i++) { parms.payload[i] = 0; } /* end for */ if (parms.payloadlen>0UL) { tmp0 = parms.payloadlen-1UL; i = 0UL; if (i<=tmp0) for (;; i++) { parms.payload[i] = (char)((uint8_t)(uint8_t)parms.payload[i]^(uint8_t)_cnst0[i]); /* whiten */ if (i==tmp0) break; } /* end for */ } wpp = 0UL; if (!implicitheader) { nib[0U] = (uint8_t)(parms.payloadlen/16UL); nib[1U] = (uint8_t)(parms.payloadlen&15UL); nib[2U] = (uint8_t)((uint32_t)parms.sendcrc+(parms.cr-4UL)*2UL); setheadcrc(nib, 12ul); tmp0 = (parms.sf-2UL)-1UL; i = 5UL; if (i<=tmp0) for (;; i++) { /* fill rest of header with payload */ nib[i] = nibble(wpp, parms.payload, 1501ul); ++wpp; if (i==tmp0) break; } /* end for */ tmp0 = (parms.sf-2UL)-1UL; i = 0UL; if (i<=tmp0) for (;; i++) { sethamm(4UL, &nib[i]); /* apply 4 bit hamming */ if (i==tmp0) break; } /* end for */ } memset((char *)sb,(char)0,40000UL); sp = 0UL; headzerosfrac = 0.0f; if (headzeros>0.0f) { i = (uint32_t)X2C_TRUNCC(headzeros,0UL,X2C_max_longcard); headzerosfrac = headzeros-(float)i; if (headzerosfrac!=0.0f) ++i; while (i>0UL) { sb[sp] = 0x10000000UL; if (sp<9997UL) ++sp; --i; } } if (sp>=9997UL) osi_WerrLn("chirp buffer full", 18ul); tmp0 = parms.preamble; i = 1UL; if (i<=tmp0) for (;; i++) { sb[sp] = 0UL; ++sp; if (i==tmp0) break; } /* end for */ sb[sp] = (uint32_t)((parms.netid/16UL&15UL)*8UL); ++sp; sb[sp] = (uint32_t)(((parms.netid&15UL)+(parms.netid/256UL)*16UL)*8UL); /* + non standard extension */ ++sp; sb[sp] = 0x80000000UL; /* reverse chirp */ ++sp; sb[sp] = 0x80000000UL; /* reverse chirp */ ++sp; sb[sp] = 0xC0000000UL; /* quarter reverse chirp */ ++sp; if (!parms.implicitheader0) { interleav(parms.sf-2UL, 8UL, 2UL, &sp, sb, 10000ul, nib, 12ul); /* header */ } while (wpp/2UL0UL) { sb[sp] = 0x10000000UL; if (sp<9997UL) ++sp; --i; } if (parms.noisegain!=0.0f) { /* append noise before and end */ for (i = sp; i>=1UL; i--) { sb[i] = sb[i-1UL]; } /* end for */ sb[0U] = 0x10000000UL; ++sp; sb[sp] = 0x10000000UL; ++sp; } samp = 0UL; bins = (uint32_t)(1UL<0.5) frac = frac-1.0; if ((0x40000000UL & sb[sym])==0 || frac<(-0.25)) { fr = frac*bws; if (((0x80000000UL & sb[sym])!=0)!=swapiq) fr = -fr; amp = (float)((0.5-fabs(frac))*12700.0); /* lower amplitude at freq jump works */ if (amp>127.0f) amp = 127.0f; amp = amp*parms.outgain; if ((0x10000000UL & sb[sym])) amp = 0.0f; w = w+fr+shifts; if (w>3.1415926535) w = w-6.283185307; else if (w<(-3.1415926535)) w = w+6.283185307; oi = osic_cos((float)w)*amp; oq = osic_sin((float)w)*amp; if (echofifo) applyecho(&oi, &oq); if (noisgain!=0.0f) applynoise(&oi, &oq); if (radarduration>0UL) applyradar(&oi, &oq); /*- add birdies */ bird = birdies; while (bird) { oi = oi+osic_cos(bird->w0)*bird->level; oq = oq+osic_sin(bird->w0)*bird->level; bird->w0 = bird->w0+bird->hz; if (bird->w0>6.283185307f) bird->w0 = bird->w0-6.283185307f; else if (bird->w0<(-6.283185307f)) bird->w0 = bird->w0+6.283185307f; bird = bird->next; } WrSamp(oi); WrSamp(oq); fro = fro+fr; } ++samp; } while (sym0UL && fo>=0L) osi_WrBin(fo, (char *)ob, 32768u/1u, wpfo); if (parms.acktext[0U]) { strncpy(hh,"{\"sent\":\"",4096u); aprsstr_Append(hh, 4096ul, parms.acktext, 8ul); aprsstr_Append(hh, 4096ul, "\"}", 3ul); i = (uint32_t)udpsend(ufd, hh, (int32_t)aprsstr_Length(hh, 4096ul), fromport, fromip); parms.acktext[0U] = 0; } if (overdriven) osi_WerrLn("WARNING: output level hard limited!", 36ul); if (verb && parms.noisegain!=0.0f) { osi_Werr("sig:", 5ul); aprsstr_FixToStr(osic_ln(parms.outgain)*8.685889638f, 2UL, hh, 4096ul); osi_Werr(hh, 4096ul); osi_Werr("dB", 3ul); if (pow0!=0.0f && powc) { pow0 = X2C_DIVR(pow0,(float)powc*127.0f*127.0f); pows = X2C_DIVR(pows,(float)powc*127.0f*127.0f); WrSN(pow0, pows, parms.outgain); if (parms.sample!=parms.bw) { osi_WerrLn("", 1ul); osi_Werr("in signal band ", 16ul); WrSN((float)(X2C_DIVL((double)pow0*parms.bw,parms.sample)), (float)(X2C_DIVL((double)pows*parms.bw,parms.sample)), parms.outgain); } } osi_WerrLn("", 1ul); } if (verb && radarc>0UL) { osi_Werr("added pulses:", 14ul); aprsstr_CardToStr(radarc, 1UL, hh, 4096ul); osi_Werr(hh, 4096ul); osi_WerrLn("", 1ul); } } loop_exit:; if (fo>=0L) osic_Close(fo); /* FOR i:=0 TO 255 DO tests[i].xor:=0 END; FOR i:=0 TO 10000000 DO INC(tests[TRUNC((Noise12()+0.5)*255.99)].xor) END; FOR i:=0 TO 255 DO WrInt(tests[i].xor,6); IF i MOD 16=15 THEN WrStrLn("") END; END; */ X2C_EXIT(); return 0; } X2C_MAIN_DEFINITION