mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-12 08:47:24 -05:00
747 lines
21 KiB
C
747 lines
21 KiB
C
/*-------------------------------------------------------------------------------
|
|
* m17.c
|
|
* M17 Decoder (WIP)
|
|
*
|
|
* m17_scramble Bit Array from SDR++
|
|
* CRC16 from M17-Implementations (thanks again, sp5wwp)
|
|
*
|
|
* LWVMOBILE
|
|
* 2023-07 DSD-FME Florida Man Edition
|
|
*-----------------------------------------------------------------------------*/
|
|
#include "dsd.h"
|
|
|
|
//try to find a fancy lfsr or calculation for this and not an array if possible
|
|
uint8_t m17_scramble[369] = {
|
|
1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1,
|
|
1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0,
|
|
1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0,
|
|
1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0,
|
|
1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
|
|
1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
|
|
1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
|
|
0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0,
|
|
0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1,
|
|
1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1,
|
|
1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0,
|
|
0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1,
|
|
0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
|
|
0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0,
|
|
1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0,
|
|
0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1,
|
|
1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
|
|
1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1,
|
|
1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1,
|
|
0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,
|
|
0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
|
0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1
|
|
};
|
|
|
|
char b40[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.";
|
|
|
|
uint8_t p1[62] = {
|
|
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1,
|
|
1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1,
|
|
0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1
|
|
};
|
|
|
|
//from M17_Implementations -- sp5wwp -- should have just looked here to begin with
|
|
//this setup looks very similar to the OP25 variant of crc16, but with a few differences (uses packed bytes)
|
|
uint16_t crc16m17(const uint8_t *in, const uint16_t len)
|
|
{
|
|
uint32_t crc = 0xFFFF; //init val
|
|
uint16_t poly = 0x5935;
|
|
for(uint16_t i=0; i<len; i++)
|
|
{
|
|
crc^=in[i]<<8;
|
|
for(uint8_t j=0; j<8; j++)
|
|
{
|
|
crc<<=1;
|
|
if(crc&0x10000)
|
|
crc=(crc^poly)&0xFFFF;
|
|
}
|
|
}
|
|
|
|
return crc&(0xFFFF);
|
|
}
|
|
|
|
void M17decodeCSD(dsd_state * state, unsigned long long int dst, unsigned long long int src)
|
|
{
|
|
//evaluate dst and src, and determine if they need to be converted to calsign
|
|
int i, j;
|
|
char c;
|
|
unsigned long long int value;
|
|
|
|
if (dst == 0xFFFFFFFFFFFF)
|
|
fprintf (stderr, " DST: BROADCAST");
|
|
else if (dst == 0)
|
|
fprintf (stderr, " DST: RESERVED %012llx", dst);
|
|
else if (dst >= 0xEE6B28000000)
|
|
fprintf (stderr, " DST: RESERVED %012llx", dst);
|
|
else
|
|
{
|
|
fprintf (stderr, " DST: ");
|
|
for (i = 0; i < 9; i++)
|
|
{
|
|
c = b40[dst % 40];
|
|
state->m17_dst_csd[i] = c;
|
|
fprintf (stderr, "%c", c);
|
|
dst = dst / 40;
|
|
}
|
|
//assign completed CSD to a more useful string instead
|
|
sprintf (state->m17_dst_str, "%c%c%c%c%c%c%c%c%c",
|
|
state->m17_dst_csd[0], state->m17_dst_csd[1], state->m17_dst_csd[2], state->m17_dst_csd[3],
|
|
state->m17_dst_csd[4], state->m17_dst_csd[5], state->m17_dst_csd[6], state->m17_dst_csd[7], state->m17_dst_csd[8]);
|
|
|
|
//debug
|
|
// fprintf (stderr, "DT: %s", state->m17_dst_str);
|
|
}
|
|
|
|
if (src == 0xFFFFFFFFFFFF)
|
|
fprintf (stderr, " SRC: UNKNOWN FFFFFFFFFFFF");
|
|
else if (src == 0)
|
|
fprintf (stderr, " SRC: RESERVED %012llx", src);
|
|
else if (src >= 0xEE6B28000000)
|
|
fprintf (stderr, " SRC: RESERVED %012llx", src);
|
|
else
|
|
{
|
|
fprintf (stderr, " SRC: ");
|
|
for (i = 0; i < 9; i++)
|
|
{
|
|
c = b40[src % 40];
|
|
state->m17_src_csd[i] = c;
|
|
fprintf (stderr, "%c", c);
|
|
src = src / 40;
|
|
}
|
|
//assign completed CSD to a more useful string instead
|
|
sprintf (state->m17_src_str, "%c%c%c%c%c%c%c%c%c",
|
|
state->m17_src_csd[0], state->m17_src_csd[1], state->m17_src_csd[2], state->m17_src_csd[3],
|
|
state->m17_src_csd[4], state->m17_src_csd[5], state->m17_src_csd[6], state->m17_src_csd[7], state->m17_src_csd[8]);
|
|
|
|
//debug
|
|
// fprintf (stderr, "ST: %s", state->m17_src_str);
|
|
}
|
|
|
|
//debug
|
|
// fprintf (stderr, " DST: %012llX SRC: %012llX", state->m17_dst, state->m17_src);
|
|
|
|
}
|
|
|
|
void M17decodeLSF(dsd_state * state)
|
|
{
|
|
int i;
|
|
|
|
unsigned long long int lsf_dst = (unsigned long long int)ConvertBitIntoBytes(&state->m17_lsf[0], 48);
|
|
unsigned long long int lsf_src = (unsigned long long int)ConvertBitIntoBytes(&state->m17_lsf[48], 48);
|
|
uint16_t lsf_type = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[96], 16);
|
|
|
|
//this is the way the manual/code expects you to read these bits
|
|
uint8_t lsf_ps = (lsf_type >> 0) & 0x1;
|
|
uint8_t lsf_dt = (lsf_type >> 1) & 0x3;
|
|
uint8_t lsf_et = (lsf_type >> 3) & 0x3;
|
|
uint8_t lsf_es = (lsf_type >> 5) & 0x3;
|
|
uint8_t lsf_cn = (lsf_type >> 7) & 0xF;
|
|
uint8_t lsf_rs = (lsf_type >> 11) & 0x1F;
|
|
|
|
//store this so we can reference it for playing voice and/or decoding data, dst/src etc
|
|
state->m17_str_dt = lsf_dt;
|
|
state->m17_dst = lsf_dst;
|
|
state->m17_src = lsf_src;
|
|
|
|
fprintf (stderr, "\n");
|
|
|
|
//packet or stream
|
|
if (lsf_ps == 0) fprintf (stderr, " P-");
|
|
if (lsf_ps == 1) fprintf (stderr, " S-");
|
|
|
|
fprintf (stderr, " CAN: %d", lsf_cn);
|
|
M17decodeCSD(state, lsf_dst, lsf_src);
|
|
|
|
if (lsf_et != 0) fprintf (stderr, " ENC");
|
|
|
|
if (lsf_dt == 0) fprintf (stderr, " Reserved");
|
|
if (lsf_dt == 1) fprintf (stderr, " Data");
|
|
if (lsf_dt == 2) fprintf (stderr, " Voice (3200bps)");
|
|
if (lsf_dt == 3) fprintf (stderr, " Voice + Data");
|
|
|
|
if (lsf_rs != 0) fprintf (stderr, " RS: %02X", lsf_rs);
|
|
|
|
if (lsf_et == 1) fprintf (stderr, " AES-CTR");
|
|
if (lsf_et == 2) fprintf (stderr, " Scrambler - %d", lsf_es);
|
|
|
|
state->m17_enc = lsf_et;
|
|
state->m17_enc_st = lsf_es;
|
|
|
|
//pack meta bits into 14 bytes
|
|
for (i = 0; i < 14; i++)
|
|
state->m17_meta[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[(i*8)+112], 8);
|
|
|
|
//Examine the Meta data
|
|
if (lsf_et == 0 && state->m17_meta[0] != 0) //not sure if this applies universally, or just to text data byte 0 for null data
|
|
{
|
|
fprintf (stderr, " Meta:");
|
|
if (lsf_es == 0) fprintf (stderr, " Text Data");
|
|
if (lsf_es == 1) fprintf (stderr, " GNSS Pos");
|
|
if (lsf_es == 2) fprintf (stderr, " Extended CSD");
|
|
if (lsf_es == 3) fprintf (stderr, " Reserved");
|
|
}
|
|
|
|
if (lsf_et == 1)
|
|
{
|
|
fprintf (stderr, " IV: ");
|
|
for (i = 0; i < 14; i++)
|
|
fprintf (stderr, "%02X", state->m17_meta[i]);
|
|
}
|
|
|
|
}
|
|
|
|
int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t lich_bits[96])
|
|
{
|
|
int i, j, err;
|
|
err = 0;
|
|
|
|
uint8_t lich[4][24];
|
|
uint8_t lich_decoded[48];
|
|
uint8_t temp[96];
|
|
bool g[4];
|
|
|
|
//for testing bit arrangement vs the crc code
|
|
uint8_t bs[240];
|
|
memset(bs, 1, sizeof(bs));
|
|
|
|
uint16_t crc_cmp = 0;
|
|
uint16_t crc_ext = 0;
|
|
uint8_t crc_err = 0;
|
|
|
|
memset(lich, 0, sizeof(lich));
|
|
memset(lich_decoded, 0, sizeof(lich_decoded));
|
|
memset(temp, 0, sizeof(temp));
|
|
|
|
//execute golay 24,12 or 4 24-bit chunks and reorder into 4 12-bit chunks
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
g[i] = TRUE;
|
|
|
|
for (j = 0; j < 24; j++)
|
|
lich[i][j] = lich_bits[(i*24)+j];
|
|
|
|
g[i] = Golay_24_12_decode(lich[i]);
|
|
if(g[i] == FALSE) err = -1;
|
|
|
|
for (j = 0; j < 12; j++)
|
|
lich_decoded[i*12+j] = lich[i][j];
|
|
|
|
}
|
|
|
|
uint8_t lich_counter = (uint8_t)ConvertBitIntoBytes(&lich_decoded[40], 3); //lich_cunt
|
|
uint8_t lich_reserve = (uint8_t)ConvertBitIntoBytes(&lich_decoded[43], 5); //lich_reserved
|
|
|
|
if (err == 0)
|
|
fprintf (stderr, "LC: %d/6 ", lich_counter+1);
|
|
else fprintf (stderr, "LICH G24 ERR");
|
|
|
|
if (err = 0 && lich_reserve != 0) fprintf(stderr, " LRS: %d", lich_reserve);
|
|
|
|
//transfer to storage
|
|
for (i = 0; i < 40; i++)
|
|
state->m17_lsf[lich_counter*40+i] = lich_decoded[i];
|
|
|
|
if (opts->payload == 1)
|
|
{
|
|
fprintf (stderr, " LICH: ");
|
|
for (i = 0; i < 6; i++)
|
|
fprintf (stderr, "[%02X]", (uint8_t)ConvertBitIntoBytes(&lich_decoded[i*8], 8));
|
|
}
|
|
|
|
uint8_t lsf_packed[30];
|
|
memset (lsf_packed, 0, sizeof(lsf_packed));
|
|
|
|
if (lich_counter == 5)
|
|
{
|
|
|
|
//need to pack bytes for the sw5wwp variant of the crc (might as well, may be useful in the future)
|
|
for (i = 0; i < 30; i++)
|
|
lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[i*8], 8);
|
|
|
|
crc_cmp = crc16m17(lsf_packed, 28);
|
|
crc_ext = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[224], 16);
|
|
|
|
if (crc_cmp != crc_ext) crc_err = 1;
|
|
|
|
if (crc_err == 0)
|
|
M17decodeLSF(state);
|
|
|
|
if (opts->payload == 1)
|
|
{
|
|
fprintf (stderr, "\n LSF: ");
|
|
for (i = 0; i < 30; i++)
|
|
{
|
|
if (i == 15) fprintf (stderr, "\n ");
|
|
fprintf (stderr, "[%02X]", lsf_packed[i]);
|
|
}
|
|
}
|
|
|
|
memset (state->m17_lsf, 1, sizeof(state->m17_lsf));
|
|
|
|
//debug
|
|
// fprintf (stderr, " E-%04X; C-%04X (CRC CHK)", crc_ext, crc_cmp);
|
|
|
|
if (crc_err == 1) fprintf (stderr, " EMB LSF CRC ERR");
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t payload[128])
|
|
{
|
|
|
|
//If payload is the same from the stream in this mode, I suppose we could use this area to parse
|
|
//or send off the remaining data to be handled or decoded , or just print out the raw data bytes
|
|
|
|
int i;
|
|
unsigned char voice1[8]; //codec2_bytes_per_frame
|
|
unsigned char voice2[8];
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
voice1[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+0], 8);
|
|
voice2[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+64], 8);
|
|
}
|
|
|
|
//TODO: Add some decryption methods
|
|
if (state->m17_enc != 0)
|
|
{
|
|
//process scrambler or AES-CTR decryption
|
|
//(no AES-CTR right now, Scrambler should be easy enough)
|
|
}
|
|
|
|
if (opts->payload == 1)
|
|
{
|
|
fprintf (stderr, "\n CODEC2: ");
|
|
for (i = 0; i < 8; i++)
|
|
fprintf (stderr, "%02X", voice1[i]);
|
|
fprintf (stderr, " (1600)");
|
|
|
|
fprintf (stderr, "\n LSDATA: "); //low speed data
|
|
for (i = 0; i < 8; i++)
|
|
fprintf (stderr, "%02X", voice2[i]);
|
|
}
|
|
|
|
#ifdef USE_CODEC2
|
|
size_t nsam;
|
|
nsam = 320; //codec2_samples_per_frame(state->codec2_1600);
|
|
|
|
short samp1[nsam];
|
|
// short samp2[nsam];
|
|
memset (samp1, 0, sizeof(samp1));
|
|
// memset (samp2, 0, sizeof(samp2));
|
|
|
|
|
|
codec2_decode(state->codec2_1600, samp1, voice1);
|
|
// codec2_decode(state->codec2_1600, samp2, voice2);
|
|
|
|
|
|
if (opts->audio_out_type == 0 && state->m17_enc == 0)
|
|
{
|
|
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
|
// pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL);
|
|
}
|
|
|
|
if (opts->audio_out_type == 5 && state->m17_enc == 0)
|
|
{
|
|
write (opts->audio_out_fd, samp1, nsam*2);
|
|
// write (opts->audio_out_fd, samp2, nsam*2);
|
|
}
|
|
|
|
//WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history
|
|
if(opts->wav_out_f != NULL && state->m17_enc == 0)
|
|
{
|
|
sf_write_short(opts->wav_out_f, samp1, nsam);
|
|
// sf_write_short(opts->wav_out_f, samp2, nsam);
|
|
}
|
|
|
|
//TODO: Codec2 Raw file saving
|
|
// if(mbe_out_dir)
|
|
// {
|
|
|
|
// }
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t payload[128])
|
|
{
|
|
int i;
|
|
unsigned char voice1[8]; //codec2_bytes_per_frame
|
|
unsigned char voice2[8];
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
voice1[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+0], 8);
|
|
voice2[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+64], 8);
|
|
}
|
|
|
|
//TODO: Add some decryption methods
|
|
if (state->m17_enc != 0)
|
|
{
|
|
//process scrambler or AES-CTR decryption
|
|
//(no AES-CTR right now, Scrambler should be easy enough)
|
|
}
|
|
|
|
if (opts->payload == 1)
|
|
{
|
|
fprintf (stderr, "\n CODEC2: ");
|
|
for (i = 0; i < 8; i++)
|
|
fprintf (stderr, "%02X", voice1[i]);
|
|
fprintf (stderr, " (3200)");
|
|
|
|
fprintf (stderr, "\n CODEC2: ");
|
|
for (i = 0; i < 8; i++)
|
|
fprintf (stderr, "%02X", voice2[i]);
|
|
fprintf (stderr, " (3200)");
|
|
}
|
|
|
|
#ifdef USE_CODEC2
|
|
size_t nsam;
|
|
nsam = 160; //codec2_samples_per_frame(state->codec2_3200);
|
|
|
|
short samp1[nsam];
|
|
short samp2[nsam];
|
|
memset (samp1, 0, sizeof(samp1));
|
|
memset (samp2, 0, sizeof(samp2));
|
|
|
|
|
|
codec2_decode(state->codec2_3200, samp1, voice1);
|
|
codec2_decode(state->codec2_3200, samp2, voice2);
|
|
|
|
|
|
if (opts->audio_out_type == 0 && state->m17_enc == 0)
|
|
{
|
|
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
|
pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL);
|
|
}
|
|
|
|
if (opts->audio_out_type == 5 && state->m17_enc == 0)
|
|
{
|
|
write (opts->audio_out_fd, samp1, nsam*2);
|
|
write (opts->audio_out_fd, samp2, nsam*2);
|
|
}
|
|
|
|
//WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history
|
|
if(opts->wav_out_f != NULL && state->m17_enc == 0)
|
|
{
|
|
sf_write_short(opts->wav_out_f, samp1, nsam);
|
|
sf_write_short(opts->wav_out_f, samp2, nsam);
|
|
}
|
|
|
|
//TODO: Codec2 Raw file saving
|
|
// if(mbe_out_dir)
|
|
// {
|
|
|
|
// }
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t m17_bits[368])
|
|
{
|
|
|
|
int i, j, k, x;
|
|
uint8_t m17_punc[310]; //25 * 11 = 275
|
|
memset (m17_punc, 0, sizeof(m17_punc));
|
|
for (i = 0; i < 272; i++)
|
|
m17_punc[i] = m17_bits[i+96];
|
|
|
|
//depuncture the bits
|
|
uint8_t m17_depunc[310]; //25 * 12 = 300
|
|
memset (m17_depunc, 0, sizeof(m17_depunc));
|
|
k = 0; x = 0;
|
|
for (i = 0; i < 25; i++)
|
|
{
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = m17_punc[x++];
|
|
m17_depunc[k++] = 0;
|
|
}
|
|
|
|
//setup the convolutional decoder
|
|
uint8_t temp[300];
|
|
uint8_t s0;
|
|
uint8_t s1;
|
|
uint8_t m_data[28];
|
|
uint8_t trellis_buf[400];
|
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
|
memset (temp, 0, sizeof (temp));
|
|
memset (m_data, 0, sizeof (m_data));
|
|
|
|
for (i = 0; i < 296; i++)
|
|
temp[i] = m17_depunc[i] << 1;
|
|
|
|
CNXDNConvolution_start();
|
|
for (i = 0; i < 148; i++)
|
|
{
|
|
s0 = temp[(2*i)];
|
|
s1 = temp[(2*i)+1];
|
|
|
|
CNXDNConvolution_decode(s0, s1);
|
|
}
|
|
|
|
CNXDNConvolution_chainback(m_data, 144);
|
|
|
|
//144/8 = 18, last 4 (144-148) are trailing zeroes
|
|
for(i = 0; i < 18; i++)
|
|
{
|
|
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
|
|
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
|
|
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
|
|
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
|
|
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
|
|
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
|
|
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
|
|
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
|
|
}
|
|
|
|
//load m_data into bits for either data packets or voice packets
|
|
uint8_t payload[128];
|
|
uint8_t end = 9;
|
|
uint16_t fn = 0;
|
|
memset (payload, 0, sizeof(payload));
|
|
|
|
end = trellis_buf[0];
|
|
fn = (uint16_t)ConvertBitIntoBytes(&trellis_buf[1], 15);
|
|
|
|
if (opts->payload == 1)
|
|
fprintf (stderr, " FSN: %05d", fn);
|
|
|
|
if (end == 1)
|
|
fprintf (stderr, " END;");
|
|
|
|
for (i = 0; i < 128; i++)
|
|
payload[i] = trellis_buf[i+16];
|
|
|
|
if (state->m17_str_dt == 2)
|
|
M17processCodec2_3200(opts, state, payload);
|
|
else if (state->m17_str_dt == 3)
|
|
M17processCodec2_1600(opts, state, payload);
|
|
else if (state->m17_str_dt == 1) fprintf (stderr, " DATA;");
|
|
else if (state->m17_str_dt == 0) fprintf (stderr, " RES;");
|
|
// else fprintf (stderr, " UNK;");
|
|
|
|
if (opts->payload == 1 && state->m17_str_dt < 2)
|
|
{
|
|
fprintf (stderr, "\n STREAM: ");
|
|
for (i = 0; i < 18; i++)
|
|
fprintf (stderr, "[%02X]", (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8));
|
|
}
|
|
|
|
}
|
|
|
|
void processM17STR(dsd_opts * opts, dsd_state * state)
|
|
{
|
|
|
|
int i, x;
|
|
|
|
//NOTE: adding more space for dbuf seems to fix the memory issue, but I don't think this is
|
|
//the culprit, not entirely sure what is going on here, but the issue with Cygwin (32-bit)
|
|
//not working at all with this also is fixed by this and I can't seem to figure out why
|
|
//its probably something really dumb that I am completely blind on seeing here for some reason
|
|
|
|
|
|
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
|
|
uint8_t m17_rnd_bits[368]; //368 bits that are still scrambled (randomized)
|
|
uint8_t m17_int_bits[368]; //368 bits that are still interleaved
|
|
uint8_t m17_bits[368]; //368 bits that have been de-interleaved and de-scramble
|
|
uint8_t lich_bits[96];
|
|
int lich_err = -1;
|
|
|
|
memset (dbuf, 0, sizeof(dbuf));
|
|
memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits));
|
|
memset (m17_int_bits, 0, sizeof(m17_int_bits));
|
|
memset (m17_bits, 0, sizeof(m17_bits));
|
|
memset (lich_bits, 0, sizeof(lich_bits));
|
|
|
|
//load dibits into dibit buffer
|
|
for (i = 0; i < 184; i++)
|
|
dbuf[i] = (uint8_t) getDibit(opts, state);
|
|
|
|
//convert dbuf into a bit array
|
|
for (i = 0; i < 184; i++)
|
|
{
|
|
m17_rnd_bits[i*2+0] = (dbuf[i] >> 1) & 1;
|
|
m17_rnd_bits[i*2+1] = (dbuf[i] >> 0) & 1;
|
|
}
|
|
|
|
//descramble the frame
|
|
for (i = 0; i < 368; i++)
|
|
m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1;
|
|
|
|
//deinterleave the bit array using Quadratic Permutation Polynomial
|
|
//function π(x) = (45x + 92x^2 ) mod 368
|
|
for (i = 0; i < 368; i++)
|
|
{
|
|
x = ((45*i)+(92*i*i)) % 368;
|
|
m17_bits[i] = m17_int_bits[x];
|
|
}
|
|
|
|
for (i = 0; i < 96; i++)
|
|
lich_bits[i] = m17_bits[i];
|
|
|
|
//check lich first, and handle LSF chunk and completed LSF
|
|
lich_err = M17processLICH(state, opts, lich_bits);
|
|
|
|
if (lich_err == 0)
|
|
M17prepareStream(opts, state, m17_bits);
|
|
|
|
// if (lich_err != 0) state->lastsynctype = -1; //disable
|
|
|
|
//ending linebreak
|
|
fprintf (stderr, "\n");
|
|
|
|
} //end processM17STR
|
|
|
|
void processM17LSF(dsd_opts * opts, dsd_state * state)
|
|
{
|
|
|
|
//NOTE1: Pretty sure the flow here is all correct, but the initial (and only)
|
|
//LSF frame is demodulated incorrectly, so more than likely, this frame will
|
|
//always be bad since there is only one sent before STR
|
|
|
|
//NOTE2: Even with the preamble detection and LSF sync, we still get bad decode on this
|
|
|
|
int i, j, k, x;
|
|
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
|
|
uint8_t m17_rnd_bits[500]; //368 bits that are still scrambled (randomized)
|
|
uint8_t m17_int_bits[500]; //368 bits that are still interleaved
|
|
uint8_t m17_bits[500]; //368 bits that have been de-interleaved and de-scramble
|
|
uint8_t m17_depunc[500]; //488 bits after depuncturing
|
|
|
|
memset (dbuf, 0, sizeof(dbuf));
|
|
memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits));
|
|
memset (m17_int_bits, 0, sizeof(m17_int_bits));
|
|
memset (m17_bits, 0, sizeof(m17_bits));
|
|
memset (m17_depunc, 0, sizeof(m17_depunc));
|
|
|
|
//load dibits into dibit buffer
|
|
for (i = 0; i < 184; i++)
|
|
dbuf[i] = (uint8_t) getDibit(opts, state);
|
|
|
|
//convert dbuf into a bit array
|
|
for (i = 0; i < 184; i++)
|
|
{
|
|
m17_rnd_bits[i*2+0] = (dbuf[i] >> 1) & 1;
|
|
m17_rnd_bits[i*2+1] = (dbuf[i] >> 0) & 1;
|
|
}
|
|
|
|
//descramble the frame
|
|
for (i = 0; i < 368; i++)
|
|
m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1;
|
|
|
|
//deinterleave the bit array using Quadratic Permutation Polynomial
|
|
//function π(x) = (45x + 92x^2 ) mod 368
|
|
for (i = 0; i < 368; i++)
|
|
{
|
|
x = ((45*i)+(92*i*i)) % 368;
|
|
m17_bits[i] = m17_int_bits[x];
|
|
}
|
|
|
|
j = 0; k = 0; x = 0;
|
|
|
|
// P1 Depuncture
|
|
for (i = 0; i < 488; i++)
|
|
{
|
|
if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++];
|
|
else m17_depunc[x++] = 1;
|
|
|
|
if (k == 61) k = 0; //61 -- should reset 8 times againt the array
|
|
|
|
}
|
|
|
|
//debug -- values seem okay at end of run
|
|
// fprintf (stderr, "K = %d; J = %d; X = %d", k, j, x);
|
|
|
|
//setup the convolutional decoder
|
|
uint8_t temp[500];
|
|
uint8_t s0;
|
|
uint8_t s1;
|
|
uint8_t m_data[32];
|
|
uint8_t trellis_buf[400];
|
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
|
memset (temp, 0, sizeof (temp));
|
|
memset (m_data, 0, sizeof (m_data));
|
|
|
|
for (i = 0; i < 488; i++)
|
|
temp[i] = m17_depunc[i] << 1;
|
|
|
|
CNXDNConvolution_start();
|
|
for (i = 0; i < 244; i++)
|
|
{
|
|
s0 = temp[(2*i)];
|
|
s1 = temp[(2*i)+1];
|
|
|
|
CNXDNConvolution_decode(s0, s1);
|
|
}
|
|
|
|
CNXDNConvolution_chainback(m_data, 240);
|
|
|
|
//244/8 = 30, last 4 (244-248) are trailing zeroes
|
|
for(i = 0; i < 30; i++)
|
|
{
|
|
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
|
|
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
|
|
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
|
|
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
|
|
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
|
|
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
|
|
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
|
|
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
|
|
}
|
|
|
|
memset (state->m17_lsf, 0, sizeof(state->m17_lsf));
|
|
memcpy (state->m17_lsf, trellis_buf, 240);
|
|
|
|
uint8_t lsf_packed[30];
|
|
memset (lsf_packed, 0, sizeof(lsf_packed));
|
|
|
|
//need to pack bytes for the sw5wwp variant of the crc (might as well, may be useful in the future)
|
|
for (i = 0; i < 30; i++)
|
|
lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[i*8], 8);
|
|
|
|
uint16_t crc_cmp = crc16m17(lsf_packed, 28);
|
|
uint16_t crc_ext = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[224], 16);
|
|
int crc_err = 0;
|
|
|
|
if (crc_cmp != crc_ext) crc_err = 1;
|
|
|
|
if (crc_err == 0)
|
|
M17decodeLSF(state);
|
|
|
|
if (opts->payload == 1)
|
|
{
|
|
fprintf (stderr, "\n LSF: ");
|
|
for (i = 0; i < 30; i++)
|
|
{
|
|
if (i == 15) fprintf (stderr, "\n ");
|
|
fprintf (stderr, "[%02X]", lsf_packed[i]);
|
|
}
|
|
}
|
|
|
|
//debug
|
|
// fprintf (stderr, " E-%04X; C-%04X (CRC CHK)", crc_ext, crc_cmp);
|
|
|
|
if (crc_err == 1) fprintf (stderr, " CRC ERR");
|
|
|
|
//ending linebreak
|
|
fprintf (stderr, "\n");
|
|
|
|
} //end processM17LSF
|