/* 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 tetrarx_C_ #ifndef osi_H_ #include "osi.h" #endif #include #include #ifndef viterbi_cch_H_ #include "viterbi_cch.h" #endif #ifndef csdecoder_H_ #include "csdecoder.h" #endif #ifndef aprsstr_H_ #include "aprsstr.h" #endif #include /* iq synchronous dqpsk and tetra decoder */ #define tetrarx_PI 3.1415926535 #define tetrarx_PI2 6.283185307 #define tetrarx_LF "\012" #define tetrarx_MAXINBUF 4096 #define tetrarx_LOGNFSK 2 #define tetrarx_NFSK 4 #define tetrarx_OVERSAMP 16 #define tetrarx_BAUD 100.0 #define tetrarx_MAXDEMODS 256 #define tetrarx_MAXSUBBANDS 256 #define tetrarx_DDSLEN 16384 #define tetrarx_CHECKSNR 8.0 /* send new payload id only over this snr */ #define tetrarx_MODD "d" #define tetrarx_PLLGAIN 3200 /* 3200 d4psk psk pll loop gain */ struct Complex; struct Complex { float Re; float Im; }; struct LPCONTEXT24; struct LPCONTEXT24 { float uc1; float uc2; float il; float LPR; float OLPR; float LPL; }; typedef char FRAME[101]; struct DEMOD { uint32_t lastn; uint32_t symclk; uint32_t framewp; uint32_t synword; int32_t ppm; FRAME frame; float afc; float levm; float noism; }; struct DQPSKMODEM; typedef struct DQPSKMODEM * pDQPSKMODEM; struct DQPSKMODEM { pDQPSKMODEM next; struct LPCONTEXT24 iflpi; struct LPCONTEXT24 iflpq; uint16_t iffreq; uint16_t iffreqc; uint16_t iffreqafc; uint16_t ifosc; uint8_t lastd; uint32_t modemnum; uint32_t vcnt; uint32_t state; uint32_t baud; uint32_t ifsamp; uint32_t ifsamprate; uint32_t pllosc; uint32_t ifstep; int32_t maxcroase; int32_t croase; int32_t dir; float fm; float fmo; float ddsbase; float ifwidth; float rflevel; float lastlev; float noise; float qual; float lev1; float lev2; float lowlev; float olev; float pllf; float plllag; float level; uint32_t synwh; uint32_t synw; uint32_t ftyp; uint32_t fend; uint32_t fifop; signed char fifo[510]; }; static pDQPSKMODEM dqpskmodems; static char iqfn[1024]; static int32_t scanoffs; static int32_t iqfd; static uint32_t insamprate; static uint32_t isize; static char u8signed; static char verb; static char verb2; static short iqbuf[8192]; static short DDS[16384]; struct _0 { uint32_t payload; uint32_t time0; }; static uint32_t decodingtable[2048]; #define tetrarx_RAD 1.7453292519444E-2 #define tetrarx_D4BITS 2 /* bits per symbol */ #define tetrarx_SBBLK1BITS 120 #define tetrarx_SBBLK2BITS 216 #define tetrarx_SBBBKBITS 30 #define tetrarx_NDBBBK1BITS 14 #define tetrarx_NDBBBK1OFFSET 230 #define tetrarx_NDBBBK2OFFSET 266 #define tetrarx_NDBBBK2BITS 16 #define tetrarx_NDBBLKBITS 216 #define tetrarx_NDBBLK1OFFSET 14 #define tetrarx_NDBBLK2OFFSET 282 #define tetrarx_UNDBBLK1OFFSET 28 #define tetrarx_UNDBBLK2OFFSET 266 struct CONTEXT; struct CONTEXT { uint32_t xor; uint32_t mn; uint32_t tn; uint32_t fn; uint32_t mccmnc; uint32_t bcc; uint32_t la; uint32_t lac; uint32_t ccc; int32_t offset; float dmhz; float db; char istrafic; }; struct MCC; typedef struct MCC * pMCC; struct MCC { pMCC next; uint32_t mccmnc; char text[41]; }; static uint32_t tetrarx_SCRAMBINIT = 0x3UL; #define tetrarx_INB 16384 #define tetrarx_CHANS 4 #define tetrarx_DLEN 432 #define tetrarx_ALEN 480 #define tetrarx_MINFOUND 1 #define tetrarx_RXDEL 10 #define tetrarx_RXDELLONG 100 #define tetrarx_SCANTOL 10000 static char isuplink; static char rxany; static int32_t soundfd; static int32_t chanfds[4]; static uint32_t channels; static uint32_t RMTAB[16384]; struct _1; struct _1 { short af[480]; float alc; char filled; }; static struct _1 audiobufs[4]; static pMCC cachpm; static pMCC mcc; static uint32_t cachmn; static char mccfilename[1001]; static struct CONTEXT context; static void Error(const char text[], uint32_t text_len) { osi_Werr("tetrarx:", 9ul); osi_Werr(text, text_len); osi_Werr(" error abort\012", 14ul); X2C_ABORT(); } /* end Error() */ static float atan20(const struct Complex u) { float w; struct Complex abs0; abs0.Re = (float)fabs(u.Re); abs0.Im = (float)fabs(u.Im); if (abs0.Im>abs0.Re) { if (abs0.Im>0.0f) w = X2C_DIVR(abs0.Re,abs0.Im); else w = 0.0f; w = 1.57079632675f-(w*1.055f-w*w*0.267f); /* arctan */ } else { if (abs0.Re>0.0f) w = X2C_DIVR(abs0.Im,abs0.Re); else w = 0.0f; w = w*1.055f-w*w*0.267f; } if (u.Re<0.0f) w = 3.1415926535f-w; if (u.Im<0.0f) w = -w; return w; } /* end atan2() */ static float dB(float u) { if (u>0.0001f) return (float)(log((double)u)*8.68588963); return 0.0f; } /* end dB() */ static float fmhighpass(float w, float * w1) { float af; /* phase highpass make FM out of phase */ af = w-*w1; *w1 = w; if (af>3.1415926535f) af = af-6.283185307f; if (af<(-3.1415926535f)) af = af+6.283185307f; return af; } /* end fmhighpass() */ #define tetrarx_bytes 2 /*-------- write wav header */ static void wwav(int32_t fd, uint32_t hz, uint32_t chan) { char b[44]; strncpy(b,"RIFF WAVEfmt ",44u); b[4U] = '\377'; /* len */ b[5U] = '\377'; b[6U] = '\377'; b[7U] = '\377'; b[16U] = '\020'; b[17U] = 0; b[18U] = 0; b[19U] = 0; b[20U] = '\001'; /* PCM/ALAW */ b[21U] = 0; b[22U] = (char)chan; /* channels */ b[23U] = 0; b[24U] = (char)(hz&255UL); /* samp */ b[25U] = (char)(hz/256UL&255UL); b[26U] = (char)(hz/65536UL&255UL); b[27U] = (char)(hz/16777216UL); b[28U] = (char)(hz*2UL&255UL); /* byte/s */ b[29U] = (char)((hz*2UL)/256UL&255UL); b[30U] = (char)((hz*2UL)/65536UL); b[31U] = 0; b[32U] = '\002'; /* block byte */ b[33U] = 0; b[34U] = '\020'; /* bit/samp */ b[35U] = 0; b[36U] = 'd'; b[37U] = 'a'; b[38U] = 't'; b[39U] = 'a'; b[40U] = '\377'; /* len */ b[41U] = '\377'; b[42U] = '\377'; b[43U] = '\377'; if (fd>=0L) osi_WrBin(fd, (char *)b, 44u/1u, 44UL); } /* end wwav() */ static void MakeDDSi(short dds[], uint32_t dds_len) { uint32_t i0; float r; uint32_t tmp; r = X2C_DIVR(6.283185307f,(float)((dds_len-1)+1UL)); tmp = dds_len-1; i0 = 0UL; if (i0<=tmp) for (;; i0++) { dds[i0] = (short)X2C_TRUNCI(16383.9*sin((double)((float)i0*r)),-32768,32767); if (i0==tmp) break; } /* end for */ } /* end MakeDDSi() */ static void makelp24(float fg, float samp, struct LPCONTEXT24 * c) { struct LPCONTEXT24 * anonym; { /* with */ struct LPCONTEXT24 * anonym = c; anonym->LPR = (X2C_DIVR(fg,samp))*2.33363f; anonym->LPL = (float)((double)(anonym->LPR*anonym->LPR*2.888f)*(1.0-5.0*pow((double)(X2C_DIVR(fg, samp)), 2.0))); anonym->OLPR = 1.0f-anonym->LPR; } } /* end makelp24() */ static int32_t createnonblockfile(char fn[], uint32_t fn_len) { int32_t fd; int32_t createnonblockfile_ret; X2C_PCOPY((void **)&fn,fn_len); fd = osi_OpenNONBLOCK(fn, fn_len); if (fd<0L || !osi_IsFifo(fd)) { /* no pipe */ if (fd>=0L) osic_Close(fd); fd = osi_OpenWrite(fn, fn_len); } createnonblockfile_ret = fd; X2C_PFREE(fn); return createnonblockfile_ret; } /* end createnonblockfile() */ static void newmodem(uint32_t stored, uint32_t * afclim, uint32_t * ifwid, uint32_t * fskbaud, pDQPSKMODEM * pq, char mod, int32_t tune) { if ((uint32_t)labs(tune)*2UL>insamprate) Error("tuned outside bandwidth (-t)", 29ul); if (mod=='d') { osic_alloc((char * *)pq, sizeof(struct DQPSKMODEM)); if (*pq==0) Error("out of memory", 14ul); memset((char *)*pq,(char)0,sizeof(struct DQPSKMODEM)); (*pq)->baud = *fskbaud; (*pq)->ifsamprate = *fskbaud*4UL; (*pq)->ifwidth = (float)*ifwid; if ( *fskbaud*2UL>(*pq)->ifsamprate) (*pq)->ifsamprate = *fskbaud*2UL; (*pq)->ifstep = (uint32_t)X2C_TRUNCC((X2C_DIVR((float)(*pq)->ifsamprate, (float)insamprate))*4.294967295E+9f,0UL,X2C_max_longcard); makelp24((*pq)->ifwidth*0.5f, (float)insamprate, &(*pq)->iflpi); makelp24((*pq)->ifwidth*0.5f, (float)insamprate, &(*pq)->iflpq); (*pq)->ddsbase = X2C_DIVR(16384.0f,(float)insamprate); (*pq)->iffreq = (uint16_t)(int32_t)X2C_TRUNCI((*pq)->ddsbase*(float)tune,X2C_min_longint,X2C_max_longint); (*pq)->maxcroase = (int32_t)X2C_TRUNCI((*pq)->ddsbase*(float)*afclim,X2C_min_longint,X2C_max_longint); (*pq)->modemnum = stored; (*pq)->next = dqpskmodems; dqpskmodems = *pq; if (verb) { osi_WrStrLn("", 1ul); osi_WrStr("offset:", 8ul); osic_WrINT32((uint32_t)tune, 1UL); osi_WrStrLn("Hz", 3ul); if (*afclim>0UL) { osi_WrStr("max.afc:+-", 11ul); osic_WrINT32(*afclim, 1UL); osi_WrStrLn("Hz", 3ul); } osi_WrStr("if-bandwidth:", 14ul); osic_WrINT32((uint32_t)(int32_t)X2C_TRUNCI((*pq)->ifwidth,X2C_min_longint,X2C_max_longint), 1UL); osi_WrStrLn("Hz", 3ul); osi_WrStr("if-samplerate:", 15ul); osic_WrUINT32((*pq)->ifsamprate, 1UL); osi_WrStrLn("Hz", 3ul); osi_WrStr("baud:", 6ul); osic_WrUINT32(*fskbaud, 1UL); osi_WrStrLn("", 1ul); } } } /* end newmodem() */ static void num(uint32_t * v, const char h[], uint32_t h_len, uint32_t * i0) { uint32_t n; char sg; if (h[*i0]!=',') { sg = 0; n = 0UL; if (h[*i0]=='+') ++*i0; else if (h[*i0]=='-') { sg = 1; ++*i0; } while (((*i0='0') && (uint8_t)h[*i0]<='9') { n = (n*10UL+(uint32_t)(uint8_t)h[*i0])-48UL; ++*i0; } if (sg) n = (uint32_t) -(int32_t)n; *v = n; } } /* end num() */ static int32_t numm(const char h[], uint32_t h_len, uint32_t * i0) { uint32_t n; char sg; if (h[*i0]!=',') { sg = 0; n = 0UL; if (h[*i0]=='+') ++*i0; else if (h[*i0]=='-') { sg = 1; ++*i0; } while (((*i0='0') && (uint8_t)h[*i0]<='9') { n = (n*10UL+(uint32_t)(uint8_t)h[*i0])-48UL; ++*i0; } if (sg) return -(int32_t)n; return (int32_t)n; } return 0L; } /* end numm() */ static uint32_t getscramb(uint32_t mcc0, uint32_t mnc, uint32_t colour) /*p.723*/ { return 0x3UL|X2C_LSH((uint32_t)colour&0x3FUL|X2C_LSH((uint32_t)mnc&0x3FFFUL,32, 6)|X2C_LSH((uint32_t)mcc0&0x3FFUL,32,20),32,2); } /* end getscramb() */ static void Parms(void) { char err; uint32_t i0; uint32_t fixedlen; uint32_t fskbaud; uint32_t n; uint32_t afclim; uint32_t ifwid; uint32_t stored; char h[1024]; int32_t tune; float baud; char ademod; char mod; pDQPSKMODEM pq; uint32_t syncmask; uint32_t syncpattern; uint32_t ch; uint32_t bcc; uint32_t mcc0; uint32_t mnc; mod = 'd'; ademod = 0; iqfn[0] = 0; isize = 1UL; verb = 0; verb2 = 0; err = 0; insamprate = 0UL; tune = 0L; fskbaud = 18000UL; baud = 100.0f; ifwid = 20000UL; stored = 0UL; afclim = 0UL; u8signed = 0; syncpattern = 0UL; syncmask = 0UL; fixedlen = 0UL; err = 0; soundfd = -2L; channels = 2UL; for (ch = 0UL; ch<=3UL; ch++) { chanfds[ch] = -1L; } /* end for */ ch = 0UL; for (;;) { osi_NextArg(h, 1024ul); if (h[0U]==0) break; if ((h[0U]=='-' && h[1U]) && h[2U]==0) { if (h[0U]=='u') { osi_NextArg(h, 1024ul); i0 = 0UL; mcc0 = (uint32_t)numm(h, 1024ul, &i0); if (h[i0]!=',') Error("-u mcc,mnc,bcc", 15ul); ++i0; mnc = (uint32_t)numm(h, 1024ul, &i0); if (h[i0]!=',') Error("-u mcc,mnc,bcc", 15ul); ++i0; bcc = (uint32_t)numm(h, 1024ul, &i0); if (h[i0]) Error("-u mcc,mnc,bcc", 15ul); context.xor = getscramb(mcc0, mnc, bcc); isuplink = 1; } else if (h[1U]=='c') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToCard(h, 1024ul, &channels) || (channels!=1UL && channels!=2UL) && channels!=4UL) { Error("-c 1,2,4", 25ul); } } else if (h[1U]=='m') { osi_NextArg(mccfilename, 1001ul); if (mccfilename[0U]==0) Error("-m =0L) wwav(chanfds[ch], 8000UL, 1UL); else Error("-W cannot open sound output", 44ul); ++ch; } else Error("-W maximum 4 sound channels", 29ul); } else if (h[1U]=='i') { osi_NextArg(iqfn, 1024ul); 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]=='t') { osi_NextArg(h, 1024ul); i0 = 0UL; num(&n, h, 1024ul, &i0); tune = (int32_t)n; if (h[i0]==',') { ++i0; num(&afclim, h, 1024ul, &i0); } if (h[i0]) { Error("-t <+-Hz>[,]", 17ul); } } else if (h[1U]=='v') verb = 1; else if (h[1U]=='V') { verb = 1; verb2 = 1; } else if (h[1U]=='r') { osi_NextArg(h, 1024ul); if (!aprsstr_StrToCard(h, 1024ul, &insamprate) || insamprate<100UL) { Error("-r ", 19ul); } } else if (h[1U]=='d') { if (stored>0UL) newmodem(stored, &afclim, &ifwid, &fskbaud, &pq, mod, tune); ++stored; osi_NextArg(h, 1024ul); ifwid = 20000UL; i0 = 0UL; num(&fskbaud, h, 1024ul, &i0); if (h[i0]==',') { ++i0; num(&ifwid, h, 1024ul, &i0); } if (h[i0]) Error("-d ,", 27ul); } else { if (h[1U]=='h') { osi_WrStrLn("", 1ul); osi_WrStrLn(" Demodulate DQPSK and decode tetra", 36ul); osi_WrStrLn("", 1ul); osi_WrStrLn(" -c audio channels 1, 2 or 4, less than 4: mono/stereo downmix (2)", 79ul); osi_WrStrLn(" -d [,] (-d 18000,20000)", 43ul); osi_WrStrLn(" -f u8|i8|i16|f32 IQ data format (f32 slow)", 46ul); osi_WrStrLn(" -h this", 25ul); osi_WrStrLn(" -i IQ-filename or pipe from sdr receiver", 58ul); osi_WrStrLn(" -m read file with \'mcc mnc text\' lines", 56ul); osi_WrStrLn(" -O print raw demodulated bits to stdout", 57ul); osi_WrStrLn(" -r iq samplerate", 34ul); osi_WrStrLn(" -t <+-offsetHz>[,]", 27ul); osi_WrStrLn(" Shift rx-frequency inside IQ band (avoid near 0 where is adc birdy) (0\ )", 94ul); osi_WrStrLn(" afc-follow-range Hz, 90% in about 10ms, 0=afc off (0)", 76ul); osi_WrStrLn(" -v verbous", 28ul); osi_WrStrLn(" -u decoding uplink needs scrambler code seen by decoding downlink -v \\ "CC\" or give any number and decode a while downlink before uplink", 157ul); osi_WrStrLn(" -W write wav file or unbreakable pipe with slot 0, repeat -W for slot 1 2 3\ ", 93ul); osi_WrStrLn(" -w write wav file or unbreakable pipe with -c channels downmixed and gain l\ imited", 99ul); osi_WrStrLn("", 1ul); osi_WrStrLn(" mknod pipe.wav p", 19ul); osi_WrStrLn(" rtl_sdr -f 430.0m -s 2000000 -g 50 - | ./tetrarx -i /dev/stdin -f u8 -r 2000000 -t 87500,0\ -w pipe.wav -m mccmnc.txt -c 2 -v", 127ul); osi_WrStrLn(" aplay a.wav", 14ul); 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 (soundfd>=0L) wwav(soundfd, 8000UL, channels); else if (soundfd>=-1L) Error("-w cannot open sound output", 44ul); if (insamprate==0UL) Error("need input samplerate (-r)", 27ul); newmodem(stored, &afclim, &ifwid, &fskbaud, &pq, mod, tune); } /* end Parms() */ /*---------------tetradec */ static void readmccmnc(void) { int32_t fp; char c; uint32_t mn; uint32_t num0; uint32_t n; char s[1001]; pMCC m; if (mccfilename[0U]==0) return; fp = osi_OpenRead(mccfilename, 1001ul); if (fp>=0L) { n = 0UL; num0 = 0UL; while (osi_RdBin(fp, (char *) &c, 1u/1u, 1UL)==1L) { if (num0<=1UL) { if ((uint8_t)c>='0' && (uint8_t)c<='9') { n = (n*10UL+(uint32_t)(uint8_t)c)-48UL; } else { ++num0; mn = mn*65536UL+n; n = 0UL; } } else if ((uint8_t)c>=' ') { if (n<1000UL) { s[n] = c; ++n; } } else { if (mn) { if (n<=1000UL) s[n] = 0; osic_alloc((char * *) &m, sizeof(struct MCC)); if (m==0) return; memset((char *)m,(char)0,sizeof(struct MCC)); m->mccmnc = mn; aprsstr_Assign(m->text, 41ul, s, 1001ul); m->next = mcc; mcc = m; } num0 = 0UL; n = 0UL; } } osic_Close(fp); } else osi_WerrLn("mmc-file not readable", 22ul); if (verb2) { m = mcc; while (m) { osic_WrINT32(m->mccmnc/65536UL, 6UL); osic_WrINT32(m->mccmnc&65535UL, 6UL); osi_WrStr(" ", 2ul); osi_WrStrLn(m->text, 41ul); m = m->next; } } } /* end readmccmnc() */ static void printmcc(uint32_t mn) { if (cachmn!=mn) { cachpm = mcc; while (cachpm && cachpm->mccmnc!=mn) cachpm = cachpm->next; } cachmn = mn; if (cachpm) { osi_WrStr(" [", 3ul); osi_WrStr(cachpm->text, 41ul); osi_WrStr("]", 2ul); } } /* end printmcc() */ /*------- init reed muller decode */ static uint8_t tetrarx_RM3014[224] = {1U,0U,0U,1U,1U,0U,1U,1U,0U,1U,1U,0U,0U,0U,0U,0U,0U,0U,1U,0U,1U,1U,0U,1U,1U,1U, 1U,0U,0U,0U,0U,0U,1U,1U,1U,1U,1U,1U,0U,0U,0U,0U,1U,0U,0U,0U,0U,0U,1U,1U,1U,0U,0U,0U,0U,0U,0U,0U,1U,1U, 1U,1U,0U,0U,1U,0U,0U,1U,1U,0U,0U,0U,0U,0U,1U,1U,1U,0U,1U,0U,0U,1U,0U,1U,0U,1U,0U,0U,0U,0U,1U,1U,0U,1U, 1U,0U,0U,0U,1U,0U,1U,1U,0U,0U,0U,0U,1U,0U,1U,1U,1U,0U,1U,1U,1U,1U,1U,1U,1U,1U,1U,1U,0U,1U,1U,1U,1U,1U, 1U,0U,0U,0U,0U,0U,1U,1U,0U,0U,1U,1U,1U,0U,0U,1U,0U,1U,0U,0U,0U,0U,1U,0U,1U,0U,1U,1U,0U,1U,0U,1U,0U,0U, 1U,0U,0U,0U,0U,1U,1U,0U,1U,0U,1U,1U,0U,1U,0U,0U,0U,1U,0U,0U,1U,0U,0U,1U,1U,1U,0U,0U,1U,1U,0U,0U,0U,0U, 1U,0U,0U,1U,0U,1U,1U,0U,1U,0U,1U,1U,0U,0U,0U,0U,0U,1U,0U,0U,1U,1U,1U,0U,0U,1U,1U,1U}; static uint8_t _cnst[224] = {1U,0U,0U,1U,1U,0U,1U,1U,0U,1U,1U,0U,0U,0U,0U,0U,0U,0U,1U,0U,1U,1U,0U,1U,1U,1U,1U,0U,0U, 0U,0U,0U,1U,1U,1U,1U,1U,1U,0U,0U,0U,0U,1U,0U,0U,0U,0U,0U,1U,1U,1U,0U,0U,0U,0U,0U,0U,0U,1U,1U,1U,1U,0U, 0U,1U,0U,0U,1U,1U,0U,0U,0U,0U,0U,1U,1U,1U,0U,1U,0U,0U,1U,0U,1U,0U,1U,0U,0U,0U,0U,1U,1U,0U,1U,1U,0U,0U, 0U,1U,0U,1U,1U,0U,0U,0U,0U,1U,0U,1U,1U,1U,0U,1U,1U,1U,1U,1U,1U,1U,1U,1U,1U,0U,1U,1U,1U,1U,1U,1U,0U,0U, 0U,0U,0U,1U,1U,0U,0U,1U,1U,1U,0U,0U,1U,0U,1U,0U,0U,0U,0U,1U,0U,1U,0U,1U,1U,0U,1U,0U,1U,0U,0U,1U,0U,0U, 0U,0U,1U,1U,0U,1U,0U,1U,1U,0U,1U,0U,0U,0U,1U,0U,0U,1U,0U,0U,1U,1U,1U,0U,0U,1U,1U,0U,0U,0U,0U,1U,0U,0U, 1U,0U,1U,1U,0U,1U,0U,1U,1U,0U,0U,0U,0U,0U,1U,0U,0U,1U,1U,1U,0U,0U,1U,1U,1U}; static void RMinit(void) { uint32_t j; uint32_t i0; uint32_t b; uint32_t rows[14]; for (i0 = 0UL; i0<=13UL; i0++) { b = X2C_LSH(0x1UL,32,(int32_t)i0); for (j = 0UL; j<=15UL; j++) { if ((uint32_t)_cnst[j+16UL*i0]>0UL) b |= (1UL<<14UL+j); } /* end for */ rows[i0] = b; } /* end for */ for (j = 0UL; j<=16383UL; j++) { b = 0UL; for (i0 = 0UL; i0<=13UL; i0++) { if (X2C_IN(13UL-i0,32,(uint32_t)j)) b = b^rows[i0]; } /* end for */ RMTAB[j] = b; } /* end for */ } /* end RMinit() */ static uint32_t getscramb0(uint32_t mcc0, uint32_t mnc, uint32_t colour) /*p.723*/ { return 0x3UL|X2C_LSH((uint32_t)colour&0x3FUL|X2C_LSH((uint32_t)mnc&0x3FFFUL,32, 6)|X2C_LSH((uint32_t)mcc0&0x3FFUL,32,20),32,2); } /* end getscramb() */ #define tetrarx_MAXG 20.0 static short lim(short u, float * mul, float lim0) { float ll; float r; r = (float)u*(20.0f-*mul); ll = (float)fabs(r)-lim0; if (ll>0.0f) *mul = *mul+(20.0f-*mul)*ll*0.00001f; else *mul = *mul*0.9999f; if (r>lim0) r = lim0; else if (r<-lim0) r = -lim0; return (short)X2C_TRUNCI(r,-32768,32767); } /* end lim() */ static void decodeaudio(const signed char frame[], uint32_t frame_len, uint32_t ch) { uint32_t sp; uint32_t c; uint32_t i0; short fw[432]; short sb[1920]; if (ch>=4UL) ch = 3UL; if (audiobufs[ch].filled) { /* buffer filled and new data for this channel so dump sound */ sp = 0UL; memset((char *)sb,(char)0,3840UL); if (channels==1UL) { /* mix down to mono */ for (i0 = 0UL; i0<=479UL; i0++) { for (c = 0UL; c<=3UL; c++) { sb[sp] += lim(audiobufs[c].af[i0], &audiobufs[c].alc, 8000.0f); } /* end for */ ++sp; } /* end for */ } else if (channels==2UL) { /* mix down to stereo */ for (i0 = 0UL; i0<=479UL; i0++) { sb[sp] += lim(audiobufs[0U].af[i0], &audiobufs[0U].alc, 16000.0f); sb[sp] += lim(audiobufs[2U].af[i0], &audiobufs[2U].alc, 10600.0f); sb[sp] += lim(audiobufs[3U].af[i0], &audiobufs[3U].alc, 5300.0f); ++sp; sb[sp] += lim(audiobufs[2U].af[i0], &audiobufs[2U].alc, 5300.0f); sb[sp] += lim(audiobufs[3U].af[i0], &audiobufs[3U].alc, 10600.0f); sb[sp] += lim(audiobufs[1U].af[i0], &audiobufs[1U].alc, 16000.0f); ++sp; } /* end for */ } else { for (i0 = 0UL; i0<=479UL; i0++) { /* 4 channel audio */ for (c = 0UL; c<=3UL; c++) { sb[sp] = lim(audiobufs[c].af[i0], &audiobufs[c].alc, 32000.0f); ++sp; } /* end for */ } /* end for */ } osi_WrBin(soundfd, (char *)sb, 3840u/1u, sp*2UL); osic_flush(); for (c = 0UL; c<=3UL; c++) { memset((char *)audiobufs[c].af,(char)0,960UL); audiobufs[c].filled = 0; } /* end for */ } for (i0 = 0UL; i0<=431UL; i0++) { fw[i0] = (short)frame[i0]; /* make 16 bit (but no soft viterbi) */ } /* end for */ csdec(audiobufs[ch].af, fw); /* decode audio */ audiobufs[ch].filled = 1; if (chanfds[ch]>=0L) { osi_WrBin(chanfds[ch], (char *)audiobufs[ch].af, 960u/1u, 960UL); /* write single channel audio file */ } } /* end decodeaudio() */ static int32_t inlen; static int32_t rdp; static uint32_t tetrarx_TRAINn = 0xB970BUL; static uint32_t tetrarx_TRAINp = 0x1EC25EUL; static uint32_t tetrarx_TRAINy = 0x83973983UL; static uint32_t tetrarx_TRAINy1 = 0x39UL; static uint32_t tetrarx_TRAINx = 0x30B970B9UL; #define tetrarx_NOTFOUND 100 static uint32_t frametyp(const signed char f[], uint32_t f_len, uint32_t len) { uint32_t j; uint32_t m; uint32_t i0; uint32_t e[4]; e[0U] = 0UL; e[1U] = 0UL; e[2U] = 0UL; e[3U] = 0UL; if (len==510UL) { for (i0 = 0UL; i0<=21UL; i0++) { if (X2C_IN(i0,32,0xB970BUL)!=(int32_t)f[i0+244UL]<0L) ++e[0U]; if (X2C_IN(i0,32,0x1EC25EUL)!=(int32_t)f[i0+244UL]<0L) ++e[1U]; } /* end for */ for (i0 = 0UL; i0<=31UL; i0++) { if (X2C_IN(i0,32,0x83973983UL)!=(int32_t)f[i0+214UL]<0L) ++e[2U]; } /* end for */ for (i0 = 0UL; i0<=5UL; i0++) { if (X2C_IN(i0,32,0x39UL)!=(int32_t)f[i0+246UL]<0L) ++e[2U]; } /* end for */ } else { e[0U] = 100UL; e[1U] = 100UL; e[2U] = 100UL; } if (len==206UL) { for (i0 = 0UL; i0<=29UL; i0++) { if (X2C_IN(i0,32,0x30B970B9UL)!=(int32_t)f[i0+88UL]<0L) ++e[3U]; } /* end for */ } else e[3U] = 100UL; m = 100UL; j = 0UL; for (i0 = 0UL; i0<=3UL; i0++) { if (e[i0]0UL) { n += n+(uint32_t)b[from]; ++from; --len; } return n; } /* end bton() */ static uint32_t btoni(const char b[], uint32_t b_len, uint32_t * from, uint32_t len) { uint32_t r; r = bton(b, b_len, *from, len); *from += len; return r; } /* end btoni() */ static void showSBBLK1(const char b[], uint32_t b_len, uint32_t len, struct CONTEXT * cont) { uint32_t bc; uint32_t cn; uint32_t mnc; uint32_t mcc0; /* IF verb THEN WrStr("CC="); WrCard(bton(b, 4,6),1) END; */ cont->tn = bton(b, b_len, 10UL, 2UL); cont->fn = bton(b, b_len, 12UL, 5UL); cont->mn = bton(b, b_len, 17UL, 6UL); mcc0 = bton(b, b_len, 31UL, 10UL); mnc = bton(b, b_len, 41UL, 14UL); bc = bton(b, b_len, 4UL, 6UL); cn = mcc0*65536UL+mnc; if (labs(scanoffs-cont->offset)<10000L) { if (cont->mccmnc==cn && cont->bcc==bc) ++cont->ccc; else cont->ccc = 0UL; } cont->mccmnc = cn; cont->bcc = bc; cont->xor = getscramb0(mcc0, mnc, cont->bcc); if (verb) { osi_WrStr(" TN=", 5ul); osic_WrUINT32(cont->tn, 1UL); osi_WrStr(" FN=", 5ul); osic_WrUINT32(cont->fn, 2UL); osi_WrStr(" MN=", 5ul); osic_WrUINT32(cont->mn, 1UL); /* WrStr(" MCC="); WrCard(mcc,1); */ /* WrStr(" MNC="); WrCard(mnc,1); */ osi_WrStr(" CC=", 5ul); osic_WrUINT32(mcc0, 1UL); osi_WrStr(",", 2ul); osic_WrUINT32(mnc, 1UL); osi_WrStr(",", 2ul); osic_WrUINT32(cont->bcc, 1UL); osi_WrStr(" ", 2ul); } } /* end showSBBLK1() */ static uint8_t tetrarx_LEN[8] = {0U,24U,10U,24U,34U,34U,30U,34U}; static uint8_t _cnst5[8] = {0U,24U,10U,24U,34U,34U,30U,34U}; static void showSCHf(const char b[], uint32_t b_len, uint32_t len) { uint32_t usagemarker; uint32_t ssi; uint32_t styp; uint32_t n; uint32_t type; uint32_t p; /*WrStr(" ----B["); WrInt(bton(b,0,4),1); WrStrLn("]"); */ if (verb) { p = 0UL; type = btoni(b, b_len, &p, 2UL); /* p613 p380 */ osi_WrStr(" MAC=", 6ul); osic_WrUINT32(type, 1UL); if (type==0UL) { n = btoni(b, b_len, &p, 2UL); n = btoni(b, b_len, &p, 2UL); n = btoni(b, b_len, &p, 1UL); n = btoni(b, b_len, &p, 6UL); styp = btoni(b, b_len, &p, 3UL); usagemarker = 0UL; if (styp>0UL) { if (styp==3UL) osi_WrStr(" ussi=", 7ul); else osi_WrStr(" ssi=", 6ul); osic_WrUINT32(styp, 1UL); ssi = btoni(b, b_len, &p, (uint32_t)_cnst5[styp]); if (styp==6UL) { usagemarker = ssi&63UL; ssi = ssi/64UL; } osi_WrStr(":", 2ul); osic_WrUINT32(ssi, 1UL); if (styp==6UL) { osi_WrStr(" um:", 5ul); osic_WrUINT32(usagemarker, 1UL); } } } osi_WrStr(" ", 2ul); } } /* end showSCHf() */ static float tetrarx_OFFS[4] = {0.0f,(-6.25f),6.25f,12.5f}; static int32_t tetrarx_DUPLEX[128] = {-1L,1600L,10000L,10000L,10000L,10000L,10000L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L, -1L,-1L,4500L,-1L,36000L,7000L,-1L,-1L,-1L,45000L,45000L,-1L,-1L,-1L,-1L,-1L,-1L,0L,0L,0L,0L,0L,0L,0L, 0L,0L,0L,0L,0L,0L,0L,0L,0L,-1L,-1L,-1L,8000L,8000L,-1L,-1L,-1L,18000L,18000L,-1L,-1L,-1L,-1L,-1L,-1L, -1L,-1L,-1L,18000L,5000L,-1L,30000L,30000L,-1L,39000L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,9500L,-1L, -1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L, -1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L}; static float _cnst7[4] = {0.0f,(-6.25f),6.25f,12.5f}; static int32_t _cnst6[128] = {-1L,1600L,10000L,10000L,10000L,10000L,10000L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L, 4500L,-1L,36000L,7000L,-1L,-1L,-1L,45000L,45000L,-1L,-1L,-1L,-1L,-1L,-1L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L, 0L,0L,0L,0L,0L,0L,-1L,-1L,-1L,8000L,8000L,-1L,-1L,-1L,18000L,18000L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L, 18000L,5000L,-1L,30000L,30000L,-1L,39000L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,9500L,-1L,-1L,-1L,-1L, -1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L, -1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L,-1L}; static void showSBBLK2(const char b[], uint32_t b_len, uint32_t len, struct CONTEXT * cont) { uint32_t adrtyp; uint32_t la; uint32_t subscrclass; uint32_t hyperframenr; uint32_t cckid; uint32_t norf; uint32_t rtimeout; uint32_t accparm; uint32_t rxlev; uint32_t mspwr; uint32_t ncsh; uint32_t revers; uint32_t duplexspacing; uint32_t offs; uint32_t ch; uint32_t band; uint32_t i0; uint32_t bsservicedetails; int32_t shift; /*WrStr("B["); FOR i:=0 TO len-1 DO WrInt(ORD(b[i]),1) END; WrStrLn("]"); */ /*WrStr(" ----B["); WrInt(bton(b,0,4),1); WrStrLn("]"); */ if (bton(b, b_len, 0UL, 4UL)==8UL) { /* SYSINFO p623 */ i0 = 4UL; ch = btoni(b, b_len, &i0, 12UL); band = btoni(b, b_len, &i0, 4UL); offs = btoni(b, b_len, &i0, 2UL); duplexspacing = btoni(b, b_len, &i0, 3UL); revers = btoni(b, b_len, &i0, 1UL); ncsh = btoni(b, b_len, &i0, 2UL); mspwr = btoni(b, b_len, &i0, 3UL); rxlev = btoni(b, b_len, &i0, 4UL); accparm = btoni(b, b_len, &i0, 4UL); rtimeout = btoni(b, b_len, &i0, 4UL); norf = btoni(b, b_len, &i0, 1UL); if (norf>0UL) cckid = btoni(b, b_len, &i0, 16UL); else hyperframenr = btoni(b, b_len, &i0, 16UL); i0 = 82UL; la = btoni(b, b_len, &i0, 14UL); /* p1172 */ if (labs(scanoffs-cont->offset)<10000L) { if (cont->la==la) ++cont->lac; else cont->lac = 0UL; } cont->la = la; subscrclass = btoni(b, b_len, &i0, 16UL); bsservicedetails = (uint32_t)btoni(b, b_len, &i0, 12UL); shift = _cnst6[band+duplexspacing*16UL]; cont->dmhz = ((float)(band*100000UL+ch*25UL)+_cnst7[offs])*0.001f; if (verb) { osi_WrStr("TX=", 4ul); osic_WrFixed(cont->dmhz, 4L, 1UL); if (shift>=0L) { if (revers>0UL) shift = -shift; osi_WrStr(" RX=", 5ul); osic_WrFixed((((float)(band*100000UL+ch*25UL)+_cnst7[offs])-(float)shift)*0.001f, 4L, 1UL); } osi_WrStr(" Po=", 5ul); osic_WrUINT32(mspwr*5UL+10UL, 1UL); osi_WrStr("dBm", 4ul); osi_WrStr(" LA=", 5ul); osic_WrUINT32(cont->la, 1UL); if ((0x20UL & bsservicedetails)) osi_WrStr(" Voice-Sv", 10ul); if ((0x2UL & bsservicedetails)) osi_WrStr(" Air-encr", 10ul); printmcc(cont->mccmnc); } } else if (bton(b, b_len, 0UL, 2UL)==0UL) { /* MAC RESOURCE p612 */ /* WrStr(" ----B["); WrInt(bton(b,13,3),1); WrStrLn("]"); */ adrtyp = bton(b, b_len, 13UL, 3UL); if (verb) { if (adrtyp==1UL) { osi_WrStr(" SSI=", 6ul); /* ASSI p739 p356 */ osic_WrUINT32(bton(b, b_len, 16UL, 24UL), 1UL); } else if (adrtyp==3UL) { osi_WrStr(" USSI=", 7ul); osic_WrUINT32(bton(b, b_len, 16UL, 24UL), 1UL); } else if (adrtyp==4UL) { osi_WrStr(" SMI=", 6ul); osic_WrUINT32(bton(b, b_len, 16UL, 24UL), 1UL); } else if (adrtyp==6UL) { osi_WrStr(" USSI/UM=", 10ul); osic_WrUINT32(bton(b, b_len, 16UL, 30UL)/64UL, 1UL); osi_WrStr(":", 2ul); osic_WrUINT32(bton(b, b_len, 16UL, 30UL)&63UL, 1UL); } else { osi_WrStr("ADRTYP:", 8ul); osic_WrUINT32(adrtyp, 1UL); osi_WrStr(":", 2ul); osic_WrUINT32(bton(b, b_len, 16UL, 24UL), 1UL); } } } else if (bton(b, b_len, 0UL, 4UL)==9UL) { /* 9 MAC RESOURCE p631 */ if (verb) { osi_WrStr(" ACCESS-DEF:", 13ul); osic_WrINT32(bton(b, b_len, 27UL, 2UL), 1UL); if (bton(b, b_len, 27UL, 2UL)==2UL) { /* 2 */ osi_WrStr(" GSSI=", 7ul); /*WrCard(bton(b,27,2),1); WrStr(":"); */ /*WrCard(bton(b,0,4),1); WrStr(":"); */ /* WrCard(bton(b,45,24),1); */ osic_WrUINT32(bton(b, b_len, 29UL, 24UL), 1UL); } } } } /* end showSBBLK2() */ static void SCHf(const char b[], uint32_t b_len, const signed char type4[], uint32_t type4_len, uint32_t len, uint32_t slot) { /*WrStr("S["); FOR i:=0 TO len-1 DO WrInt(ORD(b[i]),1) END; WrStrLn("]"); */ if (slot>3UL) slot = 3UL; if (chanfds[0U]>=0L || soundfd>=0L) { /* else save cpu */ decodeaudio(type4, type4_len, slot); } } /* end SCHf() */ static uint8_t tetrarx_B[256] = {0U,1U,1U,2U,1U,2U,2U,3U,1U,2U,2U,3U,2U,3U,3U,4U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U, 3U,4U,4U,5U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U, 5U,6U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U, 2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,1U,2U, 2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,2U,3U,3U,4U, 3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,2U,3U,3U,4U,3U,4U, 4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,3U,4U,4U,5U,4U,5U,5U,6U, 4U,5U,5U,6U,5U,6U,6U,7U,4U,5U,5U,6U,5U,6U,6U,7U,5U,6U,6U,7U,6U,7U,7U,8U}; /* number of ones in a byte */ static uint32_t tetrarx_M8 = 0xFFUL; static uint8_t _cnst8[256] = {0U,1U,1U,2U,1U,2U,2U,3U,1U,2U,2U,3U,2U,3U,3U,4U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U, 4U,4U,5U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U, 6U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,2U, 3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,1U,2U,2U, 3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,2U,3U,3U,4U,3U, 4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,2U,3U,3U,4U,3U,4U,4U, 5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,3U,4U,4U,5U,4U,5U,5U,6U,4U, 5U,5U,6U,5U,6U,6U,7U,4U,5U,5U,6U,5U,6U,6U,7U,5U,6U,6U,7U,6U,7U,7U,8U}; static uint32_t decodeRM(const signed char inb[], uint32_t inb_len, char outb[], uint32_t outb_len) { uint32_t errs; uint32_t best; uint32_t min0; uint32_t i0; uint32_t out; uint32_t in; in = 0UL; i0 = 0UL; do { if ((int32_t)inb[i0]<=0L) in |= (1UL<>8)&0xFFUL)]+(uint32_t)_cnst8[(uint32_t)((uint32_t)((uint32_t)out>>16)&0xFFUL)]+(uint32_t) _cnst8[(uint32_t)(uint32_t)((uint32_t)out>>24)]; /* fast error bits counter */ if (errs0UL) { osi_WrStr("RM-corr=", 9ul); osic_WrUINT32(min0, 1UL); osi_WrStr(" ", 2ul); } /*WrStr("D["); FOR i:=0 TO 13 DO WrCard(ORD(outb[i]),1) END; WrStrLn("]"); */ return (uint32_t)(min0>3UL); } /* end decodeRM() */ static void showBB(const char b[], uint32_t b_len, struct CONTEXT * cont) /* p. 634 */ { uint32_t f2; uint32_t f1; uint32_t head; head = bton(b, b_len, 0UL, 2UL); f1 = bton(b, b_len, 2UL, 6UL); f2 = bton(b, b_len, 8UL, 6UL); cont->istrafic = 0; /*WrInt(cont.fn,1);WrStr("B["); FOR i:=0 TO 13 DO WrCard(ORD(b[i]),1) END; WrStrLn("]"); */ /* IF cont.fn=18 THEN */ /* ELSE */ if ((head&1)) { /* downlink usage */ /*WrStr("DL-Usage=");WrCard(f1, 1); WrStr(" "); */ cont->istrafic = f1>=4UL; } /* cont.istrafic:=TRUE; */ /* END; */ } /* end showBB() */ static void decode(signed char fr[], uint32_t fr_len, uint32_t start, uint32_t len, struct CONTEXT * cont, uint32_t ftyp) { uint32_t deint; uint32_t crclen; uint32_t vitlen; uint32_t i0; signed char bd[510]; signed char b[510]; signed char bdp[2001]; char bdv[2001]; uint32_t crcok; uint32_t tmp; X2C_PCOPY((void **)&fr,fr_len); tmp = len-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { b[i0] = fr[i0+start]; if (i0==tmp) break; } /* end for */ /*WrStr("U["); FOR i:=start TO start+len-1 DO WrInt(ORD(fr[i]<0),1); END; WrStrLn("]"); */ if (len==120UL) { vitlen = 80UL; crclen = 60UL; deint = 11UL; } else if (len==216UL) { vitlen = 144UL; crclen = 124UL; deint = 101UL; } else if (len==30UL) { vitlen = 0UL; crclen = 0UL; } else if (len==432UL) { vitlen = 288UL; crclen = 268UL; deint = 103UL; } /*WrStr(" len=");WrCard(len,1); */ /*WrStr(" xor="); WrCard(CAST(CARDINAL, xor),1); WrStrLn(""); */ descramble(b, 510ul, cont->xor, len); if (len==30UL) { /* reed muller */ crcok = decodeRM(b, 510ul, bdv, 2001ul); showBB(bdv, 2001ul, cont); } else { deinterleave(len, deint, b, 510ul, bd, 510ul); depuncture(tetrarx_PUNCT23, bd, 510ul, len, bdp, 2001ul); /*WrStr("d["); FOR i:=0 TO len DO WrInt(bd[i],1); WrStr(" "); END; WrStrLn("]"); */ viterbidec(bdp, 2001ul, vitlen, (char *)bdv, 2001u/1u); /*WrInt(vitlen,1);WrStr(" v["); FOR i:=0 TO vitlen-1 DO WrInt(ORD(bdv[i]),1); END; WrStrLn("]"); */ crcok = crc16(bdv, 2001ul, crclen+16UL); if (verb) { osi_WrStr("crc=", 5ul); osic_WrUINT32(crcok, 1UL); osi_WrStr(" ", 2ul); } if (crcok==0UL) { if (len==120UL) showSBBLK1(bdv, 2001ul, crclen, cont); else if (len==216UL) { showSBBLK2(bdv, 2001ul, crclen, cont); if (ftyp==2UL) showSCHf(bdv, 2001ul, crclen); } else if (len==432UL) showSCHf(bdv, 2001ul, crclen); } /* ELSIF len=NDBBLKBITS THEN showNDB(bdv, crclen); */ if (len==432UL && (isuplink || cont->istrafic)) { SCHf(bdv, 2001ul, b, 510ul, crclen, cont->tn); if (verb) { osi_WrStr(" Data[", 7ul); osic_WrUINT32(context.fn, 1UL); osi_WrStr("/", 2ul); osic_WrUINT32(context.tn, 1UL); osi_WrStr("]", 2ul); } } } X2C_PFREE(fr); } /* end decode() */ static signed char fb[510]; static void decodefr(const signed char fr[], uint32_t fr_len, uint32_t frlen) { uint32_t typ; uint32_t i0; /* WrFixed(context.db, 1,1); WrStr("dB "); */ /* WrInt(context.offset, 1); WrStr("Hz "); */ typ = frametyp(fr, fr_len, frlen); if (verb) { osi_WrStr("FT=", 4ul); osic_WrUINT32(typ, 1UL); osi_WrStr(" ", 2ul); } if (typ==3UL) { context.xor = 0x3UL; decode(fr, fr_len, 94UL, 120UL, &context, 3UL); decode(fr, fr_len, 252UL, 30UL, &context, 3UL); decode(fr, fr_len, 282UL, 216UL, &context, 3UL); if (verb) osi_WrStrLn("", 1ul); } else if (typ==2UL) { if (isuplink) { decode(fr, fr_len, 28UL, 216UL, &context, 2UL); decode(fr, fr_len, 266UL, 216UL, &context, 2UL); } else { /* re-combine the broadcast block */ for (i0 = 0UL; i0<=13UL; i0++) { fb[i0] = fr[i0+230UL]; } /* end for */ for (i0 = 0UL; i0<=15UL; i0++) { fb[i0+14UL] = fr[i0+266UL]; } /* end for */ decode(fb, 510ul, 0UL, 30UL, &context, 2UL); decode(fr, fr_len, 14UL, 216UL, &context, 2UL); decode(fr, fr_len, 282UL, 216UL, &context, 2UL); } if (verb) osi_WrStrLn("", 1ul); } else if (typ==1UL) { /* SCH/F */ if (!isuplink) ++context.tn; if (context.tn>3UL) { context.tn = 0UL; context.fn = context.fn%18UL+1UL; } if (isuplink) { /*WrStr("u["); FOR i:=0 TO frlen-1 DO WrInt(ORD(fr[i]<0),1); END; WrStrLn("]"); */ for (i0 = 0UL; i0<=215UL; i0++) { fb[i0] = fr[i0+28UL]; } /* end for */ for (i0 = 0UL; i0<=215UL; i0++) { fb[i0+216UL] = fr[i0+266UL]; } /* end for */ decode(fb, 510ul, 0UL, 432UL, &context, 1UL); } else { /* re-combine the broadcast block */ for (i0 = 0UL; i0<=13UL; i0++) { fb[i0] = fr[i0+230UL]; } /* end for */ for (i0 = 0UL; i0<=15UL; i0++) { fb[i0+14UL] = fr[i0+266UL]; } /* end for */ decode(fb, 510ul, 0UL, 30UL, &context, 1UL); for (i0 = 0UL; i0<=215UL; i0++) { fb[i0] = fr[i0+14UL]; } /* end for */ for (i0 = 0UL; i0<=215UL; i0++) { fb[i0+216UL] = fr[i0+282UL]; } /* end for */ decode(fb, 510ul, 0UL, 432UL, &context, 1UL); } if (verb) osi_WrStrLn("", 1ul); } else if (verb) osi_WrStrLn("", 1ul); if (labs(scanoffs-context.offset)<10000L) rxany = 1; } /* end decodefr() */ /*---------------tetradec end */ static void lp(float in, struct LPCONTEXT24 * c) /* lowpass 24db/oct 6dB loss */ { struct LPCONTEXT24 * anonym; { /* with */ struct LPCONTEXT24 * anonym = c; anonym->uc1 = (anonym->uc1+(in-anonym->uc1)*anonym->LPR)-anonym->il; anonym->uc2 = anonym->uc2*anonym->OLPR+anonym->il; anonym->il = anonym->il+(anonym->uc1-anonym->uc2)*anonym->LPL; } /* result is uc2 */ } /* end lp() */ static uint8_t tetrarx_B0[256] = {0U,1U,1U,2U,1U,2U,2U,3U,1U,2U,2U,3U,2U,3U,3U,4U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U, 3U,4U,4U,5U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U, 5U,6U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U, 2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,1U,2U, 2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,2U,3U,3U,4U, 3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,2U,3U,3U,4U,3U,4U, 4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,3U,4U,4U,5U,4U,5U,5U,6U, 4U,5U,5U,6U,5U,6U,6U,7U,4U,5U,5U,6U,5U,6U,6U,7U,5U,6U,6U,7U,6U,7U,7U,8U}; static uint8_t _cnst9[256] = {0U,1U,1U,2U,1U,2U,2U,3U,1U,2U,2U,3U,2U,3U,3U,4U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U, 4U,4U,5U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U, 6U,1U,2U,2U,3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,2U, 3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,1U,2U,2U, 3U,2U,3U,3U,4U,2U,3U,3U,4U,3U,4U,4U,5U,2U,3U,3U,4U,3U,4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,2U,3U,3U,4U,3U, 4U,4U,5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,2U,3U,3U,4U,3U,4U,4U, 5U,3U,4U,4U,5U,4U,5U,5U,6U,3U,4U,4U,5U,4U,5U,5U,6U,4U,5U,5U,6U,5U,6U,6U,7U,3U,4U,4U,5U,4U,5U,5U,6U,4U, 5U,5U,6U,5U,6U,6U,7U,4U,5U,5U,6U,5U,6U,6U,7U,5U,6U,6U,7U,6U,7U,7U,8U}; static char errlim(uint32_t s, uint32_t lim0) /* fast count 1 in a bitset */ { uint32_t c; c = (uint32_t)_cnst9[(uint32_t)(s&0xFFUL)]; if (c>lim0) return 0; c += (uint32_t)_cnst9[(uint32_t)(X2C_LSH(s,32,-8)&0xFFUL)]; c += (uint32_t)_cnst9[(uint32_t)(X2C_LSH(s,32,-16)&0xFFUL)]; c += (uint32_t)_cnst9[(uint32_t)X2C_LSH(s,32,-24)]; return c<=lim0; } /* end errlim() */ /*-------------------- D4PSK */ static void d4pskframe(const signed char fb0[], uint32_t fb_len, uint32_t flen, struct DQPSKMODEM * m) { uint32_t i0; float afchz; float d; char dat[510]; int32_t offs; uint32_t tmp; /* offs:=VAL(INTEGER, (VAL(REAL, VAL(INT16,m.iffreqc))+0.0*m.pllf*PLLGAIN*m.ddsbase)/m.ddsbase); */ offs = (int32_t)X2C_TRUNCI(X2C_DIVR((float)(short)m->iffreqc,m->ddsbase),X2C_min_longint,X2C_max_longint); if (flen>1UL) { afchz = X2C_DIVR(m->pllf*3200.0f*m->ddsbase+(float)m->croase,m->ddsbase); d = dB(m->rflevel)*0.5f-90.0f; decodefr(fb0, fb_len, flen); if (verb) { osi_WrStr("Tetra:", 7ul); osic_WrUINT32(m->modemnum, 1UL); osi_WrStr(" fr:", 5ul); osic_WrUINT32(m->ftyp, 1UL); /* WrStr(" offs:"); WrInt(VAL(INTEGER, VAL(REAL, VAL(INT16,m.iffreq))/m.ddsbase),1); WrStr("Hz"); */ osi_WrStr(" offs:", 7ul); osic_WrINT32((uint32_t)offs, 1UL); osi_WrStr("Hz", 3ul); osi_WrStr(" afc:", 6ul); osic_WrINT32((uint32_t)(int32_t)X2C_TRUNCI(afchz,X2C_min_longint,X2C_max_longint), 1UL); osi_WrStr("Hz ", 4ul); osic_WrINT32((uint32_t)(int32_t)X2C_TRUNCI((0.5f-m->qual)*200.0f,X2C_min_longint,X2C_max_longint), 1UL); osi_WrStr("% ", 3ul); osic_WrFixed(d, 1L, 5UL); osi_WrStr("dB ", 4ul); osi_WrStr("len:", 5ul); osic_WrINT32(flen, 1UL); if (verb2) { osi_WrStr(" [", 3ul); tmp = flen-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { dat[i0] = (char)((uint32_t)((int32_t)fb0[i0]>=0L)+48UL); if (i0==tmp) break; } /* end for */ if (flen<=509UL) dat[flen] = 0; osi_WrStr(dat, 510ul); osi_WrStrLn("]", 2ul); } /*WrFixed(VAL(REAL,m.croase)/m.ddsbase,1,1); WrStr("Hz "); */ /*IF (flen=206) & fb[0] & fb[1] & NOT fb[2] & NOT fb[3] & fb[202] & fb[203] & NOT fb[204] & NOT fb[205] THEN WrStr(" uplink burst") END; */ osi_WrStrLn("", 1ul); } } } /* end d4pskframe() */ #define tetrarx_FULLLEN 510 #define tetrarx_CONTROLLEN 206 static uint32_t tetrarx_TRAIN1 = 0x343A74UL; static uint32_t tetrarx_TRAIN1MASK = 0x3FFFFFUL; #define tetrarx_TRAIN1END 244 static uint32_t tetrarx_TRAIN2 = 0x1E90DEUL; static uint32_t tetrarx_TRAIN2MASK = 0x3FFFFFUL; #define tetrarx_TRAIN2END 244 static uint32_t tetrarx_TRAIN3 = 0x2DC1ADUL; static uint32_t tetrarx_TRAIN3MASK = 0x3FFFFFUL; #define tetrarx_TRAIN3END 244 /*1011010110 000011101101 */ static uint32_t tetrarx_TRAINX0 = 0x2743A743UL; static uint32_t tetrarx_TRAINXMASK = 0x3FFFFFFFUL; #define tetrarx_TRAINXEND 88 static uint32_t tetrarx_TRAINSL = 0x673A7067UL; static uint32_t tetrarx_TRAINSH = 0x30UL; static uint32_t tetrarx_TRAINSHMASK = 0x3FUL; #define tetrarx_TRAINSEND 258 /*(1,1, 0,0, 0,0, 0,1, 1,0, 0,1, 1,1, 0,0, 1,1, 1,0, 1,0, 0,1, 1,1, 0,0, 0,0, 0,1, 1,0, 0,1, 1,1) */ /*110000101110010111000010111001 */ /* 0010111001011100001011 */ /* TRAIN2=SET32{1,2,3,4,6,7,12,15,17,18,19,20}; */ /* TRAIN2MASK=SET32{0..21}; */ /* TRAIN1=SET32{2,4,5,6,9,11,12,13,18,20,21}; */ /* TRAIN1MASK=SET32{0..21}; */ /* TRAINSYN=ARRAY OF CARD8{1,1,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,1,0,1,0,0,1,1,1,0,0,0,0,0,1,1,0,0,1,1,1}; */ /* TRAIN1=ARRAY OF CARD8{1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,1,1,1,0,1,0,0}; */ /* TRAIN2=ARRAY OF CARD8{0,1,1,1,1,0,1,0,0,1,0,0,0,0,1,1,0,1,1,1,1,0}; */ static void d4psksymb(float w, struct DQPSKMODEM * m) /* continous downlink 1,0, 1,1, 0,1, 1,1, 0,0, 0,0, 0,1, 1,0, 1,0, 1,1, 0,1*/ { uint8_t dd; uint8_t d; signed char soft; uint32_t flen; uint32_t i0; signed char fb0[510]; uint32_t tmp; d = (uint8_t)X2C_TRUNCC(w,0U,255U); dd = (uint8_t)((uint32_t)d-(uint32_t)m->lastd&3UL); m->lastd = d; soft = (signed char)X2C_TRUNCI((w-(float)d)*127.0f,-128,127); m->synwh = X2C_LSH(m->synwh,32,2)|X2C_LSH(m->synw,32,-30); m->synw = X2C_LSH(m->synw,32,2); switch ((unsigned)dd) { case 0U: m->fifo[m->fifop] = (signed char)(127L-(int32_t)soft); m->fifo[m->fifop+1UL] = soft; break; case 1U: m->fifo[m->fifop] = -soft; m->fifo[m->fifop+1UL] = (signed char)(127L-(int32_t)soft); m->synw |= 0x2UL; break; case 2U: m->fifo[m->fifop] = (signed char)((int32_t)soft-127L); m->fifo[m->fifop+1UL] = -soft; m->synw |= 0x1UL; m->synw |= 0x2UL; break; default:; m->fifo[m->fifop] = soft; m->fifo[m->fifop+1UL] = (signed char)((int32_t)soft-127L); m->synw |= 0x1UL; break; } /* end switch */ m->fifop = (m->fifop+2UL)%510UL; if (errlim(m->synw^0x673A7067UL, 1UL) && errlim(m->synwh&0x3FUL^0x30UL, 1UL)) { m->ftyp = 3UL; m->fend = m->fifop+258UL; } else if (errlim(m->synw&0x3FFFFFFFUL^0x2743A743UL, 2UL)) { /*WrStr("syn3:");WrCard(testc,1); WrStrLn(""); */ m->ftyp = 4UL; m->fend = m->fifop+88UL; } else if (errlim(m->synw&0x3FFFFFUL^0x343A74UL, 0UL)) { /*WrStr("syn4:");WrCard(testc,1); WrStrLn(""); */ m->ftyp = 1UL; m->fend = m->fifop+244UL; } else if (errlim(m->synw&0x3FFFFFUL^0x1E90DEUL, 0UL)) { /*WrStr("syn1:");WrCard(testc,1); WrStrLn(""); */ m->ftyp = 2UL; m->fend = m->fifop+244UL; } /*WrStr("syn2:");WrCard(testc,1); WrStrLn(""); */ if (m->ftyp>0UL && m->fend%510UL==m->fifop) { flen = 510UL; if (m->ftyp==4UL) flen = 206UL; /*WrStrLn(""); */ tmp = flen-1UL; i0 = 0UL; if (i0<=tmp) for (;; i0++) { fb0[i0] = m->fifo[((i0+510UL+m->fifop)-flen)%510UL]; if (i0==tmp) break; } /* end for */ /*WrInt(ORD(m.fifo[i]),1); */ /*WrStrLn(""); */ d4pskframe(fb0, 510ul, flen, m); m->ftyp = 0UL; } } /* end d4psksymb() */ #define tetrarx_DLLSPEED 32 /* 32 */ #define tetrarx_AFCTHRES 0.1 /* 0.1 */ static void sampled4psk(int32_t ire, int32_t iim, struct DQPSKMODEM * m) { uint32_t dm; uint32_t c; float w; float lev; int32_t ico; int32_t isi; struct Complex s; isi = (int32_t)DDS[(uint32_t)m->ifosc&16383UL]; ico = (int32_t)DDS[(uint32_t)m->ifosc+4096UL&16383UL]; m->ifosc += m->iffreqc; lp((float)(iim*ico-ire*isi), &m->iflpq); lp((float)(ire*ico+iim*isi), &m->iflpi); c = m->ifsamp; dm = m->ifstep; if (m->dir>0L) dm += m->ifstep/32UL; else if (m->dir<0L) dm -= m->ifstep/32UL; m->dir = 0L; m->ifsamp += dm; /* wrap around 32bit */ if (m->ifsampiflpq.uc2; s.Im = m->iflpi.uc2; lev = s.Re*s.Re+s.Im*s.Im; /* gain for symbol sync and measurement */ w = fmhighpass(atan20(s), &m->fmo); /* fm demod for wide range afc */ m->fm = m->fm+(w-m->fm)*0.001f; /* fm lowpass */ if ((float)fabs(m->fm)>0.1f && labs(m->croase)maxcroase) { /* croase afc threshold and in limit */ if (m->fm>=0.0f) { m->croase -= (int32_t)(uint32_t)X2C_TRUNCC(1000.0f*m->ddsbase,0UL,X2C_max_longcard); } else m->croase += (int32_t)(uint32_t)X2C_TRUNCC(1000.0f*m->ddsbase,0UL,X2C_max_longcard); m->fm = 0.0f; } /* IF m.croase>m.afclimit THEN m.croase:=m.afclimit; */ /* ELSIF m.croase<-m.afclimit THEN m.croase:=-m.afclimit END; */ if (m->state==0UL) m->lev1 = lev; else if (m->state==1UL) m->lowlev = lev; else if (m->state==2UL) m->lev2 = lev; else { if ((m->olev+lev)*0.43f>m->lowlev) { /* 0.45 big fase jump used for adjust symbol sync */ m->dir = (int32_t)((uint32_t)(m->lev1lev2)*2UL-1UL); /* move symbol sample time */ } /*smeter */ m->rflevel = m->rflevel+(lev-m->rflevel)*0.02f; m->olev = lev; /*symbol phase 0.0..4.0 + pi/8 shift remove */ w = atan20(s)*6.3661977238578E-1f+2.0f+(float)m->pllosc*0.5f; m->pllosc = m->pllosc+1UL&7UL; if (w<0.0f) w = w+4.0f; else if (w>4.0f) w = w-4.0f; d4psksymb(w, m); /*--carrier pll */ w = (w-(float)(int32_t)X2C_TRUNCI(w,X2C_min_longint,X2C_max_longint))-0.5f; /* -0.5..0.5 phase error */ m->qual = m->qual*0.975f+(float)fabs(w)*0.025f; /* 0.025 */ m->pllf = m->pllf-w*0.15f; m->plllag = m->plllag+(m->pllf-m->plllag)*0.05f; /* 0.05 0.02 for dx */ /* lead lag pll loopfilter */ m->pllf = m->pllf+(m->plllag-m->pllf)*0.6f; /* 0.6 */ if (m->pllf>0.35f) m->pllf = 0.35f; else if (m->pllf<(-0.35f)) m->pllf = (-0.35f); } m->iffreqc = (uint16_t)((int32_t)m->iffreq+m->croase+(int32_t)X2C_TRUNCI(m->pllf*3200.0f*m->ddsbase, X2C_min_longint,X2C_max_longint)); m->state = m->state+1UL&3UL; } } /* end sampled4psk() */ static short realint(float x, float * g) /* limit real input > +-1.0 to INT16*/ { float r; /* r:=SaveReal(CAST(CARDINAL, x))*g; */ r = x* *g; if ((float)fabs(r)>=32766.0f) { *g = X2C_DIVR(1.073643522E+9f,(float)fabs(r)); r = x* *g; if (r>32767.0f) return 32767; if (r<(-3.2767E+4f)) return -32768; } return (short)X2C_TRUNCI(r,-32768,32767); } /* end realint() */ union _2; union _2 { struct Complex c[4096]; short i0[16384]; uint8_t b[32768]; }; static uint32_t inreform(short b[], uint32_t b_len) { uint32_t wp0; uint32_t rs; uint32_t bs; uint32_t i0; int32_t res; union _2 ib; char * p; float g; uint32_t tmp; bs = isize*8192UL; if (bs>((b_len-1)+1UL)*2UL) bs = ((b_len-1)+1UL)*2UL; rs = 0UL; do { p = (char *) &ib.b[rs]; res = osi_RdBin(iqfd, p, 65536ul, bs-rs); if (res<=0L) return 0UL; rs += (uint32_t)res; } while (rsnext; } } X2C_EXIT(); return 0; } X2C_MAIN_DEFINITION