/* Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO This file is part of QtSoundModem QtSoundModem is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. QtSoundModem is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with QtSoundModem. If not, see http://www.gnu.org/licenses */ // UZ7HO Soundmodem Port by John Wiseman G8BPQ #include "UZ7HOStuff.h" extern int blnBusyStatus; extern word MEMRecovery[5]; void make_rx_frame_FX25(int snd_ch, int rcvr_nr, int emph, string * data); string * memory_ARQ(TStringList * buf, string * data); void CreateStringList(TStringList * List); void analiz_frame(int snd_ch, string * frame, char * code, boolean fecflag); void KISS_on_data_out(int port, string * frame, int TX); void updateDCD(int Chan, boolean State); void Frame_Optimize(TAX25Port * AX25Sess, TStringList * buf); void RX2TX(int snd_ch); int fx25_decode_rs(Byte * data, int * eras_pos, int no_eras, int pad, int rs_size); void il2p_rec_bit(int chan, int subchan, int slice, int dbit); float GuessCentreFreq(int i); void ProcessRXFrames(int snd_ch); extern struct il2p_context_s *il2p_context[4][16][3]; /* unit ax25_demod; interface uses math,sysutils,Graphics,classes; procedure detector_init; procedure detector_free; procedure Mux3(snd_ch,rcvr_nr,emph: byte; src1,core: array of single; var dest,prevI,prevQ: array of single; tap,buf_size: word); procedure Mux3_PSK(snd_ch,rcvr_nr,emph: byte; src1,core: array of single; var destI,destQ,prevI,prevQ: array of single; tap,buf_size: word); procedure make_core_intr(snd_ch: byte); procedure make_core_LPF(snd_ch: byte; width: single); procedure make_core_BPF(snd_ch: byte; freq,width: single); procedure make_core_TXBPF(snd_ch: byte; freq,width: single); procedure init_BPF(freq1,freq2: single; tap: word; samplerate: single; var buf: array of single); procedure FIR_filter(src: array of single; buf_size,tap: word; core: array of single; var dest,prev: array of single); procedure Demodulator(snd_ch,rcvr_nr: byte; src_buf: array of single; last: boolean); function memory_ARQ(buf: TStringList; data: string): string; type TSurvivor = record BitEstimates: int64; Pathdistance: integer; } type TMChannel = record prev_LPF1I_buf : array [0..4095] of single; prev_LPF1Q_buf : array [0..4095] of single; prev_dLPFI_buf : array [0..4095] of single; prev_dLPFQ_buf : array [0..4095] of single; prev_AFCI_buf : array [0..4095] of single; prev_AFCQ_buf : array [0..4095] of single; AngleCorr : single; MUX_osc : single; AFC_IZ1 : single; AFC_IZ2 : single; AFC_QZ1 : single; AFC_QZ2 : single; AFC_bit_buf1I : array [0..1023] of single; AFC_bit_buf1Q : array [0..1023] of single; AFC_bit_buf2 : array [0..1023] of single; AFC_IIZ1 : single; AFC_QQZ1 : single; } */ #define sbc 175 single ch_offset[4] = { -sbc * 1.5,-sbc * 0.5,sbc*0.5,sbc*1.5 }; float PI125 = 0.125f * M_PI; float PI375 = 0.375f * M_PI; float PI625 = 0.625f * M_PI; float PI875 = 0.875f * M_PI; float PI5 = 0.5f * M_PI; float PI25 = 0.25f * M_PI; float PI75 = 0.75f * M_PI; unsigned char modem_mode[5] ={0,0,0,0}; unsigned short bpf[5] = { 500, 500, 500, 500,500 }; unsigned short lpf[5] = { 150, 150, 150, 150, 150 }; float BIT_AFC = 32; float slottime_tick[5] = { 0 }; float resptime_tick[5] = { 0 }; int dcd_threshold = 128; int rxOffset = 0; int chanOffset[4] = { 0,0,0,0 }; float DCD_LastPkPos[5] = { 0 }; float DCD_LastPerc[5] = { 0 }; int dcd_bit_cnt[5] = { 0 }; Byte DCD_status[5] = { 0 }; float DCD_persist[5] = { 0 }; int dcd_bit_sync[5] = { 0 }; Byte dcd_hdr_cnt[5] = { 0 }; longword DCD_header[5] = { 0 }; int dcd_on_hdr[5] = { 0 }; extern int centreFreq[4]; float lastangle[4]; // pevious value for differential modes unsigned short n_INTR[5] = { 1,1,1,1,1 }; unsigned short INTR_tap[5] = { 16, 16,16,16,16 }; unsigned short BPF_tap[5] = { 256, 256,256,256,256 }; // 256 default unsigned short LPF_tap[5] = { 128, 128,128,128,128 }; // 128 short rx_freq[5] = { 1700, 1700,1700,1700,1700 }; short rx_shift[5] = { 200, 200, 200, 200, 200 }; short rx_baudrate[5] = { 300, 300, 300, 300, 300 }; short rcvr_offset[5] = { 30, 30, 30, 30,30 }; // rx_freq is configured freq. We shouldn't change it so need a sparate variable // for the actual demod freq when using multiple decoders short active_rx_freq[5] = { 1700, 1700,1700,1700,1700 }; int fx25_mode[4] = { 0, 0, 0, 0 }; int il2p_mode[4] = { 0, 0, 0, 0 }; int il2p_crc[4] = { 0, 0, 0, 0 }; int pnt_change[5] = { 0 }; float src_buf[5][2048]; float INTR_core[5][2048]; float AFC_core[5][2048]; float LPF_core[5][2048]; int new_tx_port[4] = { 0,0,0,0 }; UCHAR RCVR[5] = { 0 }; // We allow two (or more!) ports to be assigned to the same soundcard channel int soundChannel[5] = { 0 }; // 0 = Unused 1 = Left 2 = Right 3 = Mono int modemtoSoundLR[4] = { 0 }; struct TDetector_t DET[nr_emph + 1][16]; // Chan, Decoder, Emph float Phases[4][16][nr_emph + 1][4096]; float Mags[4][16][nr_emph + 1][4096]; int nPhases[4][16][nr_emph + 1]; TStringList detect_list_l[5]; TStringList detect_list[5]; TStringList detect_list_c[5]; int lastDCDState[4] = { 0,0,0,0 }; /* implementation uses sm_main,ax25,ax25_l2,ax25_mod,ax25_agw,rsunit,kiss_mode; */ void detector_init() { int i, k, j; for (k = 0; k < 16; k++) { for (i = 1; i <= 4; i++) { for (j = 0; j <= nr_emph; j++) { struct TDetector_t * pDET = &DET[j][k]; pDET->fx25[i].status = FX25_TAG; pDET->AngleCorr[i] = 0; pDET->last_sample[i] = 0; pDET->sample_cnt[i] = 0; pDET->last_bit[i] = 0; pDET->PkAmp[i] = 0; pDET->PkAmpMax[i] = 0; pDET->newpkpos[i] = 0; pDET->ones[i] = 0; pDET->zeros[i] = 0; pDET->MinAmp[i] = 0; pDET->MaxAmp[i] = 0; pDET->MUX3_osc[i] = 0; pDET->Preemphasis6[i] = 0; pDET->Preemphasis12[i] = 0; pDET->PSK_AGC[i] = 0; pDET->AGC[i] = 0; pDET->AGC1[i] = 0; pDET->AGC2[i] = 0; pDET->AGC3[i] = 0; pDET->AGC_max[i] = 0; pDET->AGC_min[i] = 0; pDET->AFC_IZ1[i] = 0; pDET->AFC_IZ2[i] = 0; pDET->AFC_QZ1[i] = 0; pDET->AFC_QZ2[i] = 0; pDET->AFC_dF[i] = 0; pDET->AFC_cnt[i] = 0; pDET->PSK_IZ1[i] = 0; pDET->PSK_QZ1[i] = 0; pDET->PkAmpI[i] = 0; pDET->PkAmpQ[i] = 0; pDET->last_rx_bit[i] = 0; pDET->bit_stream[i] = 0; pDET->byte_rx[i] = 0; pDET->bit_stuff_cnt[i] = 0; pDET->bit_cnt[i] = 0; pDET->bit_osc[i] = 0; pDET->frame_status[i] = 0; initString(&pDET->FEC_rx_data[i]); initString(&pDET->rx_data[i]); initString(&pDET->raw_bits[i]); initTStringList(&pDET->mem_ARQ_buf[i]); initTStringList(&pDET->mem_ARQ_F_buf[i]); pDET->rx_decoded = 0; pDET->emph_decoded = 0; } } } for (i = 1; i <= 4; i++) { initTStringList(&detect_list[i]); initTStringList(&detect_list_l[i]); initTStringList(&detect_list_c[i]); } } /* procedure detector_free; var i,k,j: word; { for i = 1 to 4 do { detect_list[i].Free; detect_list_l[i].Free; detect_list_c[i].Free; } for k = 0 to 16 do for i = 1 to 4 do for j = 0 to nr_emph do { DET[j,k].mem_ARQ_buf[i].Free; DET[j,k].mem_ARQ_F_buf[i].Free; } } */ void FIR_filter(float * src, unsigned short buf_size, unsigned short tap, float * core, float * dest, float * prev) { float accum = 0.0f; float fp1; int eax, ebx; float * edi; fmove(&prev[buf_size], &prev[0], tap * 4); fmove(&src[0], &prev[tap], buf_size * 4); eax = 0; // ; shl ecx, 2; // ; shl edx, 2; cfir_i: edi = prev; edi += eax; ebx = 0; accum = 0.0f; cfir_k: // FLD pushes operand onto stack, so old value goes to fp1 fp1 = accum; accum = edi[ebx]; accum *= core[ebx]; accum += fp1; ebx++; if (ebx != tap) goto cfir_k; dest[eax] = accum; eax++; if (eax != buf_size) goto cfir_i; } float get_persist(int snd_ch, int persist) { single x, x1 ; x = 256 / persist; x1 = round(x*x) * rand() / RAND_MAX; return x1 * 0.5 * slottime[snd_ch]; } void chk_dcd1(int snd_ch, int buf_size) { // This seems to schedule all TX, but is only called when a frame has been processed // ? does this work as Andy passes aborted frames to decoder Byte port; int i; single tick; word active; boolean ind_dcd; boolean dcd_sync; longint n; TAX25Port * AX25Sess; dcd[snd_ch] = 1; ind_dcd = 0; tick = 1000 / RX_Samplerate; if (modem_mode[snd_ch] == MODE_ARDOP) { dcd_bit_sync[snd_ch] = blnBusyStatus; } else if (modem_mode[snd_ch] == MODE_RUH) { dcd_bit_sync[snd_ch] = blnBusyStatus; } else { if (dcd_bit_cnt[snd_ch] > 0) dcd_bit_sync[snd_ch] = 0; else dcd_bit_sync[snd_ch] = 1; if (dcd_on_hdr[snd_ch]) dcd_bit_sync[snd_ch] = 1; if (modem_mode[snd_ch] == MODE_MPSK && DET[0][0].frame_status[snd_ch] == FRAME_LOAD) dcd_bit_sync[snd_ch] = 1; } if (lastDCDState[snd_ch] != dcd_bit_sync[snd_ch]) { updateDCD(snd_ch, dcd_bit_sync[snd_ch]); updateDCD(snd_ch, dcd_bit_sync[snd_ch]); lastDCDState[snd_ch] = dcd_bit_sync[snd_ch]; } if (resptime_tick[snd_ch] < resptime[snd_ch]) resptime_tick[snd_ch] = resptime_tick[snd_ch] + tick * buf_size; slottime_tick[snd_ch] = slottime_tick[snd_ch] + tick * buf_size; if (dcd_bit_sync[snd_ch]) // reset the slottime timer { slottime_tick[snd_ch] = 0; DCD_status[snd_ch] = DCD_WAIT_SLOT; } switch (DCD_status[snd_ch]) { case DCD_WAIT_SLOT: if (slottime_tick[snd_ch] >= slottime[snd_ch]) { DCD_status[snd_ch] = DCD_WAIT_PERSIST; DCD_persist[snd_ch] = get_persist(snd_ch, persist[snd_ch]); } break; case DCD_WAIT_PERSIST: if (slottime_tick[snd_ch] >= slottime[snd_ch] + DCD_persist[snd_ch]) { dcd[snd_ch] = FALSE; slottime_tick[snd_ch] = 0; DCD_status[snd_ch] = DCD_WAIT_SLOT; } break; } active = 0; for (i = 0; i < port_num; i++) { if (AX25Port[snd_ch][i].status != STAT_NO_LINK) active++; if (active < 2) resptime_tick[snd_ch] = resptime[snd_ch]; if (TX_rotate) { for (int n = 0; n < 4; n++) { if (snd_status[n] == SND_TX) dcd[snd_ch] = TRUE; } } if (snd_ch == 1) snd_ch = 1; if (!dcd[snd_ch] && resptime_tick[snd_ch] >= resptime[snd_ch]) { int n = 0; port = new_tx_port[snd_ch]; do { AX25Sess = &AX25Port[snd_ch][port]; if (AX25Sess->frame_buf.Count > 0) Frame_Optimize(AX25Sess, &AX25Sess->frame_buf); if (AX25Sess->frame_buf.Count > 0) { for (n = 0; n < AX25Sess->frame_buf.Count; n++) { Add(&all_frame_buf[snd_ch], duplicateString(Strings(&AX25Sess->frame_buf, n))); } Clear(&AX25Sess->frame_buf); } port++; if (port >= port_num) port = 0; if (all_frame_buf[snd_ch].Count > 0) new_tx_port[snd_ch] = port; n++; } while (all_frame_buf[snd_ch].Count == 0 && n < port_num); // Add KISS frames if (KISSServ) { // KISS monitor outgoing AGW frames if (all_frame_buf[snd_ch].Count > 0) { for (int n = 0; n < all_frame_buf[snd_ch].Count; n++) { KISS_on_data_out(snd_ch, Strings(&all_frame_buf[snd_ch], n), 1); // Mon TX } } // Add outgoing KISS frames to TX Q if (KISS.buffer[snd_ch].Count > 0) { for (int k = 0; k < KISS.buffer[snd_ch].Count; k++) { if (AGWServ) AGW_Raw_monitor(snd_ch, Strings(&KISS.buffer[snd_ch], n)); // Need to add copy as clear will free original Add(&all_frame_buf[snd_ch], duplicateString(Strings(&KISS.buffer[snd_ch], k))); } Clear(&KISS.buffer[snd_ch]); } } if (all_frame_buf[snd_ch].Count > 0 && snd_status[snd_ch] == SND_IDLE) { resptime_tick[snd_ch] = 0; RX2TX(snd_ch); // Do TX return; } } } } string * get_pkt_data(string * stream) { Byte bitstuff_cnt; Byte bits_cnt; word i; string * s = newString(); Byte bit; Byte raw_bit; Byte sym; bits_cnt = 0; bitstuff_cnt = 0; sym = 0; if (stream->Length > 0) { for (i = 0; i < stream->Length; i++) { if (stream->Data[i] == '1') bit = RX_BIT1; else bit = RX_BIT0; if (bitstuff_cnt < 5) { sym = (sym >> 1) | bit; bits_cnt++; } if (bitstuff_cnt == 5 || bit == RX_BIT0) bitstuff_cnt = 0; if (bit == RX_BIT1) bitstuff_cnt++; if (bits_cnt == 8) { stringAdd(s, &sym, 1); sym = 0; bits_cnt = 0; } } } return s; } string * get_pkt_data2(string * stream, Byte last_nrzi_bit) { Byte bitstuff_cnt; Byte bits_cnt; word i; string * s = newString(); Byte pkt[350]; Byte bit; Byte raw_bit; Byte sym; int n = 0; bits_cnt = 0; bitstuff_cnt = 0; sym = 0; if (stream->Length > 0) { for (i = 0; i < stream->Length; i++) { if (stream->Data[i] == '1') raw_bit = RX_BIT1; else raw_bit = RX_BIT0; if (raw_bit == last_nrzi_bit) bit = RX_BIT1; else bit = RX_BIT0; last_nrzi_bit = raw_bit; if (bitstuff_cnt < 5) { sym = (sym >> 1) | bit; bits_cnt++; } if (bitstuff_cnt == 5 || bit == RX_BIT0) bitstuff_cnt = 0; if (bit == RX_BIT1) bitstuff_cnt++; if (bits_cnt == 8) { if (n < 330) pkt[n++] = sym; sym = 0; bits_cnt = 0; } } } stringAdd(s, pkt, n); return s; } string * get_NRZI_data(string * stream, UCHAR last_nrzi_bit) { longword len; word i; string * s = NULL; Byte raw_bit; len = stream->Length; if (len > 65535) len = 65535; if (len > 0) { s = newString(); setlength(s, len); for (i = 0; i < len; i++) { if (stream->Data[i] == '1') raw_bit = RX_BIT1; else raw_bit = RX_BIT0; if (raw_bit == last_nrzi_bit) s->Data[i] = '1'; else s->Data[i] = '0'; last_nrzi_bit = raw_bit; } } return s; } /* function invert_NRZI_data(stream: string; last_nrzi_bit: byte): string; var len: longword; i: word; s: string; { s = ''; len = length(stream); if len>65535 then len = 65535; if len>0 then { setlength(s,len); for i = 1 to len do if last_nrzi_bit=RX_BIT0 then { if stream[i]='1' then s[i] = '0' else s[i] = '1'; end else s[i] = stream[i]; } result = s; } */ void make_rx_frame(int snd_ch, int rcvr_nr, int emph, Byte last_nrzi_bit, string * raw_data, string * raw_data1) { int swap_i, swap_k; string * data; string * nrzi_data; longword raw_len; word len, crc1, crc2; int arq_mem = 0; string s; int i, k, n; unsigned char * raw; unsigned char * raw1; char Mode[16] = ""; struct TDetector_t * pDET = &DET[emph][rcvr_nr]; // Decode RAW-stream raw_len = raw_data->Length; if (raw_len < 80) return; mydelete(raw_data, raw_len - 6, 7); // Does this remove trailing flag raw_len = raw_data->Length; nrzi_data = get_NRZI_data(raw_data, last_nrzi_bit); if (nrzi_data == NULL) return; // data = newString(); data = get_pkt_data(nrzi_data); len = data->Length; if (len < pkt_raw_min_len) { freeString(nrzi_data); freeString(data); return; } crc1 = get_fcs(data->Data, len - 2); crc2 = (data->Data[len - 1] << 8) | data->Data[len - 2]; // MEM recovery arq_mem = FALSE; if (raw_len > 2970) freeString(nrzi_data); else { Add(&pDET->mem_ARQ_buf[snd_ch], nrzi_data); if (pDET->mem_ARQ_buf[snd_ch].Count > MEMRecovery[snd_ch]) Delete(&pDET->mem_ARQ_buf[snd_ch], 0); if (crc1 != crc2) { freeString(data); data = get_pkt_data(memory_ARQ(&pDET->mem_ARQ_buf[snd_ch], nrzi_data)); crc1 = get_fcs(data->Data, len - 2); arq_mem = TRUE; } } if (crc1 == crc2) { if (arq_mem) { Debugprintf("Good CRC after Memory ARQ correction %x Len %d chan %d rcvr %d emph %d", crc1, len, snd_ch, rcvr_nr, emph); stat_r_mem++; pDET->emph_decoded = 2; //MEM pDET->rx_decoded = decodedMEM; } else { Debugprintf("Good CRC %x Len %d chan %d rcvr %d emph %d", crc1, len, snd_ch, rcvr_nr, emph); pDET->rx_decoded = decodedNormal; pDET->emph_decoded = 4; //Normal } if (detect_list[snd_ch].Count > 0 && my_indexof(&detect_list[snd_ch], data) >= 0) { // Already have a copy of this frame freeString(data); Debugprintf("Discarding copy rcvr %d emph %d", rcvr_nr, emph); return; } string * xx = newString(); memset(xx->Data, 0, 16); sprintf(Mode, "AX25 %d", centreFreq[snd_ch]); Add(&detect_list_c[snd_ch], xx); Add(&detect_list[snd_ch], data); if (arq_mem) stringAdd(xx, "MEM", 3); else stringAdd(xx, "", 0); sprintf(Mode, "AX25 %d", centreFreq[snd_ch]); stringAdd(xx, Mode, strlen(Mode)); return; } // Single bit recovery freeString(data); // finished with original if (recovery[snd_ch] == 0 || raw_len > 2970) return; raw = raw_data->Data; raw1 = raw_data1->Data; for (i = 0; i < raw_len; i++) { if (raw[i] != raw1[i]) { //change bit raw[i] ^= 1; // get new data data = get_pkt_data2(raw_data, last_nrzi_bit); //restore bit raw[i] ^= 1; len = data->Length; if (len > pkt_raw_min_len) { crc1 = get_fcs(data->Data, len - 2); crc2 = (data->Data[len - 1] << 8) | data->Data[len - 2]; if (crc1 == crc2) { Debugprintf("Good CRC after single bit correction %x Len %d chan %d rcvr %d emph %d", crc1, len, snd_ch, rcvr_nr, emph); if (detect_list[snd_ch].Count > 0 && my_indexof(&detect_list[snd_ch], data) >=- 0) { // Already have a copy of this frame Debugprintf("Discarding copy rcvr %d, emph %d", rcvr_nr, emph); freeString(data); return; } string * xx = newString(); memset(xx->Data, 0, 16); Add(&detect_list_c[snd_ch], xx); Add(&detect_list[snd_ch], data); stringAdd(xx, "SINGLE", 3); pDET->rx_decoded = decodedSingle; pDET->emph_decoded = 1; //SINGLE return; } } freeString(data); // finished with original } } } int lastcrc = 0; void make_rx_frame_PSK(int snd_ch, int rcvr_nr, int emph, string * data) { word len, crc1, crc2; len = data->Length; if (len < pkt_raw_min_len) return; crc1 = get_fcs(data->Data, len - 2); crc2 = (data->Data[len - 1] << 8) | data->Data[len - 2]; if (crc1 == crc2) { struct TDetector_t * pDET = &DET[emph][rcvr_nr]; Debugprintf("Good CRC %x Len %d chan %d rcvr %d emph %d", crc1, len, snd_ch, rcvr_nr, emph); pDET->rx_decoded = decodedNormal; pDET->emph_decoded = 4; //Normal if (detect_list[snd_ch].Count > 0 && my_indexof(&detect_list[snd_ch], data) >= 0) { // Already have a copy of this frame Debugprintf("Discarding copy rcvr %d emph %d", rcvr_nr, emph); return; } string * xx = newString(); memset(xx->Data, 0, 16); Add(&detect_list_c[snd_ch], xx); xx = duplicateString(data); Add(&detect_list[snd_ch], xx); } } /* function memory_ARQ_FEC(buf: TStringList; data: string): string; var len,i,k: integer; s,temp: string; new_blk,temp_blk: TStringList; n,err: byte; done: boolean; { s = ''; if data='' then { result = s; exit; } new_blk = TStringList.Create; temp_blk = TStringList.Create; temp = data; len = length(data); // Split new data; repeat n = ord(temp[1]) and $7F; err = ord(temp[1]) and $80; if err=0 then new_blk.Add(copy(temp,2,n)) else new_blk.Add(''); delete(temp,1,n+1); until temp=''; // Search blocks if (buf.Count>0) and (new_blk.Count>0) then { i = 0; repeat // If length is the same if length(buf.Strings[i])=len then { temp = buf.Strings[i]; // If last 4 bytes is the same if copy(temp,len-3,4)=copy(data,len-3,4) then { temp_blk.Clear; repeat n = ord(temp[1]) and $7F; err = ord(temp[1]) and $80; if err=0 then temp_blk.Add(copy(temp,2,n)) else temp_blk.Add(''); delete(temp,1,n+1); until temp=''; // Add new parts if new_blk.Count=temp_blk.Count then { done = TRUE; for k = 0 to new_blk.Count-1 do { if (new_blk.Strings[k]='') and (temp_blk.Strings[k]<>'') then new_blk.Strings[k] = temp_blk.Strings[k]; // Check if no empty data if new_blk.Strings[k]='' then done = FALSE; } } } } inc(i); until (i=buf.Count) or done; if done then for k = 0 to new_blk.Count-1 do s = s+new_blk.Strings[k]; } result = s; new_blk.Free; temp_blk.Free } procedure add_to_ARQ_FEC(buf: TStringList; data: string); { if buf.Count=50 then buf.Delete(0); buf.Add(data); } */ void make_rx_frame_FEC(int snd_ch, int rcvr_nr, string * data, string * fec_data, word nErr) { } /*var len,crc1,crc2: word; s: string; i,k,n: word; { len = length(data); if len<17 then exit; crc1 = get_fcs(data,len-2); crc2 = (ord(data[len]) shl 8) or ord(data[len-1]); if crc1=crc2 then { if detect_list[snd_ch].Count>0 then { //if detect_list[snd_ch].IndexOf(data)<0 then if my_indexof(detect_list[snd_ch],data)<0 then { detect_list[snd_ch].Add(data); detect_list_c[snd_ch].Add('Err: '+inttostr(nErr)); } end else { detect_list[snd_ch].Add(data); detect_list_c[snd_ch].Add('Err: '+inttostr(nErr)); } add_to_ARQ_FEC(DET[0,rcvr_nr].mem_ARQ_F_buf[snd_ch],fec_data); } if crc1<>crc2 then { data = memory_ARQ_FEC(DET[0,rcvr_nr].mem_ARQ_F_buf[snd_ch],fec_data); add_to_ARQ_FEC(DET[0,rcvr_nr].mem_ARQ_F_buf[snd_ch],fec_data); if data<>'' then { len = length(data); crc1 = get_fcs(data,len-2); crc2 = (ord(data[len]) shl 8) or ord(data[len-1]); if crc1=crc2 then { if detect_list[snd_ch].Count>0 then { //if detect_list[snd_ch].IndexOf(data)<0 then if my_indexof(detect_list[snd_ch],data)<0 then { detect_list[snd_ch].Add(data); detect_list_c[snd_ch].Add('MEM Err: '+inttostr(nErr)); } end else { detect_list[snd_ch].Add(data); detect_list_c[snd_ch].Add('MEM Err: '+inttostr(nErr)); } } } } } */ //////////////////////////// PLL-Peak-detector //////////////////////////// void Mux3(int snd_ch, int rcvr_nr, int emph, float * src1, float * core, float *dest, float * prevI, float * prevQ, int tap, int buf_size) { float pi2 = 2 * pi; int i; float x; float acc1, acc2, acc3, mag; int tap4; int tap_cnt; unsigned int ii, kk; float Preemphasis6, Preemphasis12, MUX3_osc, AGC; float AFC_IZ1, AFC_QZ1, AFC_IZ2, AFC_QZ2; // looks like this is an LPF // Get local copy of this detectors variables struct TDetector_t * pDET = &DET[emph][rcvr_nr]; Preemphasis6 = pDET->Preemphasis6[snd_ch]; Preemphasis12 = pDET->Preemphasis12[snd_ch]; MUX3_osc = pDET->MUX3_osc[snd_ch]; AGC = pDET->AGC[snd_ch]; AFC_IZ2 = pDET->AFC_IZ2[snd_ch]; AFC_QZ2 = pDET->AFC_QZ2[snd_ch]; AFC_QZ1 = pDET->AFC_QZ1[snd_ch]; AFC_IZ1 = pDET->AFC_IZ1[snd_ch]; // tap4 = tap * 4; x = active_rx_freq[snd_ch] * pi2 / RX_Samplerate; fmove(&prevI[buf_size], &prevI[0], tap4); fmove(&prevQ[buf_size], &prevQ[0], tap4); tap_cnt = tap; if (prevI[128] != prevI[128]) prevI[128] = 0; for (i = 0; i < buf_size; i++) { // Pre-emphasis 6dB if (emph > 0) { acc1 = Preemphasis6 - src1[i]; Preemphasis6 = src1[i]; src1[i] = acc1; } // Pre-emphasis 12dB if (emph > 1) { acc1 = Preemphasis12 - src1[i]; Preemphasis12 = src1[i]; src1[i] = acc1; } // MUX3_osc = MUX3_osc + x; if (MUX3_osc > pi2) MUX3_osc = MUX3_osc - pi2; if (src1[i] != src1[i]) src1[i] = 0; if (prevI[128] != prevI[128]) prevI[128] = 0; prevI[tap_cnt] = src1[i] * sinf(MUX3_osc); prevQ[tap_cnt] = src1[i] * cosf(MUX3_osc); if (prevI[128] != prevI[128]) prevI[tap_cnt] = src1[i] * sinf(MUX3_osc); if (prevI[128] != prevI[128]) prevI[128] = 0; /* mag = sqrtf(prevI[tap_cnt] * prevI[tap_cnt] + prevQ[tap_cnt] * prevQ[tap_cnt]); DET[emph][rcvr_nr].AGC1[snd_ch] = 0.5*DET[emph][rcvr_nr].AGC1[snd_ch] + 0.5*mag; AGC = 0.5*AGC + 0.5*DET[emph][rcvr_nr].AGC1[snd_ch]; if (AGC > 1) begin prevI[tap_cnt] = prevI[tap_cnt] / AGC; prevQ[tap_cnt] = prevQ[tap_cnt] / AGC; end */ // Fast AGC mag = sqrtf(prevI[tap_cnt] * prevI[tap_cnt] + prevQ[tap_cnt] * prevQ[tap_cnt]); AGC = 0.5 * AGC + 0.5 *mag; if (AGC > 1) { prevI[tap_cnt] = prevI[tap_cnt] / AGC; prevQ[tap_cnt] = prevQ[tap_cnt] / AGC; } ii = i << 2; kk = tap << 2; // C version of delphi asm code below { float accum = 0.0f; float fp1; int ebx; float * edi; edi = &prevI[i]; ebx = 0; accum = 0.0f; fsk_k1: // FLD pushes operand onto stack, so old value goes to fp1 fp1 = accum; accum = edi[ebx]; if (accum != accum) accum = 0; accum *= core[ebx]; if (accum != accum) accum = 0; accum += fp1; if (accum != accum) accum = 0; ebx++; if (ebx != tap) goto fsk_k1; acc1 = accum; if (acc1 != acc1) acc1 = 0; edi = &prevQ[i]; ebx = 0; accum = 0.0f; fsk_k2: fp1 = accum; accum = edi[ebx]; accum *= core[ebx]; accum += fp1; ebx++; if (ebx != tap) goto fsk_k2; acc2 = accum; } if (acc1 != acc1) acc1 = 0; tap_cnt++; /// PLL-Detector /// dest[i] = (acc1 - AFC_IZ2)*AFC_QZ1 - (acc2 - AFC_QZ2)*AFC_IZ1; // Check for NAN if (dest[i] != dest[i]) dest[i] = 0.0f; AFC_IZ2 = AFC_IZ1; AFC_QZ2 = AFC_QZ1; AFC_IZ1 = acc1; AFC_QZ1 = acc2; } pDET->Preemphasis6[snd_ch] = Preemphasis6; pDET->Preemphasis12[snd_ch] = Preemphasis12; pDET->MUX3_osc[snd_ch] = MUX3_osc; pDET->AGC[snd_ch] = AGC; pDET->AFC_IZ2[snd_ch] = AFC_IZ2; pDET->AFC_QZ2[snd_ch] = AFC_QZ2; pDET->AFC_QZ1[snd_ch] = AFC_QZ1; pDET->AFC_IZ1[snd_ch] = AFC_IZ1; } void Mux3_PSK(int snd_ch, int rcvr_nr, int emph, float * src1, float * core, float *destI, float *destQ, float * prevI, float * prevQ, int tap, int buf_size) { float pi2 = 2 * pi; int i; float x; float acc1, acc2, mag; int tap4; int prev_cnt, tap_cnt; float Preemphasis6, Preemphasis12, MUX3_osc; // looks like this is an LPF // Get local copy of this detectors variables struct TDetector_t * pDET = &DET[emph][rcvr_nr]; Preemphasis6 = pDET->Preemphasis6[snd_ch]; Preemphasis12 = pDET->Preemphasis12[snd_ch]; MUX3_osc = pDET->MUX3_osc[snd_ch]; tap4 = tap * 4; x = active_rx_freq[snd_ch] * pi2 / RX_Samplerate; fmove(&prevI[buf_size], &prevI[0], tap4); fmove(&prevQ[buf_size], &prevQ[0], tap4); tap_cnt = tap; if (prevI[128] != prevI[128]) prevI[128] = 0; for (i = 0; i < buf_size; i++) { // Pre-emphasis 6dB if (emph > 0) { acc1 = Preemphasis6 - src1[i]; Preemphasis6 = src1[i]; src1[i] = acc1; } // Pre-emphasis 12dB if (emph > 1) { acc1 = Preemphasis12 - src1[i]; Preemphasis12 = src1[i]; src1[i] = acc1; } MUX3_osc = MUX3_osc + x; if (MUX3_osc > pi2) MUX3_osc = MUX3_osc - pi2; prevI[tap_cnt] = src1[i] * sinf(MUX3_osc); prevQ[tap_cnt] = src1[i] * cosf(MUX3_osc); // C version of delphi asm code { float accum = 0.0f; float fp1; int ebx; float * edi; edi = &prevI[i]; ebx = 0; accum = 0.0f; fsk_k1: // FLD pushes operand onto stack, so old value goes to fp1 fp1 = accum; accum = edi[ebx]; accum *= core[ebx]; accum += fp1; ebx++; if (ebx != tap) goto fsk_k1; acc1 = accum; edi = &prevQ[i]; ebx = 0; accum = 0.0f; fsk_k2: fp1 = accum; accum = edi[ebx]; accum *= core[ebx]; accum += fp1; ebx++; if (ebx != tap) goto fsk_k2; acc2 = accum; } if (acc1 != acc1) acc1 = 0; tap_cnt++; destI[i] = acc1; destQ[i] = acc2; } pDET->Preemphasis6[snd_ch] = Preemphasis6; pDET->Preemphasis12[snd_ch] = Preemphasis12; pDET->MUX3_osc[snd_ch] = MUX3_osc; } int stats[2] = { 0 }; #define dcd_corr 0.11111f void decode_stream_MPSK(int snd_ch, int rcvr_nr, float * src, int buf_size, int last) { #ifndef XXXX // Until ASM is converted return; } #else float pi2 = 2 * pi; #define NR_FEC_CH 3 float agc_fast = 0.01f; float agc_fast1 = 1 - agc_fast; float agc_slow = agc_fast / 4; float agc_slow1 = 1 - agc_slow; word dcnt, dsize; word i, k, j, j1, j2, j3; single x, x1; single amp, acc1, acc2; single sumI, sumQ, sumIQ, muxI, muxQ; word tap_cnt, tap_cnt1; single afc_lim; word i_tap, tap; single AFC, k1, k2, freq; single maxval, div_bit_afc, baudrate; word max_cnt; single AmpI, AmpQ, angle, muxI1, muxQ1, muxI2, muxQ2, sumIQ1, sumIQ2; single AFC_acc1, AFC_acc2; single BIT_acc1, BIT_acc2; integer AFC_newpkpos; // single threshol; single tr; Byte fec_ch, bit; longword ii, kk; single * core, *prevI, *prevQ; // unsigned long long bit64 = 0; boolean hdr_ok; Byte fec_code; string fec_data_blk; string line1; Byte line[512]; int linelen = 0; integer nErr; word crc1, crc2, size; Byte hdr_byte[15] = ""; tr = dcd_threshold * dcd_corr; if (last) { if (dcd_hdr_cnt[snd_ch] == 0) dcd_on_hdr[snd_ch] = 0; dcd_bit_cnt[snd_ch] = 0; } baudrate = 400; div_bit_afc = 1.0f / roundf(BIT_AFC*(RX_Samplerate / 11025)); x1 = baudrate / RX_Samplerate; max_cnt = roundf(RX_Samplerate / baudrate); // afc_lim = rx_baudrate[snd_ch] * 0.1f; dsize = buf_size / n_INTR[snd_ch]; tap = LPF_tap[snd_ch]; i_tap = INTR_tap[snd_ch]; freq = active_rx_freq[snd_ch]; for (fec_ch = 0; fec_ch <= NR_FEC_CH; fec_ch++) { struct TMChannel_t * pMChan = &DET[0][rcvr_nr].MChannel[snd_ch][fec_ch]; fmove(&pMChan->prev_dLPFI_buf[buf_size], &pMChan->prev_dLPFI_buf[0], i_tap * 4); fmove(&pMChan->prev_dLPFQ_buf[buf_size], &pMChan->prev_dLPFQ_buf[0], i_tap * 4); fmove(&pMChan->prev_LPF1I_buf[dsize], &pMChan->prev_LPF1I_buf[0], tap * 4); fmove(&pMChan->prev_LPF1Q_buf[dsize], &pMChan->prev_LPF1Q_buf[0], tap * 4); fmove(&pMChan->prev_AFCI_buf[dsize], &pMChan->prev_AFCI_buf[0], tap * 4); fmove(&pMChan->prev_AFCQ_buf[dsize], &pMChan->prev_AFCQ_buf[0], tap * 4); } tap_cnt = i_tap; tap_cnt1 = tap; dcnt = 0; k = 0; for (i = 0; i < buf_size; i++) { for (fec_ch = 0; fec_ch <= NR_FEC_CH; fec_ch++) { struct TDetector_t * pDET = &DET[0][rcvr_nr]; x = (freq + pDET->AFC_dF[snd_ch] + ch_offset[fec_ch])*pi2 / RX_Samplerate; struct TMChannel_t * pMChan = &pDET->MChannel[snd_ch][fec_ch]; { pMChan->MUX_osc = pMChan->MUX_osc + x; if (pMChan->MUX_osc > pi2) pMChan->MUX_osc = pMChan->MUX_osc - pi2; pMChan->prev_dLPFI_buf[tap_cnt] = src[i] * sinf(pMChan->MUX_osc); pMChan->prev_dLPFQ_buf[tap_cnt] = src[i] * cosf(pMChan->MUX_osc); prevI = pMChan->prev_dLPFI_buf; prevQ = pMChan->prev_dLPFQ_buf; core = INTR_core[snd_ch]; // Decimation filter ii = i << 2; kk = i_tap << 2; _asm { push eax; push ebx; push edi; push esi; mov edi, prevI; mov esi, core; add edi, ii; mov eax, kk; xor ebx, ebx; fldz; lk1: fld dword ptr[edi + ebx]; fmul dword ptr[esi + ebx]; fadd; add ebx, 4; cmp ebx, eax; jne lk1; fstp dword ptr acc1; wait; mov edi, prevQ; add edi, ii; xor ebx, ebx; fldz; lk2: fld dword ptr[edi + ebx]; fmul dword ptr[esi + ebx]; fadd; add ebx, 4; cmp ebx, eax; jne lk2; fstp dword ptr acc2; wait; pop esi; pop edi; pop ebx; pop eax; } } if (fec_ch == NR_FEC_CH) tap_cnt++; // Decimation if (dcnt == 0) { { pMChan->prev_LPF1I_buf[tap_cnt1] = acc1; pMChan->prev_LPF1Q_buf[tap_cnt1] = acc2; pMChan->prev_AFCI_buf[tap_cnt1] = acc1; pMChan->prev_AFCQ_buf[tap_cnt1] = acc2; // Bit-filter prevI = pMChan->prev_LPF1I_buf; prevQ = pMChan->prev_LPF1Q_buf; core = LPF_core[snd_ch]; ii = k << 2; kk = tap << 2; __asm { push eax; push ebx; push edi; push esi; mov edi, prevI; mov esi, core; add edi, ii; mov eax, kk; xor ebx, ebx; fldz; xk1: fld dword ptr[edi + ebx]; fmul dword ptr[esi + ebx]; fadd; add ebx, 4; cmp ebx, eax; jne xk1; fstp dword ptr BIT_acc1; wait; mov edi, prevQ; add edi, ii; xor ebx, ebx; fldz; xk2: fld dword ptr[edi + ebx]; fmul dword ptr[esi + ebx]; fadd; add ebx, 4; cmp ebx, eax; jne xk2; fstp dword ptr BIT_acc2; wait; pop esi; pop edi; pop ebx; pop eax; } // AFC-filter prevI = pMChan->prev_AFCI_buf; prevQ = pMChan->prev_AFCQ_buf; core = AFC_core[snd_ch]; ii = k << 2; kk = tap << 2; _asm { push eax; push ebx; push edi; push esi; mov edi, prevI; mov esi, core; add edi, ii; mov eax, kk; xor ebx, ebx; fldz; xxk1: fld dword ptr[edi + ebx]; fmul dword ptr[esi + ebx]; fadd; add ebx, 4; cmp ebx, eax; jne xxk1; fstp dword ptr AFC_acc1; wait; mov edi, prevQ; add edi, ii; xor ebx, ebx; fldz; xxk2: fld dword ptr[edi + ebx]; fmul dword ptr[esi + ebx]; fadd; add ebx, 4; cmp ebx, eax; jne xxk2; fstp dword ptr AFC_acc2; wait; pop esi; pop edi; pop ebx; pop eax; } } // AGC amp = sqrtf(BIT_acc1*BIT_acc1 + BIT_acc2 * BIT_acc2); if (amp > pDET->PSK_AGC[snd_ch]) pDET->PSK_AGC[snd_ch] = pDET->PSK_AGC[snd_ch] * agc_fast1 + amp*agc_fast; else pDET->PSK_AGC[snd_ch] = pDET->PSK_AGC[snd_ch] * agc_slow1 + amp*agc_slow; if (pDET->PSK_AGC[snd_ch] > 1) { BIT_acc1 = BIT_acc1 / pDET->PSK_AGC[snd_ch]; BIT_acc2 = BIT_acc2 / pDET->PSK_AGC[snd_ch]; AFC_acc1 = AFC_acc1 / pDET->PSK_AGC[snd_ch]; AFC_acc2 = AFC_acc2 / pDET->PSK_AGC[snd_ch]; amp = amp / pDET->PSK_AGC[snd_ch]; } // AFC Correction sumIQ = (AFC_acc1 - pMChan->AFC_IZ2)*pMChan->AFC_QZ1 - (AFC_acc2 - pMChan->AFC_QZ2)*pMChan->AFC_IZ1; pMChan->AFC_IZ2 = pMChan->AFC_IZ1; pMChan->AFC_QZ2 = pMChan->AFC_QZ1; pMChan->AFC_IZ1 = AFC_acc1; pMChan->AFC_QZ1 = AFC_acc2; pDET->AFC_dF[snd_ch] = pDET->AFC_dF[snd_ch] - sumIQ * 0.07f; // AFC_LPF=1 if (pDET->AFC_dF[snd_ch] > afc_lim) pDET->AFC_dF[snd_ch] = afc_lim; if (pDET->AFC_dF[snd_ch] < -afc_lim) pDET->AFC_dF[snd_ch] = -afc_lim; pMChan->AFC_bit_buf1I[pDET->AFC_cnt[snd_ch]] = BIT_acc1; pMChan->AFC_bit_buf1Q[pDET->AFC_cnt[snd_ch]] = BIT_acc2; pMChan->AFC_bit_buf2[pDET->AFC_cnt[snd_ch]] = amp; if (fec_ch == NR_FEC_CH) { pDET->AFC_cnt[snd_ch]++; pDET->AFC_bit_osc[snd_ch] = pDET->AFC_bit_osc[snd_ch] + x1; if (pDET->AFC_bit_osc[snd_ch] >= 1) { // Find the maximum in the synchronization buffer for (j = 0; j <= NR_FEC_CH; j++) { struct TMChannel_t * pMChan = &pDET->MChannel[snd_ch][j]; maxval = 0; for (j1 = 0; j1 < pDET->AFC_cnt[snd_ch]; j1++) { amp = pMChan->AFC_bit_buf2[j1]; pDET->AFC_bit_buf[snd_ch][j1] = pDET->AFC_bit_buf[snd_ch][j1] * 0.95 + amp*0.05; if (pDET->AFC_bit_buf[snd_ch][j1] > maxval) { { AFC_newpkpos = j1; maxval = pDET->AFC_bit_buf[snd_ch][j1]; } } k1 = 1.0f *AFC_newpkpos / (pDET->AFC_cnt[snd_ch] - 1); k2 = pila(k1) - 1; //AFC = div_bit_afc*k2; AFC = div_bit_afc * k2*0.25; //for 4 carriers if (k1 > 0.5) pDET->AFC_bit_osc[snd_ch] = pDET->AFC_bit_osc[snd_ch] + AFC; else pDET->AFC_bit_osc[snd_ch] = pDET->AFC_bit_osc[snd_ch] - AFC; //DCD feature if (last) { DCD_LastPkPos[snd_ch] = DCD_LastPkPos[snd_ch] * 0.96f + AFC_newpkpos * 0.04f; DCD_LastPerc[snd_ch] = DCD_LastPerc[snd_ch] * 0.96f + abs(AFC_newpkpos - DCD_LastPkPos[snd_ch])*0.04f; if (DCD_LastPerc[snd_ch] >= tr || DCD_LastPerc[snd_ch] < 0.00001f) dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] + 1; else dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] - 1; } } // Bit-detector AmpI = pMChan->AFC_bit_buf1I[AFC_newpkpos]; AmpQ = pMChan->AFC_bit_buf1Q[AFC_newpkpos]; muxI1 = AmpI * pMChan->AFC_IIZ1; muxI2 = AmpQ * pMChan->AFC_IIZ1; muxQ1 = AmpQ * pMChan->AFC_QQZ1; muxQ2 = AmpI * pMChan->AFC_QQZ1; sumIQ1 = muxI1 + muxQ1; sumIQ2 = muxI2 - muxQ2; angle = atan2f(sumIQ2, sumIQ1); pMChan->AFC_IIZ1 = AmpI; pMChan->AFC_QQZ1 = AmpQ; // Phase corrector if (fabsf(angle) < PI5) pMChan->AngleCorr = pMChan->AngleCorr * 0.9f - angle * 0.1f; else { if (angle > 0) pMChan->AngleCorr = pMChan->AngleCorr * 0.9f + (pi - angle)*0.1f; else pMChan->AngleCorr = pMChan->AngleCorr * 0.9f + (-pi - angle)*0.1f; } angle = angle + pMChan->AngleCorr; if (fabsf(angle) < PI5) bit = RX_BIT1; else bit = RX_BIT0; // DCD on flag if (last) { if (dcd_hdr_cnt[snd_ch] > 0) dcd_hdr_cnt[snd_ch]--; DCD_header[snd_ch] = (DCD_header[snd_ch] >> 1) | (bit << 24); if ((DCD_header[snd_ch] & 0xFFFF0000) == 0x7E7E0000 || (DCD_header[snd_ch] & 0xFFFFFF00) == 0x7E000000 || (DCD_header[snd_ch] & 0xFFFFFF00) == 0x00000000) { dcd_hdr_cnt[snd_ch] = 48; dcd_on_hdr[snd_ch] = TRUE; } } // header stream bit64 = bit; bit64 <<= 56; pDET->FEC_header1[snd_ch][1] = (pDET->FEC_header1[snd_ch][1] >> 1) | (pDET->FEC_header1[snd_ch][0] << 63); pDET->FEC_header1[snd_ch][0] = (pDET->FEC_header1[snd_ch][0] >> 1) | bit64; // copy body if (pDET->frame_status[snd_ch] == FRAME_LOAD) { pDET->bit_stream[snd_ch] = (pDET->bit_stream[snd_ch] >> 1) + bit; pDET->bit_cnt[snd_ch]++; if (pDET->bit_cnt[snd_ch] == 8) { pDET->bit_cnt[snd_ch] = 0; pDET->FEC_len_cnt[snd_ch]++; stringAdd(&pDET->FEC_rx_data[snd_ch], &pDET->bit_stream[snd_ch], 1); if (pDET->FEC_len_cnt[snd_ch] == pDET->FEC_len[snd_ch]) { // descrambler scrambler(pDET->FEC_rx_data[snd_ch].Data, pDET->FEC_rx_data[snd_ch].Length); // deinterleave pDET->FEC_blk_int[snd_ch] = ((pDET->FEC_len[snd_ch] - 1) / 16) + 1; linelen = pDET->FEC_rx_data[snd_ch].Length; memcpy(line, pDET->FEC_rx_data[snd_ch].Data, linelen); j3 = 1; for (j1 = 0; j1 < 16; j1++) { for (j2 = 0; j2 < pDET->FEC_blk_int[snd_ch]; j2++) { if ((j2 * 16 + j1) <= pDET->FEC_len[snd_ch] && j3 <= pDET->FEC_len[snd_ch]) { pDET->FEC_rx_data[snd_ch].Data[j2 * 16 + j1] = line[j3]; j3++; } } } // RS-decode /* line = pDET->FEC_rx_data[snd_ch]; pDET->FEC_rx_data[snd_ch].Length = 0; do { line1 = copy(line, 1, 16); size = length(line1); FillChar(xEncoded, SizeOf(xEncoded), 0); FillChar(xDecoded, SizeOf(xDecoded), 0); move(line1[1], xEncoded[0], size); RS.InitBuffers; nErr = RS.DecodeRS(xEncoded, xDecoded); line1 = ''; for j1 = MaxErrors * 2 to size - 1 do line1 = line1 + chr(xDecoded[j1]); pDET->FEC_rx_data[snd_ch] = FEC_rx_data[snd_ch] + line1; if nErr >= 0 then FEC_err[snd_ch] = FEC_err[snd_ch] + nErr; // For MEM-ARQ fec_code = length(line1) and $7F; if nErr < 0 then fec_code = fec_code or $80; fec_data_blk = fec_data_blk + chr(fec_code) + line1; delete(line, 1, 16); } while(line.Count); */ make_rx_frame_FEC(snd_ch, rcvr_nr, &pDET->FEC_rx_data[snd_ch], &fec_data_blk, pDET->FEC_err[snd_ch]); pDET->FEC_rx_data[snd_ch].Length = 0; pDET->frame_status[snd_ch] = FRAME_WAIT; pDET->FEC_header1[snd_ch][0] = 0; pDET->FEC_header1[snd_ch][1] = 0; } } } hdr_ok = FALSE; // I think FEC_header1[0] and FEC_header1[1] form the 128 bit header // We look for a pair of flags, but allow a few bits to be wrong // as FEC may fix them if (pDET->frame_status[snd_ch] == FRAME_WAIT) { j1 = (pDET->FEC_header1[snd_ch][1] >> 16) ^ 0x7E7E; /*_asm { push ax; push bx; push cx; mov ax, 15; mov bx, j1; zloop: mov cx, bx; and cx, 1; cmp cx, 1; jne is_zero; inc ah; // count damaged bits is_zero: shr bx, 1; dec al; jnz zloop; cmp ah, 5; // greater than 4 bits jnb greater; mov hdr_ok, TRUE; greater: pop cx; pop bx; pop ax; } */ } //if (FEC_header1[snd_ch][1] shr 24 and $FF=$7E) and (frame_status[snd_ch]=FRAME_WAIT) then if (hdr_ok) { // Have up to 4 bits wrong in 7E7E pattern // Extract header, check crc then try RS hdr_ok = FALSE; // if ((pDET->FEC_header1[snd_ch][1] & 0xffff0000) == 0x7E7E0000) // { hdr_byte[13] = (pDET->FEC_header1[snd_ch][1] >> 24) & 0xFF; hdr_byte[14] = (pDET->FEC_header1[snd_ch][1] >> 16) & 0xFF; if (hdr_byte[13] == 0x7E && hdr_byte[14] == 0x7E) { hdr_byte[1] = (pDET->FEC_header1[snd_ch][0] >> 56) & 0xFF; hdr_byte[2] = (pDET->FEC_header1[snd_ch][0] >> 48) & 0xFF; hdr_byte[3] = (pDET->FEC_header1[snd_ch][0] >> 40) & 0xFF; hdr_byte[4] = (pDET->FEC_header1[snd_ch][0] >> 32) & 0xFF; hdr_byte[5] = (pDET->FEC_header1[snd_ch][0] >> 24) & 0xFF; hdr_byte[6] = (pDET->FEC_header1[snd_ch][0] >> 16) & 0xFF; hdr_byte[7] = (pDET->FEC_header1[snd_ch][0] >> 8) & 0xFF; hdr_byte[8] = pDET->FEC_header1[snd_ch][0] & 0xFF; hdr_byte[9] = (pDET->FEC_header1[snd_ch][1] >> 56) & 0xFF; hdr_byte[10] = (pDET->FEC_header1[snd_ch][1] >> 48) & 0xFF; hdr_byte[11] = (pDET->FEC_header1[snd_ch][1] >> 40) & 0xFF; hdr_byte[12] = (pDET->FEC_header1[snd_ch][1] >> 32) & 0xFF; pDET->FEC_len[snd_ch] = hdr_byte[12] << 8 + hdr_byte[11]; line[0] = 0x7E; line[1] = 0x7E; line[2] = hdr_byte[12]; line[3] = hdr_byte[11]; crc1 = (hdr_byte[10] << 8) + hdr_byte[9]; crc2 = get_fcs(line, 4); if (crc1 == crc2) hdr_ok = TRUE; Debugprintf("Len %d CRC %x %x", pDET->FEC_len[snd_ch], crc1, crc2); } /* if (!hdr_ok) { linelen = 0; for (j1 = 14; j1 > 0; j1-) line[linelen++] = hdr_byte[j1); FillChar(xEncoded, SizeOf(xEncoded), 0); FillChar(xDecoded, SizeOf(xDecoded), 0); line = copy(&line, 7, 8) + copy(&line, 1, 6); move(&line[1], xEncoded[0], 14); RS.InitBuffers; nErr = RS.DecodeRS(xEncoded, xDecoded); if (nErr > -1) { line.Length = 0; for (j1 = 8; j1 < 13; j1++) stringAdd(&line, &xDecoded[j1], 1); if (line[1] == 0x7E && line[2] == 0x7E) { FEC_len[snd_ch] = ord(line[3]) shl 8 + ord(line[4]); crc1 = (line[5] << 8) + line[6]); line = copy(line, 1, 4); crc2 = get_fcs(line, 4); if (crc1 == crc2) hdr_ok = TRUE; } } } */ if (hdr_ok) { pDET->FEC_len[snd_ch] = pDET->FEC_len[snd_ch] & 1023; //limit of length if (pDET->FEC_len[snd_ch] > 0) { pDET->frame_status[snd_ch] = FRAME_LOAD; pDET->FEC_len_cnt[snd_ch] = 0; pDET->bit_cnt[snd_ch] = 0; pDET->FEC_err[snd_ch] = 0; pDET->FEC_rx_data[snd_ch].Length = 0; fec_data_blk.Length = 0; } } } } // Finalize if (pDET->AFC_cnt[snd_ch] <= max_cnt) for (j = pDET->AFC_cnt[snd_ch]; j <= max_cnt + 5; j++) pDET->AFC_bit_buf[snd_ch][j] = 0.95f*pDET->AFC_bit_buf[snd_ch][j]; pDET->AFC_cnt[snd_ch] = 0; pDET->AFC_bit_osc[snd_ch] = pDET->AFC_bit_osc[snd_ch] - 1; } } if (fec_ch == NR_FEC_CH) { tap_cnt1++; k++; } } } dcnt = (dcnt + 1) % n_INTR[snd_ch]; } } #endif void make_rx_frame_FX25(int snd_ch, int rcvr_nr, int emph, string * data) { struct TDetector_t * pDET = &DET[emph][rcvr_nr]; word len, crc1, crc2; len = data->Length; if (len < pkt_raw_min_len) { free(data); return; } crc1 = get_fcs(data->Data, len - 2); crc2 = (data->Data[len - 1] << 8) | data->Data[len - 2]; if (crc1 != crc2) { freeString(data); return; } Debugprintf("FEC Good CRC %x Len %d chan %d rcvr %d emph %d", crc1, len, snd_ch, rcvr_nr, emph); pDET->rx_decoded = decodedFEC; if (detect_list[snd_ch].Count > 0) { //if detect_list[snd_ch].IndexOf(data)<0 then if (my_indexof(&detect_list[snd_ch], data) < 0) { string * xx = newString(); xx->Length = sprintf(xx->Data, "FX25 %d", centreFreq[snd_ch]); Add(&detect_list_c[snd_ch], xx); Add(&detect_list[snd_ch], data); stringAdd(xx, "", 0); } else { // Should check if previous decode was Single or MEM and if so replace Debugprintf("Discarding copy rcvr %d", rcvr_nr); freeString(data); } } else { string * xx = newString(); xx->Length = sprintf(xx->Data, "FX25 %d", centreFreq[snd_ch]); Add(&detect_list_c[snd_ch], xx); Add(&detect_list[snd_ch], data); if (rcvr_nr == 0) pDET->emph_decoded = 3; //FX.25 } } string * decode_FX25_data(TFX25 fx25) { integer eras_pos = 0, i, j, len, rs_res; Byte a, k; Byte bit, byte_rx, bit_stuff_cnt, bit_cnt = 0, frame_status, bit_stream; string * data = newString(); int done; Byte rs_block[256]; int RSOK; bit_stream = 0; len = fx25.size - fx25.rs_size; frame_status = FRAME_WAIT; done = 0; // RS FEC memset(rs_block, 0, 255); memcpy(rs_block, fx25.data.Data, len); memcpy(&rs_block[255 - fx25.rs_size], &fx25.data.Data[len], fx25.rs_size); rs_res = fx25_decode_rs(rs_block, &eras_pos, 0, 0, fx25.rs_size); if (rs_res == -1) { Debugprintf("RS Correction Failed"); return data; } if (rs_res == 0) Debugprintf("RS No Errors"); else Debugprintf("RS %d Errors Corrected", rs_res); // need to do ax.25 decode of bit stream i = 0; while (i < len) { a = rs_block[i]; i++; for (k = 0; k < 8; k++) { bit = a << 7; a = a >> 1; bit_stream = (bit_stream >> 1) | bit; if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_LOAD) { frame_status = FRAME_WAIT; if (bit_cnt == 6 && data->Length) return data; } if (frame_status == FRAME_LOAD) { if (bit_stuff_cnt == 5) bit_stuff_cnt = 0; else { if (bit == RX_BIT1) bit_stuff_cnt++; else bit_stuff_cnt = 0; byte_rx = (byte_rx >> 1) | bit; bit_cnt++; } if (bit_cnt == 8) { stringAdd(data, &byte_rx, 1); bit_cnt = 0; } } if ((bit_stream && FRAME_FLAG == FRAME_FLAG) && frame_status == FRAME_WAIT) { frame_status = FRAME_LOAD; bit_cnt = 0; bit_stuff_cnt = 0; data->Length = 0; } } } return data; } int FX25_corr[4] = {1, 1, 1, 1}; #define tags_nr 11 #define tt 8 unsigned long long tags[tags_nr] = { 0xB74DB7DF8A532F3E, 0x26FF60A600CC8FDE, 0xC7DC0508F3D9B09E, 0x8F056EB4369660EE, 0x6E260B1AC5835FAE, 0xFF94DC634F1CFF4E, 0x1EB7B9CDBC09C00E, 0xDBF869BD2DBB1776, 0x3ADB0C13DEAE2836, 0xAB69DB6A543188D6, 0x4A4ABEC4A724B796 }; int sizes[tags_nr] = { 255, 144, 80, 48, 255, 160, 96, 64, 255, 192, 128 }; int rs_sizes[tags_nr] = { 16, 16, 16, 16, 32, 32, 32, 32, 64, 64, 64 }; /* unsigned char get_corr_arm(unsigned long long n) { unsigned char max_corr; unsigned char result = 255; int i = 0; while (i < tags_nr) { if (__builtin_popcountll(n ^ tags[i] <= tt)) return i; } return 255; } */ char errors; unsigned char get_corr(unsigned long long val) { unsigned long v; unsigned long long n; int i = 0; while (i < tags_nr) { n = val ^ tags[i]; v = n; v = v - ((v >> 1) & 0x55555555); // reuse input as temporary v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp errors = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count if (errors > tt) { i++; continue; } v = n >> 32; v = v - ((v >> 1) & 0x55555555); // reuse input as temporary v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp errors += ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count if (errors <= tt) return i; i++; } return 255; } void decode_stream_FSK(int last, int snd_ch, int rcvr_nr, int emph, float * src_buf, float * bit_buf, int buf_size, string * data) { int i, k, j, n; UCHAR bit; UCHAR raw_bit; UCHAR raw_bit1; UCHAR raw_bit2; float AFC, x, amp, k1, k2; float baudrate; float div_bit_afc; word max_cnt; float threshold; float tr; float Freq; Byte sample_cnt; float PkAmp, PkAmpMax = 0, MaxAmp, MinAmp, AverageAmp; int newpkpos; float bit_osc; Byte last_rx_bit, bit_stream, frame_status; TFX25 fx25; unsigned long long tag64; boolean rx_fx25_mode; // get saved values to local variables to speed up access struct TDetector_t * pDET = &DET[emph][rcvr_nr]; last_rx_bit = pDET->last_rx_bit[snd_ch]; sample_cnt = pDET->sample_cnt[snd_ch]; PkAmp = pDET->PkAmp[snd_ch]; PkAmpMax = pDET->PkAmpMax[snd_ch]; newpkpos = pDET->newpkpos[snd_ch]; bit_osc = pDET->bit_osc[snd_ch]; MaxAmp = pDET->MaxAmp[snd_ch]; MinAmp = pDET->MinAmp[snd_ch]; AverageAmp = pDET->AverageAmp[snd_ch]; bit_stream = pDET->bit_stream[snd_ch]; frame_status = pDET->frame_status[snd_ch]; fx25 = pDET->fx25[snd_ch]; if (fx25_mode[snd_ch] == FX25_MODE_NONE) { rx_fx25_mode = FALSE; fx25.status = FX25_TAG; } else rx_fx25_mode = TRUE; tr = dcd_threshold * dcd_corr; if (last) { // Update DCD status if (dcd_hdr_cnt[snd_ch] == 0) dcd_on_hdr[snd_ch] = 0; dcd_bit_cnt[snd_ch] = 0; } // src_buf is input samples processed in some way. // not sure what bit_buf is, but guess bits extracted from samples // but then why floats ?? baudrate = 300; div_bit_afc = 1.0f / roundf(BIT_AFC*(RX_Samplerate / 11025.0f)); x = baudrate / RX_Samplerate; // I guess max_cnt is samples per bit //was - why + 1 then round?? max_cnt = roundf(RX_Samplerate / baudrate) + 1; max_cnt = (RX_Samplerate / baudrate); for (i = 0; i < buf_size; i++) { // Seems to be accumulating squares of all samples in the input for one bit period bit_buf[sample_cnt] = 0.95*bit_buf[sample_cnt] + 0.05*src_buf[i] * src_buf[i]; // Check for NAN if (bit_buf[sample_cnt] != bit_buf[sample_cnt]) bit_buf[sample_cnt] = 0.0f; // Находим максимум в буфере синхронизации // Find the maximum in the synchronization buffer if (bit_buf[sample_cnt] > PkAmpMax) { PkAmp = src_buf[i]; PkAmpMax = bit_buf[sample_cnt]; newpkpos = sample_cnt; } sample_cnt++; bit_osc = bit_osc + x; // This seems to be how it does samples to bits if (bit_osc >= 0.99f) // Allow for rounding errors { if (sample_cnt <= max_cnt) for (k = sample_cnt; k <= max_cnt; k++) bit_buf[k] = 0.95f*bit_buf[k]; k1 = (1.0f * newpkpos) / (sample_cnt - 1); k2 = pila(k1) - 1; AFC = div_bit_afc * k2; if (k1 > 0.5f) bit_osc = bit_osc + AFC; else bit_osc = bit_osc - AFC; PkAmpMax = 0; sample_cnt = 0; // Not sure about this, but if bit_buf gets to NaN it stays there bit_osc = bit_osc - 1; //DCD feature if (last) { DCD_LastPkPos[snd_ch] = DCD_LastPkPos[snd_ch] * 0.96f + newpkpos * 0.04f; DCD_LastPerc[snd_ch] = DCD_LastPerc[snd_ch] * 0.96f + fabsf(newpkpos - DCD_LastPkPos[snd_ch])*0.04f; if (DCD_LastPerc[snd_ch] >= tr || DCD_LastPerc[snd_ch] < 0.00001f) dcd_bit_cnt[snd_ch]++; else dcd_bit_cnt[snd_ch]--; } amp = PkAmp; if (amp > 0) raw_bit1 = RX_BIT1; else raw_bit1 = RX_BIT0; // if (amp > 0) MaxAmp = MaxAmp * 0.9f + amp*0.1f; //0.9 else MinAmp = MinAmp * 0.9f + amp*0.1f; amp = amp - (MaxAmp + MinAmp)*0.5f; // Bit-detector AverageAmp = AverageAmp * 0.5f + amp*0.5f; threshold = 0.5f * AverageAmp; if (amp > threshold) raw_bit = RX_BIT1; else raw_bit = RX_BIT0; // 0.75 if (amp > 0.75*AverageAmp) raw_bit2 = RX_BIT1; else raw_bit2 = RX_BIT0; if (raw_bit != raw_bit2) raw_bit1 = raw_bit2; // look for il2p before nrzi if (il2p_mode[snd_ch]) { il2p_rec_bit(snd_ch, rcvr_nr, emph, raw_bit); if (il2p_mode[snd_ch] == IL2P_MODE_ONLY) // Dont try HDLC decode continue; } //NRZI if (raw_bit == last_rx_bit) bit = RX_BIT1; else bit = RX_BIT0; last_rx_bit = raw_bit; // bit_stream = (bit_stream >> 1) | bit; // DCD on flag if (last) { if (dcd_hdr_cnt[snd_ch] > 0) dcd_hdr_cnt[snd_ch]--; DCD_header[snd_ch] = (DCD_header[snd_ch] >> 1) | (bit << 24); if (((DCD_header[snd_ch] & 0xFFFF0000) == 0x7E7E0000) || ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x7E000000) || ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x00000000)) { dcd_hdr_cnt[snd_ch] = 48; dcd_on_hdr[snd_ch] = 1; } } // FX25 process if (rx_fx25_mode) { if (fx25.status == FX25_LOAD) { //if last then DCD_on_hdr[snd_ch]:=true; fx25.byte_rx = (fx25.byte_rx >> 1) | bit; fx25.bit_cnt++; if (fx25.bit_cnt == 8) { fx25.bit_cnt = 0; stringAdd(&fx25.data, &fx25.byte_rx, 1); fx25.size_cnt++; if (fx25.size == fx25.size_cnt) { fx25.status = FX25_TAG; make_rx_frame_FX25(snd_ch, rcvr_nr, emph, decode_FX25_data(fx25)); //if last and (DCD_hdr_cnt[snd_ch]=0) then DCD_on_hdr[snd_ch]:=false; } } } else { fx25.size = 0; fx25.tag = (fx25.tag >> 1); if (bit) fx25.tag |= 0x8000000000000000; tag64 = fx25.tag & 0XFFFFFFFFFFFFFFFE; // FX25 tag correlation if (FX25_corr[snd_ch]) { unsigned char res; res = get_corr(tag64); if (res < tags_nr) { Debugprintf("Got FEC Tag %d Errors %d", res, errors); fx25.size = sizes[res]; fx25.rs_size = rs_sizes[res]; } } else { if (tag64 == 0xB74DB7DF8A532F3E) { fx25.size = 255; fx25.rs_size = 16; } if (tag64 == 0x26FF60A600CC8FDE) { fx25.size = 144; fx25.rs_size = 16; } if (tag64 == 0xC7DC0508F3D9B09E) { fx25.size = 80; fx25.rs_size = 16; } if (tag64 == 0x8F056EB4369660EE) { fx25.size = 48; fx25.rs_size = 16; } if (tag64 == 0x6E260B1AC5835FAE) { fx25.size = 255; fx25.rs_size = 32; } if (tag64 == 0xFF94DC634F1CFF4E) { fx25.size = 160; fx25.rs_size = 32; } if (tag64 == 0x1EB7B9CDBC09C00E) { fx25.size = 96; fx25.rs_size = 32; } if (tag64 == 0xDBF869BD2DBB1776) { fx25.size = 64; fx25.rs_size = 32; } if (tag64 == 0x3ADB0C13DEAE2836) { fx25.size = 255; fx25.rs_size = 64; } if (tag64 == 0xAB69DB6A543188D6) { fx25.size = 192; fx25.rs_size = 64; } if (tag64 == 0x4A4ABEC4A724B796) { fx25.size = 128; fx25.rs_size = 64; } } if (fx25.size != 0) { fx25.status = FX25_LOAD; fx25.data.Length = 0; fx25.bit_cnt = 0; fx25.size_cnt = 0; centreFreq[snd_ch] = GuessCentreFreq(snd_ch); } } } // if (bit_stream == 0xFF || bit_stream == 0x7F || bit_stream == 0xFE) { // All have 7 or more 1 bits if (frame_status == FRAME_LOAD) { // Have started receiving frame // Debugprintf("Frame Abort len= %d bits", pDET->raw_bits[snd_ch].Length); frame_status = FRAME_WAIT; // Raw stream init pDET->raw_bits[snd_ch].Length = 0; pDET->raw_bits1[snd_ch].Length = 0; pDET->last_nrzi_bit[snd_ch] = raw_bit; // dcd_hdr_cnt[snd_ch] = 48; // dcd_on_hdr[snd_ch] = 1; if (last) chk_dcd1(snd_ch, buf_size); } continue; } if (((bit_stream & FRAME_FLAG) == FRAME_FLAG) && (frame_status == FRAME_LOAD)) { frame_status = FRAME_WAIT; if (pDET->raw_bits[snd_ch].Length == 7) // Another flag { // Raw stream init pDET->raw_bits[snd_ch].Length = 0; pDET->raw_bits1[snd_ch].Length = 0; pDET->last_nrzi_bit[snd_ch] = raw_bit; } if (pDET->raw_bits[snd_ch].Length > 7) { //b Debugprintf("Got Frame len = %d AFC %f", pDET->raw_bits[snd_ch].Length, AFC); centreFreq[snd_ch] = GuessCentreFreq(snd_ch); make_rx_frame(snd_ch, rcvr_nr, emph, pDET->last_nrzi_bit[snd_ch], &pDET->raw_bits[snd_ch], &pDET->raw_bits1[snd_ch]); } } if (frame_status == FRAME_LOAD) { //Raw stream if (pDET->raw_bits[snd_ch].Length < 36873) { if (raw_bit == RX_BIT1) stringAdd(&pDET->raw_bits[snd_ch], "1", 1); else stringAdd(&pDET->raw_bits[snd_ch], "0", 1); } if (pDET->raw_bits1[snd_ch].Length < 36873) { if (raw_bit1 == RX_BIT1) stringAdd(&pDET->raw_bits1[snd_ch], "1", 1); else stringAdd(&pDET->raw_bits1[snd_ch], "0", 1); } // } if (((bit_stream & FRAME_FLAG) == FRAME_FLAG) && (frame_status == FRAME_WAIT)) { frame_status = FRAME_LOAD; // Raw stream init pDET->raw_bits[snd_ch].Length = 0; pDET->raw_bits1[snd_ch].Length = 0; pDET->last_nrzi_bit[snd_ch] = raw_bit; // Debugprintf("New Frame"); } } } pDET->sample_cnt[snd_ch] = sample_cnt; pDET->PkAmp[snd_ch] = PkAmp; pDET->PkAmpMax[snd_ch] = PkAmpMax; pDET->newpkpos[snd_ch] = newpkpos; pDET->bit_osc[snd_ch] = bit_osc; pDET->MaxAmp[snd_ch] = MaxAmp; pDET->MinAmp[snd_ch] = MinAmp; pDET->AverageAmp[snd_ch] = AverageAmp; pDET->bit_stream[snd_ch] = bit_stream; pDET->frame_status[snd_ch] = frame_status; pDET->last_rx_bit[snd_ch] = last_rx_bit; pDET->fx25[snd_ch] = fx25; } void decode_stream_BPSK(int last, int snd_ch, int rcvr_nr, int emph, float * srcI, float * srcQ, float * bit_buf, int buf_size, string * data) { float agc_fast = 0.01f; float agc_fast1 = 1 - agc_fast; float agc_slow = agc_fast / 4; float agc_slow1 = 1 - agc_slow; int i, k, j, n; Byte dibit, bit; single afc, x, amp, k1, k2; single baudrate; single div_bit_afc; word max_cnt; single threshold; single tr; single KCorr, AngleCorr, angle, muxI1, muxQ1, muxI2, muxQ2, sumIQ1, sumIQ2; Byte newpkpos, sample_cnt; single PkAmpI, PkAmpQ, PkAmpMax, PSK_AGC; single PSK_IZ1, PSK_QZ1; single bit_osc; Byte bit_stuff_cnt, last_rx_bit, frame_status, bit_cnt, bit_stream, byte_rx; // get saved values to local variables to speed up access struct TDetector_t * pDET = &DET[emph][rcvr_nr]; // global -> local AngleCorr = pDET->AngleCorr[snd_ch]; bit_stuff_cnt = pDET->bit_stuff_cnt[snd_ch]; sample_cnt = pDET->sample_cnt[snd_ch]; PSK_AGC = pDET->PSK_AGC[snd_ch]; PkAmpI = pDET->PkAmpI[snd_ch]; PkAmpQ = pDET->PkAmpQ[snd_ch]; PkAmpMax = pDET->PkAmpMax[snd_ch]; newpkpos = pDET->newpkpos[snd_ch]; PSK_IZ1 = pDET->PSK_IZ1[snd_ch]; PSK_QZ1 = pDET->PSK_QZ1[snd_ch]; bit_osc = pDET->bit_osc[snd_ch]; frame_status = pDET->frame_status[snd_ch]; bit_cnt = pDET->bit_cnt[snd_ch]; bit_stream = pDET->bit_stream[snd_ch]; byte_rx = pDET->byte_rx[snd_ch]; // tr = dcd_threshold * dcd_corr; if (last) { // Update DCD status if (dcd_hdr_cnt[snd_ch] == 0) dcd_on_hdr[snd_ch] = 0; dcd_bit_cnt[snd_ch] = 0; } baudrate = 300; div_bit_afc = 1.0f / round(BIT_AFC*(RX_Samplerate / 11025)); x = baudrate / RX_Samplerate; // max_cnt = round(RX_Samplerate / baudrate) + 1; max_cnt = round(RX_Samplerate / baudrate) + 1; for (i = 0; i < buf_size - 1; i++) { // AGC amp = sqrt(srcI[i] * srcI[i] + srcQ[i] * srcQ[i]); if (amp > PSK_AGC) PSK_AGC = PSK_AGC * agc_fast1 + amp*agc_fast; else PSK_AGC = PSK_AGC * agc_slow1 + amp*agc_slow; if (PSK_AGC > 1) { srcI[i] = srcI[i] / PSK_AGC; srcQ[i] = srcQ[i] / PSK_AGC; amp = amp / PSK_AGC; // Вместо SQRT } // bit_buf[sample_cnt] = 0.95*bit_buf[sample_cnt] + 0.05*amp; // Находим максимум в буфере синхронизации if (bit_buf[sample_cnt] > PkAmpMax) { PkAmpI = srcI[i]; PkAmpQ = srcQ[i]; PkAmpMax = bit_buf[sample_cnt]; newpkpos = sample_cnt; } sample_cnt++; bit_osc = bit_osc + x; if (bit_osc >= 1) { if (sample_cnt <= max_cnt) for (k = sample_cnt; k <= max_cnt; k++) bit_buf[k] = 0.95*bit_buf[k]; k1 = (1.0f * newpkpos) / (sample_cnt - 1); k2 = pila(k1) - 1; afc = div_bit_afc * k2; if (k1 > 0.5f) bit_osc = bit_osc + afc; else bit_osc = bit_osc - afc; PkAmpMax = 0; sample_cnt = 0; bit_osc = bit_osc - 1; //DCD feature if (last) { DCD_LastPkPos[snd_ch] = DCD_LastPkPos[snd_ch] * 0.96f + newpkpos * 0.04f; DCD_LastPerc[snd_ch] = DCD_LastPerc[snd_ch] * 0.96f + fabsf(newpkpos - DCD_LastPkPos[snd_ch])*0.04f; if (DCD_LastPerc[snd_ch] >= tr || DCD_LastPerc[snd_ch] < 0.00001f) dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] + 1; else dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] - 1; } // Bit-detector muxI1 = PkAmpI * PSK_IZ1; muxI2 = PkAmpQ * PSK_IZ1; muxQ1 = PkAmpQ * PSK_QZ1; muxQ2 = PkAmpI * PSK_QZ1; sumIQ1 = muxI1 + muxQ1; sumIQ2 = muxI2 - muxQ2; angle = atan2f(sumIQ2, sumIQ1); PSK_IZ1 = PkAmpI; PSK_QZ1 = PkAmpQ; float Mag = sqrtf(powf(PSK_IZ1, 2) + powf(PSK_QZ1, 2)); // Phase corrector if (fabsf(angle) < PI5) AngleCorr = AngleCorr * 0.95f - angle * 0.05f; else { if (angle > 0) AngleCorr = AngleCorr * 0.95f + (pi - angle)*0.05f; else AngleCorr = AngleCorr * 0.95f - (pi + angle)*0.05f; } angle = angle + AngleCorr; // if (fabsf(angle) < PI5) bit = RX_BIT1; else bit = RX_BIT0; // // is this the best place to store phase for constellation? // only for ilp2 for now if (il2p_mode[snd_ch]) { struct il2p_context_s * il2p = il2p_context[snd_ch][rcvr_nr][emph]; if (il2p && il2p->state > IL2P_SEARCHING) { Phases[snd_ch][rcvr_nr][emph][nPhases[snd_ch][rcvr_nr][emph]] = angle; Mags[snd_ch][rcvr_nr][emph][nPhases[snd_ch][rcvr_nr][emph]++] = Mag; if (nPhases[snd_ch][rcvr_nr][emph] > 4090) nPhases[snd_ch][rcvr_nr][emph]--; } il2p_rec_bit(snd_ch, rcvr_nr, emph, bit); if (il2p_mode[snd_ch] == IL2P_MODE_ONLY) // Dont try HDLC decode continue; } if (bit) stats[1]++; else stats[0]++; bit_stream = (bit_stream >> 1) | bit; // DCD on flag if (last) { if (dcd_hdr_cnt[snd_ch] > 0) dcd_hdr_cnt[snd_ch]--; DCD_header[snd_ch] = (DCD_header[snd_ch] >> 1) | (bit << 24); if (((DCD_header[snd_ch] & 0xFFFF0000) == 0x7E7E0000) || ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x7E000000) || ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x00000000)) { dcd_hdr_cnt[snd_ch] = 48; dcd_on_hdr[snd_ch] = 1; } } // I think Andy looks for both flag and abort here. I think it would be // clearer to detect abort separately // This may not be optimun but should work if (bit_stream == 0xFF || bit_stream == 0x7F || bit_stream == 0xFE) { // All have 7 or more 1 bits if (frame_status == FRAME_LOAD) { // Have started receiving frame // Debugprintf("Frame Abort len= %d bytes", data->Length); frame_status = FRAME_WAIT; // Raw stream init bit_cnt = 0; bit_stuff_cnt = 0; data->Length = 0; } continue; } if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_LOAD) { frame_status = FRAME_WAIT; // if (bit_cnt == 6) make_rx_frame_PSK(snd_ch, rcvr_nr, emph, data); } if (frame_status == FRAME_LOAD) { if (bit_stuff_cnt == 5) bit_stuff_cnt = 0; else { if (bit == RX_BIT1) bit_stuff_cnt++; else bit_stuff_cnt = 0; byte_rx = (byte_rx >> 1) + bit; bit_cnt++; } if (bit_cnt == 8) { if (data->Length < 4097) stringAdd(data, &byte_rx, 1); bit_cnt = 0; } } if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_WAIT) { frame_status = FRAME_LOAD; bit_cnt = 0; bit_stuff_cnt = 0; data->Length = 0; } } } pDET->sample_cnt[snd_ch] = sample_cnt; pDET->PSK_AGC[snd_ch] = PSK_AGC; pDET->PkAmpI[snd_ch] = PkAmpI; pDET->PkAmpQ[snd_ch] = PkAmpQ; pDET->PkAmpMax[snd_ch] = PkAmpMax; pDET->newpkpos[snd_ch] = newpkpos; pDET->PSK_IZ1[snd_ch] = PSK_IZ1; pDET->PSK_QZ1[snd_ch] = PSK_QZ1; pDET->bit_osc[snd_ch] = bit_osc; pDET->frame_status[snd_ch] = frame_status; pDET->bit_cnt[snd_ch] = bit_cnt; pDET->bit_stream[snd_ch] = bit_stream; pDET->byte_rx[snd_ch] = byte_rx; pDET->bit_stuff_cnt[snd_ch] = bit_stuff_cnt; pDET->AngleCorr[snd_ch] = AngleCorr; } void decode_stream_QPSK(int last, int snd_ch, int rcvr_nr, int emph, float * srcI, float * srcQ, float * bit_buf, int buf_size, string * data) { float agc_fast = 0.01f; float agc_fast1 = 1 - agc_fast; float agc_slow = agc_fast / 4; float agc_slow1 = 1 - agc_slow; int i, k, j, n; Byte dibit = 0, bit; single afc, x, amp, k1, k2; single baudrate; single div_bit_afc; word max_cnt; single threshold; single tr; single KCorr = 0, AngleCorr, angle, muxI1, muxQ1, muxI2, muxQ2, sumIQ1, sumIQ2; Byte newpkpos, sample_cnt; single PkAmpI, PkAmpQ, PkAmpMax, PSK_AGC; single PSK_IZ1, PSK_QZ1; single bit_osc; Byte bit_stuff_cnt, last_rx_bit, frame_status, bit_cnt, bit_stream, byte_rx; // get saved values to local variables to speed up access struct TDetector_t * pDET = &DET[emph][rcvr_nr]; bit_stuff_cnt = pDET->bit_stuff_cnt[snd_ch]; last_rx_bit = pDET->last_rx_bit[snd_ch]; sample_cnt = pDET->sample_cnt[snd_ch]; PSK_AGC = pDET->PSK_AGC[snd_ch]; PkAmpI = pDET->PkAmpI[snd_ch]; PkAmpQ = pDET->PkAmpQ[snd_ch]; PkAmpMax = pDET->PkAmpMax[snd_ch]; newpkpos = pDET->newpkpos[snd_ch]; PSK_IZ1 = pDET->PSK_IZ1[snd_ch]; PSK_QZ1 = pDET->PSK_QZ1[snd_ch]; bit_osc = pDET->bit_osc[snd_ch]; frame_status = pDET->frame_status[snd_ch]; bit_cnt = pDET->bit_cnt[snd_ch]; bit_stream = pDET->bit_stream[snd_ch]; byte_rx = pDET->byte_rx[snd_ch]; AngleCorr = pDET->AngleCorr[snd_ch]; tr = dcd_threshold * dcd_corr; if (last) { // Update DCD status if (dcd_hdr_cnt[snd_ch] == 0) dcd_on_hdr[snd_ch] = 0; dcd_bit_cnt[snd_ch] = 0; } // I think this works because of upsampling - 1200 = 4x 300 and we upsampled by 4 baudrate = 300; div_bit_afc = 1.0f / roundf(BIT_AFC*(RX_Samplerate / 11025.0f)); x = baudrate / RX_Samplerate; max_cnt = roundf(RX_Samplerate / baudrate) + 1; for (i = 0; i < buf_size; i++) { // AGC amp = sqrt(srcI[i] * srcI[i] + srcQ[i] * srcQ[i]); if (amp > PSK_AGC) PSK_AGC = PSK_AGC * agc_fast1 + amp * agc_fast; else PSK_AGC = PSK_AGC * agc_slow1 + amp * agc_slow; if (PSK_AGC > 1) { srcI[i] = srcI[i] / PSK_AGC; srcQ[i] = srcQ[i] / PSK_AGC; amp = amp / PSK_AGC; // Вместо SQRT } bit_buf[sample_cnt] = 0.95 * bit_buf[sample_cnt] + 0.05 * amp; // Check for NAN if (bit_buf[sample_cnt] != bit_buf[sample_cnt]) bit_buf[sample_cnt] = 0.0f; // Find the maximum in the synchronization buffer if (bit_buf[sample_cnt] > PkAmpMax) { PkAmpI = srcI[i]; PkAmpQ = srcQ[i]; PkAmpMax = bit_buf[sample_cnt]; newpkpos = sample_cnt; } sample_cnt++; bit_osc = bit_osc + x; // This seems to be how it does samples to bits if (bit_osc >= 1) { if (sample_cnt <= max_cnt) for (k = sample_cnt; k <= max_cnt; k++) bit_buf[k] = 0.95*bit_buf[k]; k1 = (1.0f * newpkpos) / (sample_cnt - 1); k2 = pila(k1) - 1; afc = div_bit_afc * k2; if (k1 > 0.5) bit_osc = bit_osc + afc; else bit_osc = bit_osc - afc; PkAmpMax = 0; sample_cnt = 0; bit_osc = bit_osc - 1; //DCD feature if (last) { DCD_LastPkPos[snd_ch] = DCD_LastPkPos[snd_ch] * 0.96 + newpkpos * 0.04; DCD_LastPerc[snd_ch] = DCD_LastPerc[snd_ch] * 0.96 + fabsf(newpkpos - DCD_LastPkPos[snd_ch])*0.04; if (DCD_LastPerc[snd_ch] >= tr || DCD_LastPerc[snd_ch] < 0.00001f) dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] + 1; else dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] - 1; } // Bit-detector muxI1 = PkAmpI * PSK_IZ1; muxI2 = PkAmpQ * PSK_IZ1; muxQ1 = PkAmpQ * PSK_QZ1; muxQ2 = PkAmpI * PSK_QZ1; sumIQ1 = muxI1 + muxQ1; sumIQ2 = muxI2 - muxQ2; angle = atan2f(sumIQ2, sumIQ1); PSK_IZ1 = PkAmpI; PSK_QZ1 = PkAmpQ; float Mag = sqrtf(powf(PSK_IZ1, 2) + powf(PSK_QZ1, 2)); if (angle > pi || angle < -pi) angle = angle; if (modem_mode[snd_ch] == MODE_PI4QPSK) { // Phase corrector // I'm pretty sure we send 4 phases starting 45 degrees from 0 so .25, .75 - .25 - .75 if (angle >= 0 && angle <= PI5) KCorr = angle - PI25; if (angle > PI5) KCorr = angle - PI75; if (angle < -PI5) KCorr = angle + PI75; if (angle < 0 && angle >= -PI5) KCorr = angle + PI25; AngleCorr = AngleCorr * 0.95f - KCorr * 0.05f; angle = angle + AngleCorr; if (angle >= 0 && angle <= PI5) { dibit = qpsk_set[snd_ch].rx[0]; // 00 - 0 qpsk_set[snd_ch].count[0]++; } else if (angle > PI5) { dibit = qpsk_set[snd_ch].rx[1]; // 01 - PI/2 qpsk_set[snd_ch].count[1]++; } else if (angle < -PI5) { dibit = qpsk_set[snd_ch].rx[2]; // 10 - PI qpsk_set[snd_ch].count[2]++; } else if (angle < 0 && angle >= -PI5) { dibit = qpsk_set[snd_ch].rx[3]; // 11 - -PI/2 qpsk_set[snd_ch].count[3]++; } } else { // "Normal" QPSK // Phase corrector // I think this sends 0 90 180 270 if (fabsf(angle) < PI25) KCorr = angle; if (angle >= PI25 && angle <= PI75) KCorr = angle - PI5; if (angle <= -PI25 && angle >= -PI75) KCorr = angle + PI5; if (fabsf(angle) > PI75) { if (angle > 0) KCorr = -M_PI + angle; else KCorr = M_PI + angle; } AngleCorr = AngleCorr * 0.95 - KCorr * 0.05; angle = angle + AngleCorr; if (fabsf(angle) < PI25) dibit = qpsk_set[snd_ch].rx[0]; // 00 - 0 else if (angle >= PI25 && angle <= PI75) dibit = qpsk_set[snd_ch].rx[1]; // 01 - PI/2 else if (fabsf(angle) > PI75) dibit = qpsk_set[snd_ch].rx[2]; // 10 - PI else if (angle <= -PI25 && angle >= -PI75) dibit = qpsk_set[snd_ch].rx[3]; // 11 - -PI/2 } for (j = 0; j < 2; j++) { dibit = dibit << 1; // is this the best place to store phase for constellation? // only for ilp2 for now if (il2p_mode[snd_ch]) { struct il2p_context_s * il2p = il2p_context[snd_ch][rcvr_nr][emph]; if (il2p && il2p->state > IL2P_SEARCHING) { Phases[snd_ch][rcvr_nr][emph][nPhases[snd_ch][rcvr_nr][emph]] = angle; Mags[snd_ch][rcvr_nr][emph][nPhases[snd_ch][rcvr_nr][emph]++] = Mag; if (nPhases[snd_ch][rcvr_nr][emph] > 4090) nPhases[snd_ch][rcvr_nr][emph]--; } il2p_rec_bit(snd_ch, rcvr_nr, emph, (dibit & RX_BIT1)); if (il2p_mode[snd_ch] == IL2P_MODE_ONLY) // Dont try HDLC decode continue; } // NRZI if (last_rx_bit == (dibit & RX_BIT1)) bit = RX_BIT1; else bit = RX_BIT0; last_rx_bit = dibit & RX_BIT1; bit_stream = (bit_stream >> 1) | bit; // DCD on flag if (last) { if (dcd_hdr_cnt[snd_ch] > 0) dcd_hdr_cnt[snd_ch]--; DCD_header[snd_ch] = (DCD_header[snd_ch] >> 1) | (bit << 24); if (((DCD_header[snd_ch] & 0xFFFF0000) == 0x7E7E0000) || ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x7E000000) || ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x00000000)) { dcd_hdr_cnt[snd_ch] = 48; dcd_on_hdr[snd_ch] = 1; } } // I think Andy looks for both flag and abort here. I think it would be // clearer to detect abort separately // This may not be optimun but should work if (bit_stream == 0xFF || bit_stream == 0x7F || bit_stream == 0xFE) { // All have 7 or more 1 bits if (frame_status == FRAME_LOAD) { // Have started receiving frame // Debugprintf("Frame Abort len= %d bytes", data->Length); frame_status = FRAME_WAIT; // Raw stream init bit_cnt = 0; bit_stuff_cnt = 0; data->Length = 0; } continue; } if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_LOAD) { frame_status = FRAME_WAIT; // if (bit_cnt == 6) make_rx_frame_PSK(snd_ch, rcvr_nr, emph, data); } if (frame_status == FRAME_LOAD) { if (bit_stuff_cnt == 5) bit_stuff_cnt = 0; else { if (bit == RX_BIT1) bit_stuff_cnt++; else bit_stuff_cnt = 0; byte_rx = (byte_rx >> 1) + bit; bit_cnt++; } if (bit_cnt == 8) { if (data->Length < 4097) stringAdd(data, &byte_rx, 1); bit_cnt = 0; } } if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_WAIT) { frame_status = FRAME_LOAD; bit_cnt = 0; bit_stuff_cnt = 0; data->Length = 0; } } } } pDET->sample_cnt[snd_ch] = sample_cnt; pDET->PSK_AGC[snd_ch] = PSK_AGC; pDET->PkAmpI[snd_ch] = PkAmpI; pDET->PkAmpQ[snd_ch] = PkAmpQ; pDET->PkAmpMax[snd_ch] = PkAmpMax; pDET->newpkpos[snd_ch] = newpkpos; pDET->PSK_IZ1[snd_ch] = PSK_IZ1; pDET->PSK_QZ1[snd_ch] = PSK_QZ1; pDET->bit_osc[snd_ch] = bit_osc; pDET->frame_status[snd_ch] = frame_status; pDET->bit_cnt[snd_ch] = bit_cnt; pDET->bit_stream[snd_ch] = bit_stream; pDET->byte_rx[snd_ch] = byte_rx; pDET->last_rx_bit[snd_ch] = last_rx_bit; pDET->bit_stuff_cnt[snd_ch] = bit_stuff_cnt; pDET->AngleCorr[snd_ch] = AngleCorr; } void decode_stream_8PSK(int last, int snd_ch, int rcvr_nr, int emph, float * srcI, float * srcQ, float * bit_buf, int buf_size, string * data) { float agc_fast = 0.01f; float agc_fast1 = 1 - agc_fast; float agc_slow = agc_fast / 4; float agc_slow1 = 1 - agc_slow; int i, k, j, n; Byte tribit = 0, bit; single afc, x, amp, k1, k2; single baudrate; single div_bit_afc; word max_cnt; single threshold; single tr; single KCorr = 0, AngleCorr, angle, muxI1, muxQ1, muxI2, muxQ2, sumIQ1, sumIQ2; Byte newpkpos, sample_cnt; single PkAmpI, PkAmpQ, PkAmpMax, PSK_AGC; single PSK_IZ1, PSK_QZ1; single bit_osc; Byte bit_stuff_cnt, last_rx_bit, frame_status, bit_cnt, bit_stream, byte_rx; // get saved values to local variables to speed up access struct TDetector_t * pDET = &DET[emph][rcvr_nr]; bit_stuff_cnt = pDET->bit_stuff_cnt[snd_ch]; last_rx_bit = pDET->last_rx_bit[snd_ch]; sample_cnt = pDET->sample_cnt[snd_ch]; PSK_AGC = pDET->PSK_AGC[snd_ch]; PkAmpI = pDET->PkAmpI[snd_ch]; PkAmpQ = pDET->PkAmpQ[snd_ch]; PkAmpMax = pDET->PkAmpMax[snd_ch]; newpkpos = pDET->newpkpos[snd_ch]; PSK_IZ1 = pDET->PSK_IZ1[snd_ch]; PSK_QZ1 = pDET->PSK_QZ1[snd_ch]; bit_osc = pDET->bit_osc[snd_ch]; frame_status = pDET->frame_status[snd_ch]; bit_cnt = pDET->bit_cnt[snd_ch]; bit_stream = pDET->bit_stream[snd_ch]; byte_rx = pDET->byte_rx[snd_ch]; AngleCorr = pDET->AngleCorr[snd_ch]; tr = dcd_threshold * dcd_corr; if (last) { // Update DCD status if (dcd_hdr_cnt[snd_ch] == 0) dcd_on_hdr[snd_ch] = 0; dcd_bit_cnt[snd_ch] = 0; } // Not sure how this works if (tx_baudrate[snd_ch] == 300) baudrate = 300; else baudrate = 1600 / 6; div_bit_afc = 1.0 / round(BIT_AFC*(RX_Samplerate / 11025)); x = baudrate / RX_Samplerate; max_cnt = round(RX_Samplerate / baudrate) + 1; for (i = 0; i < buf_size; i++) { // AGC amp = sqrt(srcI[i] * srcI[i] + srcQ[i] * srcQ[i]); if (amp > PSK_AGC) PSK_AGC = PSK_AGC * agc_fast1 + amp*agc_fast; else PSK_AGC = PSK_AGC * agc_slow1 + amp*agc_slow; if (PSK_AGC > 1) { srcI[i] = srcI[i] / PSK_AGC; srcQ[i] = srcQ[i] / PSK_AGC; amp = amp / PSK_AGC; // Вместо SQRT } bit_buf[sample_cnt] = 0.95*bit_buf[sample_cnt] + 0.05*amp; // Находим максимум в буфере синхронизации if (bit_buf[sample_cnt] > PkAmpMax) { PkAmpI = srcI[i]; PkAmpQ = srcQ[i]; PkAmpMax = bit_buf[sample_cnt]; newpkpos = sample_cnt; } // sample_cnt++; bit_osc = bit_osc + x; if (bit_osc >= 1) { if (sample_cnt <= max_cnt) for (k = sample_cnt; k <= max_cnt; k++) bit_buf[k] = 0.95*bit_buf[k]; k1 = (1.0f * newpkpos) / (sample_cnt - 1); k2 = pila(k1) - 1; afc = div_bit_afc * k2; if (k1 > 0.5) bit_osc = bit_osc + afc; else bit_osc = bit_osc - afc; PkAmpMax = 0; sample_cnt = 0; bit_osc = bit_osc - 1; //DCD feature if (last) { DCD_LastPkPos[snd_ch] = DCD_LastPkPos[snd_ch] * 0.96 + newpkpos * 0.04; DCD_LastPerc[snd_ch] = DCD_LastPerc[snd_ch] * 0.96 + abs(newpkpos - DCD_LastPkPos[snd_ch])*0.04; if (DCD_LastPerc[snd_ch] >= tr || DCD_LastPerc[snd_ch] < 0.00001) dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] + 1; else dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] - 1; } // Bit-detector muxI1 = PkAmpI * PSK_IZ1; muxI2 = PkAmpQ * PSK_IZ1; muxQ1 = PkAmpQ * PSK_QZ1; muxQ2 = PkAmpI * PSK_QZ1; sumIQ1 = muxI1 + muxQ1; sumIQ2 = muxI2 - muxQ2; angle = atan2f(sumIQ2, sumIQ1); PSK_IZ1 = PkAmpI; PSK_QZ1 = PkAmpQ; float Mag = sqrtf(powf(PSK_IZ1, 2) + powf(PSK_QZ1, 2)); // Phase corrector if (fabsf(angle) < PI125) KCorr = angle; if (angle >= PI125 && angle <= PI375) KCorr = angle - PI25; if (angle >= PI375 && angle < PI625) KCorr = angle - PI5; if (angle >= PI625 && angle <= PI875) KCorr = angle - PI75; if (angle <= -PI125 && angle > -PI375) KCorr = angle + PI25; if (angle <= -PI375 && angle > -PI625) KCorr = angle + PI5; if (angle <= -PI625 && angle >= -PI875) KCorr = angle + PI75; if (fabsf(angle) > PI875) { if (angle > 0) KCorr = angle - pi; else KCorr = angle + pi; } AngleCorr = AngleCorr * 0.95 - KCorr * 0.05; angle = angle + AngleCorr; if (fabsf(angle) < PI125) tribit = 1; if (angle >= PI125 && angle < PI375) tribit = 0; if (angle >= PI375 && angle < PI625) tribit = 2; if (angle >= PI625 && angle <= PI875) tribit = 3; if (fabsf(angle) > PI875) tribit = 7; if (angle <= -PI625 && angle >= -PI875) tribit = 6; if (angle <= -PI375 && angle > -PI625) tribit = 4; if (angle <= -PI125 && angle > -PI375) tribit = 5; tribit = tribit << 4; for (j = 0; j < 3; j++) { tribit = tribit << 1; // look for il2p before nrzi // is this the best place to store phase for constellation? // only for ilp2 for now if (il2p_mode[snd_ch]) { struct il2p_context_s * il2p = il2p_context[snd_ch][rcvr_nr][emph]; if (il2p && il2p->state > IL2P_SEARCHING) { Phases[snd_ch][rcvr_nr][emph][nPhases[snd_ch][rcvr_nr][emph]] = angle; Mags[snd_ch][rcvr_nr][emph][nPhases[snd_ch][rcvr_nr][emph]++] = Mag; if (nPhases[snd_ch][rcvr_nr][emph] > 4090) nPhases[snd_ch][rcvr_nr][emph]--; } il2p_rec_bit(snd_ch, rcvr_nr, emph, tribit & RX_BIT1); if (il2p_mode[snd_ch] == IL2P_MODE_ONLY) // Dont try HDLC decode continue; } //NRZI if (last_rx_bit == (tribit & RX_BIT1)) bit = RX_BIT1; else bit = RX_BIT0; last_rx_bit = tribit & RX_BIT1; // bit_stream = (bit_stream >> 1) | bit; // DCD on flag if (last) { if (dcd_hdr_cnt[snd_ch] > 0) dcd_hdr_cnt[snd_ch]--; DCD_header[snd_ch] = (DCD_header[snd_ch] >> 1) | (bit << 24); if (((DCD_header[snd_ch] & 0xFFFF0000) == 0x7E7E0000) || ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x7E000000) || ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x00000000)) { dcd_hdr_cnt[snd_ch] = 48; dcd_on_hdr[snd_ch] = 1; } } // I think Andy looks for both flag and abort here. I think it would be // clearer to detect abort separately // This may not be optimun but should work if (bit_stream == 0xFF || bit_stream == 0x7F || bit_stream == 0xFE) { // All have 7 or more 1 bits if (frame_status == FRAME_LOAD) { // Have started receiving frame // Debugprintf("Frame Abort len= %d bytes", data->Length); frame_status = FRAME_WAIT; // Raw stream init bit_cnt = 0; bit_stuff_cnt = 0; data->Length = 0; } continue; } if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_LOAD) { frame_status = FRAME_WAIT; if (bit_cnt == 6) make_rx_frame_PSK(snd_ch, rcvr_nr, emph, data); } if (frame_status == FRAME_LOAD) { if (bit_stuff_cnt == 5) bit_stuff_cnt = 0; else { if (bit == RX_BIT1) bit_stuff_cnt++; else bit_stuff_cnt = 0; byte_rx = (byte_rx >> 1) + bit; bit_cnt++; } if (bit_cnt == 8) { if (data->Length < 4097) stringAdd(data, &byte_rx, 1); bit_cnt = 0; } } if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_WAIT) { frame_status = FRAME_LOAD; bit_cnt = 0; bit_stuff_cnt = 0; data->Length = 0; } } } } pDET->sample_cnt[snd_ch] = sample_cnt; pDET->PSK_AGC[snd_ch] = PSK_AGC; pDET->PkAmpI[snd_ch] = PkAmpI; pDET->PkAmpQ[snd_ch] = PkAmpQ; pDET->PkAmpMax[snd_ch] = PkAmpMax; pDET->newpkpos[snd_ch] = newpkpos; pDET->PSK_IZ1[snd_ch] = PSK_IZ1; pDET->PSK_QZ1[snd_ch] = PSK_QZ1; pDET->bit_osc[snd_ch] = bit_osc; pDET->frame_status[snd_ch] = frame_status; pDET->bit_cnt[snd_ch] = bit_cnt; pDET->bit_stream[snd_ch] = bit_stream; pDET->byte_rx[snd_ch] = byte_rx; pDET->last_rx_bit[snd_ch] = last_rx_bit; pDET->bit_stuff_cnt[snd_ch] = bit_stuff_cnt; pDET->AngleCorr[snd_ch] = AngleCorr; } /* //////////////////////////////////////////////////////// function blackman(i,tap: word): single; var a0,a1,a2,a: single; { a = 0.16; a0 = (1-a)/2; a1 = 1/2; a2 = a/2; result = a0-a1*cos(2*pi*i/(tap-1))+a2*cos(4*pi*i/(tap-1)); } function nuttal(i,tap: word): single; var a0,a1,a2,a3: single; { a0 = 0.355768; a1 = 0.487396; a2 = 0.144232; a3 = 0.012604; result = a0-a1*cos(2*pi*i/(tap-1))+a2*cos(4*pi*i/(tap-1))-a3*cos(6*pi*i/(tap-1)); } function flattop(i,tap: word): single; var a0,a1,a2,a3,a4: single; { a0 = 1; a1 = 1.93; a2 = 1.29; a3 = 0.388; a4 = 0.032; result = a0-a1*cos(2*pi*i/(tap-1))+a2*cos(4*pi*i/(tap-1))-a3*cos(6*pi*i/(tap-1))+a4*cos(8*pi*i/(tap-1)); } */ void init_BPF(float freq1, float freq2, unsigned short tap, float samplerate, float * buf) { unsigned short tap1, i; float tap12, ham, acc1, acc2; float bpf_l[2048]; float bpf_h[2048]; float itap12, pi2, x1, x2; acc1 = 0; acc2 = 0; tap1 = tap - 1; tap12 = tap1 / 2; pi2 = 2 * pi; x1 = pi2 * freq1 / samplerate; x2 = pi2 * freq2 / samplerate; for (i = 0; i <= tap1; i++) { // float x = (pi2 * i) / tap1; // x = cosf(x); // ham = 0.5 - 0.5 * x; ham = 0.5 - 0.5 * cosf((pi2 * i) / tap1); //old if (ham != ham) // check for NaN ham = 0.0f; itap12 = i - tap12; if (itap12 == 0) { bpf_l[i] = x1; bpf_h[i] = x2; } else { bpf_l[i] = sinf(x1*itap12) / itap12; bpf_h[i] = sinf(x2*itap12) / itap12; } bpf_l[i] = bpf_l[i] * ham; bpf_h[i] = bpf_h[i] * ham; acc1 = acc1 + bpf_l[i]; acc2 = acc2 + bpf_h[i]; } for (i = 0; i <= tap1; i++) { bpf_l[i] = bpf_l[i] / acc1; bpf_h[i] = -(bpf_h[i] / acc2); }; bpf_h[tap / 2] = bpf_h[tap / 2] + 1; for (i = 0; i <= tap; i++) { buf[i] = -(bpf_l[i] + bpf_h[i]); } buf[tap / 2] = buf[tap / 2] + 1; } void init_LPF(float width, unsigned short tap, float samplerate, float * buf) { float acc1, ham; unsigned short tap1, i; float itap12, tap12, x1, pi2; acc1 = 0; tap1 = tap - 1; tap12 = tap1 / 2; pi2 = 2 * pi; x1 = pi2 * width / samplerate; for (i = 0; i <= tap1; i++) { ham = 0.53836f - 0.46164f * cosf(pi2 * i / tap1); //old if (ham != ham) // check for NaN ham = 0.0f; //ham = 0.5-0.5*cos(pi2*i/tap1); //ham = 0.5*(1-cos(pi2*i/tap1)); //hann //ham = blackman(i,tap); //blackman //ham = nuttal(i,tap); itap12 = i - tap12; if (itap12 == 0) buf[i] = x1; else buf[i] = sinf(x1*itap12) / itap12; buf[i] = buf[i] * ham; acc1 = acc1 + buf[i]; } for (i = 0; i <= tap1; i++) buf[i] = buf[i] / acc1; } void make_core_INTR(UCHAR snd_ch) { float width; width = roundf(RX_Samplerate / 2); n_INTR[snd_ch] = 1; switch (speed[snd_ch]) { case SPEED_300: width = roundf(RX_Samplerate / 2); n_INTR[snd_ch] = 1; break; case SPEED_P300: width = roundf(RX_Samplerate / 2); n_INTR[snd_ch] = 1; break; case SPEED_Q300: case SPEED_8PSK300: width = roundf(RX_Samplerate / 2); n_INTR[snd_ch] = 1; break; case SPEED_600: width = roundf(RX_Samplerate / 4); n_INTR[snd_ch] = 2; break; case SPEED_P600: width = roundf(RX_Samplerate / 4); n_INTR[snd_ch] = 2; break; case SPEED_1200: width = roundf(RX_Samplerate / 8); n_INTR[snd_ch] = 4; break; case SPEED_P1200: width = roundf(RX_Samplerate / 8); n_INTR[snd_ch] = 4; break; // case SPEED_Q1200: // width = roundf(RX_Samplerate / 8); // n_INTR[snd_ch] = 4; // break; case SPEED_Q2400: width = 300; n_INTR[snd_ch] = 4; break; //8 case SPEED_DW2400: width = 300; n_INTR[snd_ch] = 4; break; case SPEED_2400V26B: width = 300; n_INTR[snd_ch] = 4; break; case SPEED_MP400: width = round(RX_Samplerate / 8); n_INTR[snd_ch] = 4; break; case SPEED_Q3600: width = 300; n_INTR[snd_ch] = 6;//12 break; case SPEED_8P4800: width = 100; n_INTR[snd_ch] = 6; break; case SPEED_2400: width = round(RX_Samplerate / 16); n_INTR[snd_ch] = 8; break; case SPEED_P2400: width = round(RX_Samplerate / 16); n_INTR[snd_ch] = 8; break; case SPEED_Q4800: width = 300; n_INTR[snd_ch] = 8;//16 break; } init_LPF(width, INTR_tap[snd_ch], RX_Samplerate, INTR_core[snd_ch]); } void make_core_LPF(UCHAR snd_ch, short width) { if (modem_mode[snd_ch] == MODE_MPSK) { init_LPF(width, LPF_tap[snd_ch], RX_Samplerate / n_INTR[snd_ch], LPF_core[snd_ch]); init_LPF(rx_baudrate[snd_ch], LPF_tap[snd_ch], RX_Samplerate / n_INTR[snd_ch], AFC_core[snd_ch]); } else init_LPF(width, LPF_tap[snd_ch], RX_Samplerate, LPF_core[snd_ch]); } void make_core_BPF(UCHAR snd_ch, short freq, short width) { float old_freq, width2, rx_samplerate2, freq1, freq2; UCHAR i; freq = freq + rxOffset + chanOffset[snd_ch]; // I want to run decoders lowest to highest to simplify my display, // so filters must be calculated in same order int offset = -(RCVR[snd_ch] * rcvr_offset[snd_ch]); // lowest rx_samplerate2 = 0.5 * RX_Samplerate; width2 = 0.5 * width; old_freq = freq; for (i = 0; i <= RCVR[snd_ch] << 1; i++) { freq = old_freq + offset; freq1 = freq - width2; freq2 = freq + width2; if (freq1 < 1) freq1 = 1; if (freq2 < 1) freq2 = 1; if (freq1 > rx_samplerate2) freq1 = rx_samplerate2; if (freq2 > rx_samplerate2) freq2 = rx_samplerate2; init_BPF(freq1, freq2, BPF_tap[snd_ch], RX_Samplerate, &DET[0][i].BPF_core[snd_ch][0]); offset += rcvr_offset[snd_ch]; } } void make_core_TXBPF(UCHAR snd_ch, float freq, float width) { float freq1, freq2; freq1 = freq - width / 2; freq2 = freq + width / 2; if (freq1 < 1) freq1 = 1; if (freq2 < 1) freq2 = 1; if (freq1 > TX_Samplerate / 2) freq1 = TX_Samplerate / 2; if (freq2 > TX_Samplerate / 2) freq2 = TX_Samplerate / 2; init_BPF(freq1, freq2, tx_BPF_tap[snd_ch], TX_Samplerate, tx_BPF_core[snd_ch]); } void interpolation(int snd_ch, int rcvr_nr, int emph, float * dest_buf, float * src_buf, int buf_size) { int n_intr1, buf_size1, k, i, j; float buf[8192]; buf_size1 = buf_size - 1; n_intr1 = n_INTR[snd_ch] - 1; k = 0; for (i = 0; i <= buf_size1; i++) { for (j = 0; j <= n_intr1; j++) { buf[k] = src_buf[i]; k++; } } FIR_filter(buf, buf_size *n_INTR[snd_ch], INTR_tap[snd_ch], INTR_core[snd_ch], dest_buf, DET[emph][rcvr_nr].prev_INTR_buf[snd_ch]); } void interpolation_PSK(int snd_ch, int rcvr_nr, int emph, float * destI, float * destQ, float * srcI, float * srcQ, int buf_size) { word n_intr1, buf_size1, k, i, j; single bufI[8192], bufQ[8192]; buf_size1 = buf_size - 1; n_intr1 = n_INTR[snd_ch] - 1; k = 0; for (i = 0; i <= buf_size1; i++) { for (j = 0; j <= n_intr1; j++) { bufI[k] = srcI[i]; bufQ[k] = srcQ[i]; k++; } } FIR_filter(bufI, buf_size*n_INTR[snd_ch], INTR_tap[snd_ch], INTR_core[snd_ch], destI, DET[emph][rcvr_nr].prev_INTRI_buf[snd_ch]); FIR_filter(bufQ, buf_size*n_INTR[snd_ch], INTR_tap[snd_ch], INTR_core[snd_ch], destQ, DET[emph][rcvr_nr].prev_INTRQ_buf[snd_ch]); } void FSK_Demodulator(int snd_ch, int rcvr_nr, int emph, int last) { // filtered samples in src_BPF_buf, output in src_Loop_buf Mux3(snd_ch,rcvr_nr,emph, &DET[0][rcvr_nr].src_BPF_buf[snd_ch][0], &LPF_core[snd_ch][0], &DET[emph][rcvr_nr].src_Loop_buf[snd_ch][0], &DET[emph][rcvr_nr].prev_LPF1I_buf[snd_ch][0], &DET[emph][rcvr_nr].prev_LPF1Q_buf[snd_ch][0], LPF_tap[snd_ch], rx_bufsize); if (n_INTR[snd_ch] > 1) { interpolation(snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_INTR_buf[snd_ch], DET[emph][rcvr_nr].src_Loop_buf[snd_ch], rx_bufsize); decode_stream_FSK(last, snd_ch, rcvr_nr, emph, &DET[emph][rcvr_nr].src_INTR_buf[snd_ch][0], &DET[emph][rcvr_nr].bit_buf[snd_ch][0], rx_bufsize*n_INTR[snd_ch], &DET[emph][rcvr_nr].rx_data[snd_ch]); } else decode_stream_FSK(last,snd_ch,rcvr_nr,emph,DET[emph][rcvr_nr].src_Loop_buf[snd_ch], &DET[emph][rcvr_nr].bit_buf[snd_ch][0], rx_bufsize, &DET[emph][rcvr_nr].rx_data[snd_ch]); } void BPSK_Demodulator(int snd_ch, int rcvr_nr, int emph, int last) { Mux3_PSK(snd_ch, rcvr_nr, emph, DET[0][rcvr_nr].src_BPF_buf[snd_ch], LPF_core[snd_ch], DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], DET[emph][rcvr_nr].prev_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].prev_LPF1Q_buf[snd_ch], LPF_tap[snd_ch], rx_bufsize); if (n_INTR[snd_ch] > 1) { interpolation_PSK(snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], rx_bufsize); decode_stream_BPSK(last, snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], DET[emph][rcvr_nr].bit_buf[snd_ch], rx_bufsize*n_INTR[snd_ch], &DET[emph][rcvr_nr].rx_data[snd_ch]); } else decode_stream_BPSK(last, snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], DET[emph][rcvr_nr].bit_buf[snd_ch], rx_bufsize, &DET[emph][rcvr_nr].rx_data[snd_ch]); } void QPSK_Demodulator(int snd_ch, int rcvr_nr, int emph, int last) { Mux3_PSK(snd_ch, rcvr_nr, emph, DET[0][rcvr_nr].src_BPF_buf[snd_ch], LPF_core[snd_ch], DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], DET[emph][rcvr_nr].prev_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].prev_LPF1Q_buf[snd_ch], LPF_tap[snd_ch], rx_bufsize); if (n_INTR[snd_ch] > 1) { interpolation_PSK(snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], rx_bufsize); decode_stream_QPSK(last, snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], DET[emph][rcvr_nr].bit_buf[snd_ch], rx_bufsize*n_INTR[snd_ch], &DET[emph][rcvr_nr].rx_data[snd_ch]); } else decode_stream_QPSK(last, snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], DET[emph][rcvr_nr].bit_buf[snd_ch], rx_bufsize, &DET[emph][rcvr_nr].rx_data[snd_ch]); } void PSK8_Demodulator(int snd_ch, int rcvr_nr, int emph, boolean last) { Mux3_PSK(snd_ch, rcvr_nr, emph, DET[0][rcvr_nr].src_BPF_buf[snd_ch], LPF_core[snd_ch], DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], DET[emph][rcvr_nr].prev_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].prev_LPF1Q_buf[snd_ch], LPF_tap[snd_ch], rx_bufsize); if (n_INTR[snd_ch] > 1) { interpolation_PSK(snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], rx_bufsize); decode_stream_8PSK(last, snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], DET[emph][rcvr_nr].bit_buf[snd_ch], rx_bufsize*n_INTR[snd_ch], &DET[emph][rcvr_nr].rx_data[snd_ch]); } else decode_stream_8PSK(last, snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], DET[emph][rcvr_nr].bit_buf[snd_ch], rx_bufsize, &DET[emph][rcvr_nr].rx_data[snd_ch]); } void Demodulator(int snd_ch, int rcvr_nr, float * src_buf, int last, int xcenter) { // called once per decoder (current one in rcvr_nr) int i, k; string rec_code; UCHAR emph; int found; string * s_emph; struct TDetector_t * pDET = &DET[0][rcvr_nr]; // looks like this filters to src_BPF_buf FIR_filter(src_buf, rx_bufsize, BPF_tap[snd_ch], pDET->BPF_core[snd_ch], pDET->src_BPF_buf[snd_ch], pDET->prev_BPF_buf[snd_ch]); // AFSK demodulator if (modem_mode[snd_ch] == MODE_FSK) { if (emph_all[snd_ch]) { for (emph = 1; emph <= nr_emph; emph++) FSK_Demodulator(snd_ch, rcvr_nr, emph, FALSE); FSK_Demodulator(snd_ch, rcvr_nr, 0, last); } else FSK_Demodulator(snd_ch, rcvr_nr, emph_db[snd_ch], last); } // BPSK demodulator if (modem_mode[snd_ch] == MODE_BPSK) { if (emph_all[snd_ch]) { for (emph = 1; emph <= nr_emph; emph++) BPSK_Demodulator(snd_ch, rcvr_nr, emph, FALSE); BPSK_Demodulator(snd_ch, rcvr_nr, 0, last); } else BPSK_Demodulator(snd_ch, rcvr_nr, emph_db[snd_ch], last); } // QPSK demodulator if (modem_mode[snd_ch] == MODE_QPSK || modem_mode[snd_ch] == MODE_PI4QPSK) { if (emph_all[snd_ch]) { for (emph = 1; emph <= nr_emph; emph++) QPSK_Demodulator(snd_ch, rcvr_nr, emph, FALSE); QPSK_Demodulator(snd_ch, rcvr_nr, 0, last); } else QPSK_Demodulator(snd_ch, rcvr_nr, emph_db[snd_ch], last); } // 8PSK demodulator if (modem_mode[snd_ch]==MODE_8PSK) { if (emph_all[snd_ch]) { for (emph = 1; emph <= nr_emph; emph++) PSK8_Demodulator(snd_ch, rcvr_nr, emph, FALSE); PSK8_Demodulator(snd_ch, rcvr_nr, 0, last); } else PSK8_Demodulator(snd_ch,rcvr_nr,emph_db[snd_ch],last); } // MPSK demodulator if (modem_mode[snd_ch] == MODE_MPSK) { decode_stream_MPSK(snd_ch, rcvr_nr, DET[0][rcvr_nr].src_BPF_buf[snd_ch], rx_bufsize, last); } // I think this handles multiple decoders and passes packet on to next level // Packet manager if (last) ProcessRXFrames(snd_ch); } void ProcessRXFrames(int snd_ch) { boolean fecflag = 0; char indicators[5] = "-$#F+"; // None, Single, MEM, FEC, Normal // Work out which decoder and which emph settings worked. if (snd_ch < 0 || snd_ch > 3) return; if (detect_list[snd_ch].Count > 0) // no point if nothing decoded { char decoded[32] = ""; char indicators[5] = "-$#F+"; // None, Single, MEM, FEC, Normal char s_emph[4] = ""; int emph[4] = { 0 }; char report[32] = ""; int il2perrors = 255; // The is one DET for each Decoder for each Emph setting struct TDetector_t * pDET; int i = 0, j, found; int maxemph = nr_emph; for (i = 0; i <= nr_emph; i++) { for (j = 0; j <= RCVR[snd_ch] * 2; j++) { pDET = &DET[i][j]; if (pDET->rx_decoded > decoded[j]) // Better than other one (| is higher than F) decoded[j] = pDET->rx_decoded; if (pDET->emph_decoded > emph[i]) emph[i] = pDET->emph_decoded; if (il2perrors > pDET->errors) il2perrors = pDET->errors; pDET->rx_decoded = 0; pDET->emph_decoded = 0; // Ready for next time pDET->errors = 255; } if (emph_all[snd_ch] == 0) break; } decoded[j] = 0; for (j--; j >= 0; j--) decoded[j] = indicators[decoded[j]]; if (emph_all[snd_ch]) { for (i = 0; i <= nr_emph; i++) { s_emph[i] = indicators[emph[i]]; } sprintf(report, "%s][%s", s_emph, decoded); } else strcpy(report, decoded); if (detect_list_c[snd_ch].Items[0]->Length) { if (il2perrors < 255 && il2perrors > 0) sprintf(detect_list_c[snd_ch].Items[0]->Data, "%s-%d", detect_list_c[snd_ch].Items[0]->Data, il2perrors); strcat(report, "]["); strcat(report, detect_list_c[snd_ch].Items[0]->Data); } if (detect_list[snd_ch].Count > 0) { for (i = 0; i < detect_list[snd_ch].Count; i++) { found = 0; // if (detect_list_l[snd_ch].Count > 0) // if (my_indexof(&detect_list_l[snd_ch], detect_list[snd_ch].Items[i]) > -1) // found = 1; if (found == 0) { if (modem_mode[snd_ch] == MODE_MPSK) { // analiz_frame(snd_ch, detect_list[snd_ch].Items[i]->Data, [snd_ch].Items[i]->Data + ' dF: ' + FloatToStrF(DET[0, 0].AFC_dF[snd_ch], ffFixed, 0, 1)); } else { analiz_frame(snd_ch, detect_list[snd_ch].Items[i], report, fecflag); } } } // Cancel FX25 decode if (fx25_mode[snd_ch] != FX25_MODE_NONE) { int e; for (i = 0; i < 16; i++) for (e = 0; e <= nr_emph; e++) DET[e][i].fx25[snd_ch].status = FX25_TAG; } } // Assign(&detect_list_l[snd_ch], &detect_list[snd_ch]); // Duplicate detect_list to detect_list_l Clear(&detect_list[snd_ch]); Clear(&detect_list_c[snd_ch]); } chk_dcd1(snd_ch, rx_bufsize); } string * memory_ARQ(TStringList * buf, string * data) { unsigned char crc[32]; string * s; string * frame; word k, len, i; Byte zeros, ones; TStringList need_frames; s = data; CreateStringList(&need_frames); len = data->Length; memcpy(crc, &data->Data[data->Length - 18], 18); if (buf->Count > 0) { for (i = 0; i < buf->Count; i++) { if (buf->Items[i]->Length == len) if (memcmp(&buf->Items[i]->Data[len - 18], crc, 18) == 0) Add(&need_frames, buf->Items[i]); } } if (need_frames.Count > 2) { for (i = 0; i < len - 18; i++) { zeros = 0; ones = 0; for (k = 0; k < need_frames.Count; k++) { frame = need_frames.Items[k]; if (frame->Data[i] == '1') ones++; else zeros++; } if (ones > zeros) s->Data[i] = '1'; else s->Data[i] = '0'; } } // Clear(&need_frames); return s; }