Some much needed organization

This commit is contained in:
Jared Szechy
2015-08-06 12:25:30 -04:00
parent 6fbda52998
commit 6605925162
60 changed files with 7 additions and 6 deletions

83
src/Hamming.cpp Normal file
View File

@@ -0,0 +1,83 @@
#include "Hamming.hpp"
// definition outside class declaration
Hamming_10_6_3_data Hamming_10_6_3::data;
// definition outside class declaration
// Should go *after* Hamming_10_6_3_data since Hamming_10_6_3_TableImpl_data constructor uses
// Hamming_10_6_3 which in its turn depends on Hamming_10_6_3_data
Hamming_10_6_3_TableImpl_data Hamming_10_6_3_TableImpl::data;
int Hamming_10_6_3::decode(std::bitset<10>& input)
{
int error_count;
// Compute syndromes
int s0 = ((data.h0 & input).count() & 1) << 3;
int s1 = ((data.h1 & input).count() & 1) << 2;
int s2 = ((data.h2 & input).count() & 1) << 1;
int s3 = ((data.h3 & input).count() & 1);
int parity = s0 | s1 | s2 | s3;
if (parity == 0) {
//std::cout << input << " is OK" << std::endl;
error_count = 0;
} else {
// Error detected, attempt to fix it
int bad_bit_index = data.bad_bit_table[parity];
if (bad_bit_index < 0) {
//std::cout << "Irrecoverable error: " << std::bitset<6>(input.to_string()) << std::endl;
error_count = 2;
} else {
// Error in a data bit, or more than one error
// If there is one erroneous bit, the bad one is the one indicated by parity
if (bad_bit_index < 4) {
// Error detected in a parity bit
//std::cout << "Error on parity bit " << bad_bit_index << std::endl;
error_count = 1;
} else {
input.flip(bad_bit_index);
//std::cout << "Error on data bit " << bad_bit_index << ", hopefully fixed: " << std::bitset<6>(input.to_string()) << std::endl;
error_count = 1;
}
}
}
//std::cout << std::endl;
return error_count;
}
int Hamming_10_6_3::encode(std::bitset<6>& input)
{
// Compute syndromes
int s0 = ((data.gt0 & input).count() & 1) << 3;
int s1 = ((data.gt1 & input).count() & 1) << 2;
int s2 = ((data.gt2 & input).count() & 1) << 1;
int s3 = ((data.gt3 & input).count() & 1);
int parity = s0 | s1 | s2 | s3;
return parity;
}
int Hamming_10_6_3_TableImpl::decode(int input, int* output)
{
assert (input < 1024 && input >= 0);
// Making use of a table...
*output = data.fixed_values[input];
return data.error_counts[input];
}
int Hamming_10_6_3_TableImpl::encode(int input)
{
assert (input < 64 && input >= 0);
// Making use of a table...
return data.encode_parities[input];
}

240
src/dmr_data.c Normal file
View File

@@ -0,0 +1,240 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
void
processDMRdata (dsd_opts * opts, dsd_state * state)
{
int i, dibit;
int *dibit_p;
char sync[25];
char syncdata[25];
char cachdata[13];
char cc[5];
char bursttype[5];
#ifdef DMR_DUMP
int k;
char syncbits[49];
char cachbits[25];
#endif
cc[4] = 0;
bursttype[4] = 0;
dibit_p = state->dibit_buf_p - 90;
// CACH
for (i = 0; i < 12; i++)
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
cachdata[i] = dibit;
if (i == 2)
{
state->currentslot = (1 & (dibit >> 1)); // bit 1
if (state->currentslot == 0)
{
state->slot0light[0] = '[';
state->slot0light[6] = ']';
state->slot1light[0] = ' ';
state->slot1light[6] = ' ';
}
else
{
state->slot1light[0] = '[';
state->slot1light[6] = ']';
state->slot0light[0] = ' ';
state->slot0light[6] = ' ';
}
}
}
cachdata[12] = 0;
#ifdef DMR_DUMP
k = 0;
for (i = 0; i < 12; i++)
{
dibit = cachdata[i];
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
cachbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
cachbits[24] = 0;
printf ("%s ", cachbits);
#endif
// current slot
dibit_p += 49;
// slot type
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
cc[0] = (1 & (dibit >> 1)) + 48; // bit 1
cc[1] = (1 & dibit) + 48; // bit 0
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
cc[2] = (1 & (dibit >> 1)) + 48; // bit 1
cc[3] = (1 & dibit) + 48; // bit 0
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
bursttype[0] = (1 & (dibit >> 1)) + 48; // bit 1
bursttype[1] = (1 & dibit) + 48; // bit 0
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
bursttype[2] = (1 & (dibit >> 1)) + 48; // bit 1
bursttype[3] = (1 & dibit) + 48; // bit 0
// parity bit
dibit_p++;
if (strcmp (bursttype, "0000") == 0)
{
sprintf (state->fsubtype, " PI Header ");
}
else if (strcmp (bursttype, "0001") == 0)
{
sprintf (state->fsubtype, " VOICE Header ");
}
else if (strcmp (bursttype, "0010") == 0)
{
sprintf (state->fsubtype, " TLC ");
}
else if (strcmp (bursttype, "0011") == 0)
{
sprintf (state->fsubtype, " CSBK ");
}
else if (strcmp (bursttype, "0100") == 0)
{
sprintf (state->fsubtype, " MBC Header ");
}
else if (strcmp (bursttype, "0101") == 0)
{
sprintf (state->fsubtype, " MBC ");
}
else if (strcmp (bursttype, "0110") == 0)
{
sprintf (state->fsubtype, " DATA Header ");
}
else if (strcmp (bursttype, "0111") == 0)
{
sprintf (state->fsubtype, " RATE 1/2 DATA");
}
else if (strcmp (bursttype, "1000") == 0)
{
sprintf (state->fsubtype, " RATE 3/4 DATA");
}
else if (strcmp (bursttype, "1001") == 0)
{
sprintf (state->fsubtype, " Slot idle ");
}
else if (strcmp (bursttype, "1010") == 0)
{
sprintf (state->fsubtype, " Rate 1 DATA ");
}
else
{
sprintf (state->fsubtype, " ");
}
// signaling data or sync
for (i = 0; i < 24; i++)
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
syncdata[i] = dibit;
sync[i] = (dibit | 1) + 48;
}
sync[24] = 0;
syncdata[24] = 0;
#ifdef DMR_DUMP
k = 0;
for (i = 0; i < 24; i++)
{
dibit = syncdata[i];
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
syncbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
syncbits[48] = 0;
printf ("%s ", syncbits);
#endif
if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
{
if (state->currentslot == 0)
{
sprintf (state->slot0light, "[slot0]");
}
else
{
sprintf (state->slot1light, "[slot1]");
}
}
if (opts->errorbars == 1)
{
printf ("%s %s ", state->slot0light, state->slot1light);
}
// current slot second half, cach, next slot 1st half
skipDibit (opts, state, 120);
if (opts->errorbars == 1)
{
if (strcmp (state->fsubtype, " ") == 0)
{
printf (" Unknown burst type: %s\n", bursttype);
}
else
{
printf ("%s\n", state->fsubtype);
}
}
}

382
src/dmr_voice.c Normal file
View File

@@ -0,0 +1,382 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
#include "dmr_const.h"
void
processDMRvoice (dsd_opts * opts, dsd_state * state)
{
// extracts AMBE frames from DMR frame
int i, j, dibit;
int *dibit_p;
char ambe_fr[4][24];
char ambe_fr2[4][24];
char ambe_fr3[4][24];
const int *w, *x, *y, *z;
char sync[25];
char syncdata[25];
char cachdata[13];
int mutecurrentslot;
int msMode;
#ifdef DMR_DUMP
int k;
char syncbits[49];
char cachbits[25];
#endif
mutecurrentslot = 0;
msMode = 0;
dibit_p = state->dibit_buf_p - 144;
for (j = 0; j < 6; j++)
{
// 2nd half of previous slot
for (i = 0; i < 54; i++)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
}
// CACH
for (i = 0; i < 12; i++)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
cachdata[i] = dibit;
if (i == 2)
{
state->currentslot = (1 & (dibit >> 1)); // bit 1
if (state->currentslot == 0)
{
state->slot0light[0] = '[';
state->slot0light[6] = ']';
state->slot1light[0] = ' ';
state->slot1light[6] = ' ';
}
else
{
state->slot1light[0] = '[';
state->slot1light[6] = ']';
state->slot0light[0] = ' ';
state->slot0light[6] = ' ';
}
}
}
cachdata[12] = 0;
#ifdef DMR_DUMP
k = 0;
for (i = 0; i < 12; i++)
{
dibit = cachdata[i];
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
cachbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
cachbits[24] = 0;
printf ("%s ", cachbits);
#endif
// current slot frame 1
w = rW;
x = rX;
y = rY;
z = rZ;
for (i = 0; i < 36; i++)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
// current slot frame 2 first half
w = rW;
x = rX;
y = rY;
z = rZ;
for (i = 0; i < 18; i++)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
// signaling data or sync
for (i = 0; i < 24; i++)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
syncdata[i] = dibit;
sync[i] = (dibit | 1) + 48;
}
sync[24] = 0;
syncdata[24] = 0;
if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
{
mutecurrentslot = 1;
if (state->currentslot == 0)
{
sprintf (state->slot0light, "[slot0]");
}
else
{
sprintf (state->slot1light, "[slot1]");
}
}
else if ((strcmp (sync, DMR_BS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_VOICE_SYNC) == 0))
{
mutecurrentslot = 0;
if (state->currentslot == 0)
{
sprintf (state->slot0light, "[SLOT0]");
}
else
{
sprintf (state->slot1light, "[SLOT1]");
}
}
if ((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
{
msMode = 1;
}
if ((j == 0) && (opts->errorbars == 1))
{
printf ("%s %s VOICE e:", state->slot0light, state->slot1light);
}
#ifdef DMR_DUMP
k = 0;
for (i = 0; i < 24; i++)
{
dibit = syncdata[i];
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
syncbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
syncbits[48] = 0;
printf ("%s ", syncbits);
#endif
// current slot frame 2 second half
for (i = 0; i < 18; i++)
{
dibit = getDibit (opts, state);
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
if (mutecurrentslot == 0)
{
if (state->firstframe == 1)
{ // we don't know if anything received before the first sync after no carrier is valid
state->firstframe = 0;
}
else
{
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
}
}
// current slot frame 3
w = rW;
x = rX;
y = rY;
z = rZ;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
if (mutecurrentslot == 0)
{
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
}
// CACH
for (i = 0; i < 12; i++)
{
dibit = getDibit (opts, state);
cachdata[i] = dibit;
}
cachdata[12] = 0;
#ifdef DMR_DUMP
k = 0;
for (i = 0; i < 12; i++)
{
dibit = cachdata[i];
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
cachbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
cachbits[24] = 0;
printf ("%s ", cachbits);
#endif
// next slot
skipDibit (opts, state, 54);
// signaling data or sync
for (i = 0; i < 24; i++)
{
dibit = getDibit (opts, state);
syncdata[i] = dibit;
sync[i] = (dibit | 1) + 48;
}
sync[24] = 0;
syncdata[24] = 0;
if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (msMode == 1))
{
if (state->currentslot == 0)
{
sprintf (state->slot1light, " slot1 ");
}
else
{
sprintf (state->slot0light, " slot0 ");
}
}
else if (strcmp (sync, DMR_BS_VOICE_SYNC) == 0)
{
if (state->currentslot == 0)
{
sprintf (state->slot1light, " SLOT1 ");
}
else
{
sprintf (state->slot0light, " SLOT0 ");
}
}
#ifdef DMR_DUMP
k = 0;
for (i = 0; i < 24; i++)
{
dibit = syncdata[i];
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
syncbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
syncbits[48] = 0;
printf ("%s ", syncbits);
#endif
if (j == 5)
{
// 2nd half next slot
skipDibit (opts, state, 54);
// CACH
skipDibit (opts, state, 12);
// first half current slot
skipDibit (opts, state, 54);
}
}
if (opts->errorbars == 1)
{
printf ("\n");
}
}

620
src/dsd_audio.c Normal file
View File

@@ -0,0 +1,620 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
void
processAudio (dsd_opts * opts, dsd_state * state)
{
int i, n;
float aout_abs, max, gainfactor, gaindelta, maxbuf;
if (opts->audio_gain == (float) 0)
{
// detect max level
max = 0;
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
for (n = 0; n < 160; n++)
{
aout_abs = fabsf (*state->audio_out_temp_buf_p);
if (aout_abs > max)
{
max = aout_abs;
}
state->audio_out_temp_buf_p++;
}
*state->aout_max_buf_p = max;
state->aout_max_buf_p++;
state->aout_max_buf_idx++;
if (state->aout_max_buf_idx > 24)
{
state->aout_max_buf_idx = 0;
state->aout_max_buf_p = state->aout_max_buf;
}
// lookup max history
for (i = 0; i < 25; i++)
{
maxbuf = state->aout_max_buf[i];
if (maxbuf > max)
{
max = maxbuf;
}
}
// determine optimal gain level
if (max > (float) 0)
{
gainfactor = ((float) 30000 / max);
}
else
{
gainfactor = (float) 50;
}
if (gainfactor < state->aout_gain)
{
state->aout_gain = gainfactor;
gaindelta = (float) 0;
}
else
{
if (gainfactor > (float) 50)
{
gainfactor = (float) 50;
}
gaindelta = gainfactor - state->aout_gain;
if (gaindelta > ((float) 0.05 * state->aout_gain))
{
gaindelta = ((float) 0.05 * state->aout_gain);
}
}
gaindelta /= (float) 160;
}
else
{
gaindelta = (float) 0;
}
if(opts->audio_gain >= 0)
{
// adjust output gain
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
for (n = 0; n < 160; n++)
{
*state->audio_out_temp_buf_p = (state->aout_gain + ((float) n * gaindelta)) * (*state->audio_out_temp_buf_p);
state->audio_out_temp_buf_p++;
}
state->aout_gain += ((float) 160 * gaindelta);
}
// copy audio data to output buffer and upsample if necessary
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
if (opts->split == 0)
{
for (n = 0; n < 160; n++)
{
upsample (state, *state->audio_out_temp_buf_p);
state->audio_out_temp_buf_p++;
state->audio_out_float_buf_p += 6;
state->audio_out_idx += 6;
state->audio_out_idx2 += 6;
}
state->audio_out_float_buf_p -= (960 + opts->playoffset);
// copy to output (short) buffer
for (n = 0; n < 960; n++)
{
if (*state->audio_out_float_buf_p > 32767.0F)
{
*state->audio_out_float_buf_p = 32767.0F;
}
else if (*state->audio_out_float_buf_p < -32768.0F)
{
*state->audio_out_float_buf_p = -32768.0F;
}
*state->audio_out_buf_p = (short) *state->audio_out_float_buf_p;
state->audio_out_buf_p++;
state->audio_out_float_buf_p++;
}
state->audio_out_float_buf_p += opts->playoffset;
}
else
{
for (n = 0; n < 160; n++)
{
if (*state->audio_out_temp_buf_p > 32767.0F)
{
*state->audio_out_temp_buf_p = 32767.0F;
}
else if (*state->audio_out_temp_buf_p < -32768.0F)
{
*state->audio_out_temp_buf_p = -32768.0F;
}
*state->audio_out_buf_p = (short) *state->audio_out_temp_buf_p;
state->audio_out_buf_p++;
state->audio_out_temp_buf_p++;
state->audio_out_idx++;
state->audio_out_idx2++;
}
}
}
void
writeSynthesizedVoice (dsd_opts * opts, dsd_state * state)
{
int n;
short aout_buf[160];
short *aout_buf_p;
// for(n=0; n<160; n++)
// printf("%d ", ((short*)(state->audio_out_temp_buf))[n]);
// printf("\n");
aout_buf_p = aout_buf;
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
for (n = 0; n < 160; n++)
{
if (*state->audio_out_temp_buf_p > (float) 32767)
{
*state->audio_out_temp_buf_p = (float) 32767;
}
else if (*state->audio_out_temp_buf_p < (float) -32768)
{
*state->audio_out_temp_buf_p = (float) -32768;
}
*aout_buf_p = (short) *state->audio_out_temp_buf_p;
aout_buf_p++;
state->audio_out_temp_buf_p++;
}
sf_write_short(opts->wav_out_f, aout_buf, 160);
/*
int n;
short aout_buf[160];
short *aout_buf_p;
ssize_t result;
aout_buf_p = aout_buf;
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
for (n = 0; n < 160; n++)
{
if (*state->audio_out_temp_buf_p > (float) 32760)
{
*state->audio_out_temp_buf_p = (float) 32760;
}
else if (*state->audio_out_temp_buf_p < (float) -32760)
{
*state->audio_out_temp_buf_p = (float) -32760;
}
*aout_buf_p = (short) *state->audio_out_temp_buf_p;
aout_buf_p++;
state->audio_out_temp_buf_p++;
}
result = write (opts->wav_out_fd, aout_buf, 320);
fflush (opts->wav_out_f);
state->wav_out_bytes += 320;
*/
}
void
playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
{
ssize_t result;
if (state->audio_out_idx > opts->delay)
{
// output synthesized speech to sound card
if(opts->audio_out_type == 2)
{
#ifdef USE_PORTAUDIO
PaError err = paNoError;
do
{
long available = Pa_GetStreamWriteAvailable( opts->audio_out_pa_stream );
if(available < 0)
err = available;
//printf("Frames available: %d\n", available);
if( err != paNoError )
break;
if(available > SAMPLE_RATE_OUT * PA_LATENCY_OUT)
{
//It looks like this might not be needed for very small latencies. However, it's definitely needed for a bit larger ones.
//When PA_LATENCY_OUT == 0.500 I get output buffer underruns if I don't use this. With PA_LATENCY_OUT <= 0.100 I don't see those happen.
//But with PA_LATENCY_OUT < 0.100 I run the risk of choppy audio and stream errors.
printf("\nSyncing voice output stream\n");
err = Pa_StopStream( opts->audio_out_pa_stream );
if( err != paNoError )
break;
}
err = Pa_IsStreamActive( opts->audio_out_pa_stream );
if(err == 0)
{
printf("Start voice output stream\n");
err = Pa_StartStream( opts->audio_out_pa_stream );
}
else if(err == 1)
{
err = paNoError;
}
if( err != paNoError )
break;
//printf("write stream %d\n", state->audio_out_idx);
err = Pa_WriteStream( opts->audio_out_pa_stream, (state->audio_out_buf_p - state->audio_out_idx), state->audio_out_idx );
if( err != paNoError )
break;
} while(0);
if( err != paNoError )
{
fprintf( stderr, "An error occured while using the portaudio output stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
#endif
}
else
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
state->audio_out_idx = 0;
}
if (state->audio_out_idx2 >= 800000)
{
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
state->audio_out_buf_p = state->audio_out_buf + 100;
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
memset (state->audio_out_buf, 0, 100 * sizeof (short));
state->audio_out_idx2 = 0;
}
}
#ifdef USE_PORTAUDIO
int getPADevice(char* dev, int input, PaStream** stream)
{
int devnum = atoi(dev + 3);
printf("Using portaudio device %d.\n", devnum);
PaError err;
int numDevices = Pa_GetDeviceCount();
if( numDevices < 0 )
{
printf( "ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices );
err = numDevices;
goto error;
}
if( devnum >= numDevices)
{
printf( "ERROR: Requested device %d is larger than number of devices.\n", devnum );
return(1);
}
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( devnum );
/* print device name */
#ifdef WIN32
{ /* Use wide char on windows, so we can show UTF-8 encoded device names */
wchar_t wideName[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, deviceInfo->name, -1, wideName, MAX_PATH-1);
wprintf( L"Name = %s\n", wideName );
}
#else
printf( "Name = %s\n", deviceInfo->name );
#endif
if((input == 1) && (deviceInfo->maxInputChannels == 0))
{
printf( "ERROR: Requested device %d is not an input device.\n", devnum );
return(1);
}
if((input == 0) && (deviceInfo->maxOutputChannels == 0))
{
printf( "ERROR: Requested device %d is not an output device.\n", devnum );
return(1);
}
//Create stream parameters
PaStreamParameters parameters;
parameters.device = devnum;
parameters.channelCount = 1; /* mono */
parameters.sampleFormat = paInt16; //Shorts
parameters.suggestedLatency = (input == 1) ? PA_LATENCY_IN : PA_LATENCY_OUT;
parameters.hostApiSpecificStreamInfo = NULL;
//Open stream
err = Pa_OpenStream(
stream,
(input == 1) ? &parameters : NULL,
(input == 0) ? &parameters : NULL,
(input == 1) ? SAMPLE_RATE_IN : SAMPLE_RATE_OUT,
PA_FRAMES_PER_BUFFER,
paClipOff,
NULL /*callback*/,
NULL );
if( err != paNoError ) goto error;
return 0;
error:
fprintf( stderr, "An error occured while initializing a portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err;
}
#endif
void
openAudioOutDevice (dsd_opts * opts, int speed)
{
// get info of device/file
if(strncmp(opts->audio_out_dev, "pa:", 3) == 0)
{
opts->audio_out_type = 2;
#ifdef USE_PORTAUDIO
int err = getPADevice(opts->audio_out_dev, 0, &opts->audio_out_pa_stream);
if(err != 0)
exit(err);
#else
printf("Error, Portaudio support not compiled.\n");
exit(1);
#endif
}
else
{
struct stat stat_buf;
if(stat(opts->audio_out_dev, &stat_buf) != 0)
{
printf("Error, couldn't open %s\n", opts->audio_out_dev);
exit(1);
}
if( !(S_ISCHR(stat_buf.st_mode) || S_ISBLK(stat_buf.st_mode)))
{
// this is not a device
printf("Error, %s is not a device. use -w filename for wav output.\n", opts->audio_out_dev);
exit(1);
}
#ifdef SOLARIS
sample_info_t aset, aget;
opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY);
if (opts->audio_out_fd == -1)
{
printf ("Error, couldn't open %s\n", opts->audio_out_dev);
exit (1);
}
// get current
ioctl (opts->audio_out_fd, AUDIO_GETINFO, &aset);
aset.record.sample_rate = speed;
aset.play.sample_rate = speed;
aset.record.channels = 1;
aset.play.channels = 1;
aset.record.precision = 16;
aset.play.precision = 16;
aset.record.encoding = AUDIO_ENCODING_LINEAR;
aset.play.encoding = AUDIO_ENCODING_LINEAR;
if (ioctl (opts->audio_out_fd, AUDIO_SETINFO, &aset) == -1)
{
printf ("Error setting sample device parameters\n");
exit (1);
}
#endif
#if defined(BSD) && !defined(__APPLE__)
int fmt;
opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY);
if (opts->audio_out_fd == -1)
{
printf ("Error, couldn't open %s\n", opts->audio_out_dev);
opts->audio_out = 0;
exit(1);
}
fmt = 0;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
{
printf ("ioctl reset error \n");
}
fmt = speed;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
{
printf ("ioctl speed error \n");
}
fmt = 0;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
{
printf ("ioctl stereo error \n");
}
fmt = AFMT_S16_LE;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
{
printf ("ioctl setfmt error \n");
}
#endif
}
printf ("Audio Out Device: %s\n", opts->audio_out_dev);
}
void
openAudioInDevice (dsd_opts * opts)
{
// get info of device/file
if(strncmp(opts->audio_in_dev, "-", 1) == 0)
{
opts->audio_in_type = 1;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate=48000;
opts->audio_in_file_info->channels=1;
opts->audio_in_file_info->seekable=0;
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
opts->audio_in_file = sf_open_fd(fileno(stdin), SFM_READ, opts->audio_in_file_info, 0);
if(opts->audio_in_file == NULL) {
printf ("Error, couldn't open stdin with libsndfile: %s\n", sf_strerror(NULL));
exit(1);
}
}
else if(strncmp(opts->audio_in_dev, "pa:", 2) == 0)
{
opts->audio_in_type = 2;
#ifdef USE_PORTAUDIO
int err = getPADevice(opts->audio_in_dev, 1, &opts->audio_in_pa_stream);
if(err != 0)
exit(err);
if (opts->split == 0)
{
int err = getPADevice(opts->audio_in_dev, 0, &opts->audio_out_pa_stream);
if(err != 0)
exit(err);
}
#else
printf("Error, Portaudio support not compiled.\n");
exit(1);
#endif
}
else
{
struct stat stat_buf;
if (stat(opts->audio_in_dev, &stat_buf) != 0)
{
printf("Error, couldn't open %s\n", opts->audio_in_dev);
exit(1);
}
if (S_ISREG(stat_buf.st_mode))
{
// is this a regular file? then process with libsndfile.
opts->audio_in_type = 1;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->channels = 1;
opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info);
if(opts->audio_in_file == NULL)
{
printf ("Error, couldn't open file %s\n", opts->audio_in_dev);
exit(1);
}
}
else
{
// this is a device, use old handling
opts->audio_in_type = 0;
#ifdef SOLARIS
sample_info_t aset, aget;
int rgain;
rgain = 64;
if (opts->split == 1)
{
opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY);
}
else
{
opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR);
}
if (opts->audio_in_fd == -1)
{
printf ("Error, couldn't open %s\n", opts->audio_in_dev);
exit(1);
}
// get current
ioctl (opts->audio_in_fd, AUDIO_GETINFO, &aset);
aset.record.sample_rate = SAMPLE_RATE_IN;
aset.play.sample_rate = SAMPLE_RATE_IN;
aset.record.channels = 1;
aset.play.channels = 1;
aset.record.precision = 16;
aset.play.precision = 16;
aset.record.encoding = AUDIO_ENCODING_LINEAR;
aset.play.encoding = AUDIO_ENCODING_LINEAR;
aset.record.port = AUDIO_LINE_IN;
aset.record.gain = rgain;
if (ioctl (opts->audio_in_fd, AUDIO_SETINFO, &aset) == -1)
{
printf ("Error setting sample device parameters\n");
exit (1);
}
#endif
#if defined(BSD) && !defined(__APPLE__)
int fmt;
if (opts->split == 1)
{
opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY);
}
else
{
opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR);
}
if (opts->audio_in_fd == -1)
{
printf ("Error, couldn't open %s\n", opts->audio_in_dev);
opts->audio_out = 0;
}
fmt = 0;
if (ioctl (opts->audio_in_fd, SNDCTL_DSP_RESET) < 0)
{
printf ("ioctl reset error \n");
}
fmt = SAMPLE_RATE_IN;
if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
{
printf ("ioctl speed error \n");
}
fmt = 0;
if (ioctl (opts->audio_in_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
{
printf ("ioctl stereo error \n");
}
fmt = AFMT_S16_LE;
if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
{
printf ("ioctl setfmt error \n");
}
#endif
}
}
if (opts->split == 1)
{
printf ("Audio In Device: %s\n", opts->audio_in_dev);
}
else
{
printf ("Audio In/Out Device: %s\n", opts->audio_in_dev);
}
}

437
src/dsd_dibit.c Normal file
View File

@@ -0,0 +1,437 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <assert.h>
#include "dsd.h"
#include "p25p1_heuristics.h"
static void
print_datascope(dsd_opts* opts, dsd_state* state, int* sbuf2)
{
int i, j, o;
char modulation[8];
int spectrum[64];
if (state->rf_mod == 0)
{
sprintf (modulation, "C4FM");
}
else if (state->rf_mod == 1)
{
sprintf (modulation, "QPSK");
}
else if (state->rf_mod == 2)
{
sprintf (modulation, "GFSK");
}
for (i = 0; i < 64; i++)
{
spectrum[i] = 0;
}
for (i = 0; i < opts->ssize; i++)
{
o = (sbuf2[i] + 32768) / 1024;
spectrum[o]++;
}
if (state->symbolcnt > (4800 / opts->scoperate))
{
state->symbolcnt = 0;
printf ("\n");
printf ("Demod mode: %s Nac: %4X\n", modulation, state->nac);
printf ("Frame Type: %s Talkgroup: %7i\n", state->ftype, state->lasttg);
printf ("Frame Subtype: %s Source: %12i\n", state->fsubtype, state->lastsrc);
printf ("TDMA activity: %s %s Voice errors: %s\n", state->slot0light, state->slot1light, state->err_str);
printf ("+----------------------------------------------------------------+\n");
for (i = 0; i < 10; i++)
{
printf ("|");
for (j = 0; j < 64; j++)
{
if (i == 0)
{
if ((j == ((state->min) + 32768) / 1024) || (j == ((state->max) + 32768) / 1024))
{
printf ("#");
}
else if ((j == ((state->lmid) + 32768) / 1024) || (j == ((state->umid) + 32768) / 1024))
{
printf ("^");
}
else if (j == (state->center + 32768) / 1024)
{
printf ("!");
}
else
{
if (j == 32)
{
printf ("|");
}
else
{
printf (" ");
}
}
}
else
{
if (spectrum[j] > 9 - i)
{
printf ("*");
}
else
{
if (j == 32)
{
printf ("|");
}
else
{
printf (" ");
}
}
}
}
printf ("|\n");
}
printf ("+----------------------------------------------------------------+\n");
}
}
static void
use_symbol (dsd_opts* opts, dsd_state* state, int symbol)
{
int i;
int sbuf2[128];
int lmin, lmax, lsum;
for (i = 0; i < opts->ssize; i++)
{
sbuf2[i] = state->sbuf[i];
}
qsort (sbuf2, opts->ssize, sizeof (int), comp);
// continuous update of min/max in rf_mod=1 (QPSK) mode
// in c4fm min/max must only be updated during sync
if (state->rf_mod == 1)
{
lmin = (sbuf2[0] + sbuf2[1]) / 2;
lmax = (sbuf2[(opts->ssize - 1)] + sbuf2[(opts->ssize - 2)]) / 2;
state->minbuf[state->midx] = lmin;
state->maxbuf[state->midx] = lmax;
if (state->midx == (opts->msize - 1))
{
state->midx = 0;
}
else
{
state->midx++;
}
lsum = 0;
for (i = 0; i < opts->msize; i++)
{
lsum += state->minbuf[i];
}
state->min = lsum / opts->msize;
lsum = 0;
for (i = 0; i < opts->msize; i++)
{
lsum += state->maxbuf[i];
}
state->max = lsum / opts->msize;
state->center = ((state->max) + (state->min)) / 2;
state->umid = (((state->max) - state->center) * 5 / 8) + state->center;
state->lmid = (((state->min) - state->center) * 5 / 8) + state->center;
state->maxref = (int)((state->max) * 0.80F);
state->minref = (int)((state->min) * 0.80F);
}
else
{
state->maxref = state->max;
state->minref = state->min;
}
// Increase sidx
if (state->sidx == (opts->ssize - 1))
{
state->sidx = 0;
if (opts->datascope == 1)
{
print_datascope(opts, state, sbuf2);
}
}
else
{
state->sidx++;
}
if (state->dibit_buf_p > state->dibit_buf + 900000)
{
state->dibit_buf_p = state->dibit_buf + 200;
}
}
static int
invert_dibit(int dibit)
{
switch (dibit)
{
case 0:
return 2;
case 1:
return 3;
case 2:
return 0;
case 3:
return 1;
}
// Error, shouldn't be here
assert(0);
return -1;
}
static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
{
// determine dibit state
if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18))
{
// 6 +D-STAR
// 14 +ProVoice
// 18 +D-STAR_HD
if (symbol > state->center)
{
*state->dibit_buf_p = 1;
state->dibit_buf_p++;
return (0); // +1
}
else
{
*state->dibit_buf_p = 3;
state->dibit_buf_p++;
return (1); // +3
}
}
else if ((state->synctype == 7) || (state->synctype == 15)|| (state->synctype == 19))
{
// 7 -D-STAR
// 15 -ProVoice
// 19 -D-STAR_HD
if (symbol > state->center)
{
*state->dibit_buf_p = 1;
state->dibit_buf_p++;
return (1); // +3
}
else
{
*state->dibit_buf_p = 3;
state->dibit_buf_p++;
return (0); // +1
}
}
else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) ||
(state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) || (state->synctype == 17))
{
// 1 -P25p1
// 3 -X2-TDMA (inverted signal voice frame)
// 5 -X2-TDMA (inverted signal data frame)
// 9 -NXDN (inverted voice frame)
// 11 -DMR (inverted signal voice frame)
// 13 -DMR (inverted signal data frame)
// 17 -NXDN (inverted data frame)
int valid;
int dibit;
valid = 0;
if (state->synctype == 1)
{
// Use the P25 heuristics if available
valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit);
}
if (valid == 0)
{
// Revert to the original approach: choose the symbol according to the regions delimited
// by center, umid and lmid
if (symbol > state->center)
{
if (symbol > state->umid)
{
dibit = 3; // -3
}
else
{
dibit = 2; // -1
}
}
else
{
if (symbol < state->lmid)
{
dibit = 1; // +3
}
else
{
dibit = 0; // +2
}
}
}
state->last_dibit = dibit;
// store non-inverted values in dibit_buf
*state->dibit_buf_p = invert_dibit(dibit);
state->dibit_buf_p++;
return dibit;
}
else
{
// 0 +P25p1
// 2 +X2-TDMA (non inverted signal data frame)
// 4 +X2-TDMA (non inverted signal voice frame)
// 8 +NXDN (non inverted voice frame)
// 10 +DMR (non inverted signal data frame)
// 12 +DMR (non inverted signal voice frame)
// 16 +NXDN (non inverted data frame)
int valid;
int dibit;
valid = 0;
if (state->synctype == 0)
{
// Use the P25 heuristics if available
valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit);
}
if (valid == 0)
{
// Revert to the original approach: choose the symbol according to the regions delimited
// by center, umid and lmid
if (symbol > state->center)
{
if (symbol > state->umid)
{
dibit = 1; // +3
}
else
{
dibit = 0; // +1
}
}
else
{
if (symbol < state->lmid)
{
dibit = 3; // -3
}
else
{
dibit = 2; // -1
}
}
}
state->last_dibit = dibit;
*state->dibit_buf_p = dibit;
state->dibit_buf_p++;
return dibit;
}
}
int
get_dibit_and_analog_signal (dsd_opts* opts, dsd_state* state, int* out_analog_signal)
{
int symbol;
int dibit;
#ifdef TRACE_DSD
unsigned int l, r;
#endif
state->numflips = 0;
#ifdef TRACE_DSD
l = state->debug_sample_index;
#endif
symbol = getSymbol (opts, state, 1);
#ifdef TRACE_DSD
r = state->debug_sample_index;
#endif
//
state->sbuf[state->sidx] = symbol;
if (out_analog_signal != NULL)
{
*out_analog_signal = symbol;
}
use_symbol (opts, state, symbol);
dibit = digitize (opts, state, symbol);
#ifdef TRACE_DSD
{
float left, right;
if (state->debug_label_dibit_file == NULL) {
state->debug_label_dibit_file = fopen ("pp_label_dibit.txt", "w");
}
left = l / 48000.0;
right = r / 48000.0;
fprintf(state->debug_label_dibit_file, "%f\t%f\t%i\n", left, right, dibit);
}
#endif
return dibit;
}
/**
* \brief This important method reads the last analog signal value (getSymbol call) and digitizes it.
* Depending of the ongoing transmission it in converted into a bit (0/1) or a di-bit (00/01/10/11).
*/
int
getDibit (dsd_opts* opts, dsd_state* state)
{
return get_dibit_and_analog_signal (opts, state, NULL);
}
void
skipDibit (dsd_opts * opts, dsd_state * state, int count)
{
short sample;
int i;
for (i = 0; i < (count); i++)
{
sample = getDibit (opts, state);
}
}

370
src/dsd_file.c Normal file
View File

@@ -0,0 +1,370 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
void
saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
{
int i, j, k;
unsigned char b;
unsigned char err;
err = (unsigned char) state->errs2;
fputc (err, opts->mbe_out_f);
k = 0;
for (i = 0; i < 11; i++)
{
b = 0;
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + imbe_d[k];
k++;
}
fputc (b, opts->mbe_out_f);
}
fflush (opts->mbe_out_f);
}
void
saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
{
int i, j, k;
unsigned char b;
unsigned char err;
err = (unsigned char) state->errs2;
fputc (err, opts->mbe_out_f);
k = 0;
for (i = 0; i < 6; i++)
{
b = 0;
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + ambe_d[k];
k++;
}
fputc (b, opts->mbe_out_f);
}
b = ambe_d[48];
fputc (b, opts->mbe_out_f);
fflush (opts->mbe_out_f);
}
int
readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
{
int i, j, k;
unsigned char b;
state->errs2 = fgetc (opts->mbe_in_f);
state->errs = state->errs2;
k = 0;
for (i = 0; i < 11; i++)
{
b = fgetc (opts->mbe_in_f);
if (feof (opts->mbe_in_f))
{
return (1);
}
for (j = 0; j < 8; j++)
{
imbe_d[k] = (b & 128) >> 7;
b = b << 1;
b = b & 255;
k++;
}
}
return (0);
}
int
readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
{
int i, j, k;
unsigned char b;
state->errs2 = fgetc (opts->mbe_in_f);
state->errs = state->errs2;
k = 0;
for (i = 0; i < 6; i++)
{
b = fgetc (opts->mbe_in_f);
if (feof (opts->mbe_in_f))
{
return (1);
}
for (j = 0; j < 8; j++)
{
ambe_d[k] = (b & 128) >> 7;
b = b << 1;
b = b & 255;
k++;
}
}
b = fgetc (opts->mbe_in_f);
ambe_d[48] = (b & 1);
return (0);
}
void
openMbeInFile (dsd_opts * opts, dsd_state * state)
{
char cookie[5];
opts->mbe_in_f = fopen (opts->mbe_in_file, "ro");
if (opts->mbe_in_f == NULL)
{
printf ("Error: could not open %s\n", opts->mbe_in_file);
}
// read cookie
cookie[0] = fgetc (opts->mbe_in_f);
cookie[1] = fgetc (opts->mbe_in_f);
cookie[2] = fgetc (opts->mbe_in_f);
cookie[3] = fgetc (opts->mbe_in_f);
cookie[4] = 0;
if (strstr (cookie, ".amb") != NULL)
{
state->mbe_file_type = 1;
}
else if (strstr (cookie, ".imb") != NULL)
{
state->mbe_file_type = 0;
}
else
{
state->mbe_file_type = -1;
printf ("Error - unrecognized file type\n");
}
}
void
closeMbeOutFile (dsd_opts * opts, dsd_state * state)
{
char shell[255], newfilename[64], ext[5], datestr[32], new_path[1024];
char tgid[17];
int sum, i, j;
int talkgroup;
struct tm timep;
int result;
if (opts->mbe_out_f != NULL)
{
if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15))
{
sprintf (ext, ".imb");
strptime (opts->mbe_out_file, "%s.imb", &timep);
}
else
{
sprintf (ext, ".amb");
strptime (opts->mbe_out_file, "%s.amb", &timep);
}
if (state->tgcount > 0)
{
for (i = 0; i < 16; i++)
{
sum = 0;
for (j = 0; j < state->tgcount; j++)
{
sum = sum + state->tg[j][i] - 48;
}
tgid[i] = (char) (((float) sum / (float) state->tgcount) + 48.5);
}
tgid[16] = 0;
talkgroup = (int) strtol (tgid, NULL, 2);
}
else
{
talkgroup = 0;
}
fflush (opts->mbe_out_f);
fclose (opts->mbe_out_f);
opts->mbe_out_f = NULL;
strftime (datestr, 31, "%Y-%m-%d-%H%M%S", &timep);
sprintf (newfilename, "nac%X-%s-tg%i%s", state->nac, datestr, talkgroup, ext);
sprintf (new_path, "%s%s", opts->mbe_out_dir, newfilename);
#ifdef _WIN32
sprintf (shell, "move %s %s", opts->mbe_out_path, new_path);
#else
sprintf (shell, "mv %s %s", opts->mbe_out_path, new_path);
#endif
result = system (shell);
state->tgcount = 0;
for (i = 0; i < 25; i++)
{
for (j = 0; j < 16; j++)
{
state->tg[i][j] = 48;
}
}
}
}
void
openMbeOutFile (dsd_opts * opts, dsd_state * state)
{
struct timeval tv;
int i, j;
char ext[5];
if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15))
{
sprintf (ext, ".imb");
}
else
{
sprintf (ext, ".amb");
}
// reset talkgroup id buffer
for (i = 0; i < 12; i++)
{
for (j = 0; j < 25; j++)
{
state->tg[j][i] = 0;
}
}
state->tgcount = 0;
gettimeofday (&tv, NULL);
sprintf (opts->mbe_out_file, "%i%s", (int) tv.tv_sec, ext);
sprintf(opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file);
opts->mbe_out_f = fopen (opts->mbe_out_path, "w");
if (opts->mbe_out_f == NULL)
{
printf ("Error, couldn't open %s\n", opts->mbe_out_path);
}
// write magic
fprintf (opts->mbe_out_f, "%s", ext);
fflush (opts->mbe_out_f);
}
void
openWavOutFile (dsd_opts * opts, dsd_state * state)
{
// opts->wav_out_f = fopen (opts->wav_out_file, "w");
SF_INFO info;
info.samplerate = 8000;
info.channels = 1;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info);
if (opts->wav_out_f == NULL)
{
printf ("Error - could not open wav output file %s\n", opts->wav_out_file);
return;
}
// state->wav_out_bytes = 0;
}
void
closeWavOutFile (dsd_opts * opts, dsd_state * state)
{
sf_close(opts->wav_out_f);
/*
int length;
if (opts->wav_out_f != NULL)
{
rewind (opts->wav_out_f);
length = state->wav_out_bytes;
fprintf (opts->wav_out_f, "RIFF");
// total length
fputc (((36 + length) & 0xff), opts->≈≈);
fputc ((((36 + length) >> 8) & 0xff), opts->wav_out_f);
fputc ((((36 + length) >> 16) & 0xff), opts->wav_out_f);
fputc ((((36 + length) >> 24) & 0xff), opts->wav_out_f);
fprintf (opts->wav_out_f, "WAVE");
fprintf (opts->wav_out_f, "fmt ");
// length of format chunk
fputc (16, opts->wav_out_f);
fputc (0, opts->wav_out_f);
fputc (0, opts->wav_out_f);
fputc (0, opts->wav_out_f);
// always 0x1
fputc (1, opts->wav_out_f);
fputc (0, opts->wav_out_f);
// channels
fputc (1, opts->wav_out_f);
fputc (0, opts->wav_out_f);
// sample rate
fputc (64, opts->wav_out_f);
fputc (31, opts->wav_out_f);
fputc (0, opts->wav_out_f);
fputc (0, opts->wav_out_f);
// bytes per second
fputc (128, opts->wav_out_f);
fputc (62, opts->wav_out_f);
fputc (0, opts->wav_out_f);
fputc (0, opts->wav_out_f);
// block align
fputc (2, opts->wav_out_f);
fputc (0, opts->wav_out_f);
// bits/sample
fputc (16, opts->wav_out_f);
fputc (0, opts->wav_out_f);
// data chunk header
fprintf (opts->wav_out_f, "data");
// length of data
fputc ((length & 0xff), opts->wav_out_f);
fputc (((length >> 8) & 0xff), opts->wav_out_f);
fputc (((length >> 16) & 0xff), opts->wav_out_f);
fputc (((length >> 24) & 0xff), opts->wav_out_f);
fflush (opts->wav_out_f);
}
*/
}

116
src/dsd_filters.c Normal file
View File

@@ -0,0 +1,116 @@
// DMR filter
#define NZEROS 60
float ngain = 7.423339364f;
static float xv[NZEROS+1];
float xcoeffs[] =
{ -0.0083649323f, -0.0265444850f, -0.0428141462f, -0.0537571943f,
-0.0564141052f, -0.0489161045f, -0.0310068662f, -0.0043393881f,
+0.0275375106f, +0.0595423283f, +0.0857543325f, +0.1003565948f,
+0.0986944931f, +0.0782804830f, +0.0395670487f, -0.0136691535f,
-0.0744390415f, -0.1331834575f, -0.1788967208f, -0.2005995448f,
-0.1889627181f, -0.1378439993f, -0.0454976231f, +0.0847488694f,
+0.2444859269f, +0.4209222342f, +0.5982295474f, +0.7593684540f,
+0.8881539892f, +0.9712773915f, +0.9999999166f, +0.9712773915f,
+0.8881539892f, +0.7593684540f, +0.5982295474f, +0.4209222342f,
+0.2444859269f, +0.0847488694f, -0.0454976231f, -0.1378439993f,
-0.1889627181f, -0.2005995448f, -0.1788967208f, -0.1331834575f,
-0.0744390415f, -0.0136691535f, +0.0395670487f, +0.0782804830f,
+0.0986944931f, +0.1003565948f, +0.0857543325f, +0.0595423283f,
+0.0275375106f, -0.0043393881f, -0.0310068662f, -0.0489161045f,
-0.0564141052f, -0.0537571943f, -0.0428141462f, -0.0265444850f,
-0.0083649323f,
};
// NXDN filter
#define NXZEROS 134
float nxgain = 15.95930463f;
static float nxv[NXZEROS+1];
float nxcoeffs[] =
{ +0.031462429f, +0.031747267f, +0.030401148f, +0.027362877f,
+0.022653298f, +0.016379869f, +0.008737200f, +0.000003302f,
-0.009468531f, -0.019262057f, -0.028914291f, -0.037935027f,
-0.045828927f, -0.052119261f, -0.056372283f, -0.058221106f,
-0.057387924f, -0.053703443f, -0.047122444f, -0.037734535f,
-0.025769308f, -0.011595336f, +0.004287292f, +0.021260954f,
+0.038610717f, +0.055550276f, +0.071252765f, +0.084885375f,
+0.095646450f, +0.102803611f, +0.105731303f, +0.103946126f,
+0.097138329f, +0.085197939f, +0.068234131f, +0.046586711f,
+0.020828821f, -0.008239664f, -0.039608255f, -0.072081234f,
-0.104311776f, -0.134843790f, -0.162160200f, -0.184736015f,
-0.201094346f, -0.209863285f, -0.209831516f, -0.200000470f,
-0.179630919f, -0.148282051f, -0.105841323f, -0.052543664f,
+0.011020985f, +0.083912428f, +0.164857408f, +0.252278939f,
+0.344336996f, +0.438979335f, +0.534000832f, +0.627109358f,
+0.715995947f, +0.798406824f, +0.872214756f, +0.935487176f,
+0.986548646f, +1.024035395f, +1.046939951f, +1.054644241f,
+1.046939951f, +1.024035395f, +0.986548646f, +0.935487176f,
+0.872214756f, +0.798406824f, +0.715995947f, +0.627109358f,
+0.534000832f, +0.438979335f, +0.344336996f, +0.252278939f,
+0.164857408f, +0.083912428f, +0.011020985f, -0.052543664f,
-0.105841323f, -0.148282051f, -0.179630919f, -0.200000470f,
-0.209831516f, -0.209863285f, -0.201094346f, -0.184736015f,
-0.162160200f, -0.134843790f, -0.104311776f, -0.072081234f,
-0.039608255f, -0.008239664f, +0.020828821f, +0.046586711f,
+0.068234131f, +0.085197939f, +0.097138329f, +0.103946126f,
+0.105731303f, +0.102803611f, +0.095646450f, +0.084885375f,
+0.071252765f, +0.055550276f, +0.038610717f, +0.021260954f,
+0.004287292f, -0.011595336f, -0.025769308f, -0.037734535f,
-0.047122444f, -0.053703443f, -0.057387924f, -0.058221106f,
-0.056372283f, -0.052119261f, -0.045828927f, -0.037935027f,
-0.028914291f, -0.019262057f, -0.009468531f, +0.000003302f,
+0.008737200f, +0.016379869f, +0.022653298f, +0.027362877f,
+0.030401148f, +0.031747267f, +0.031462429f,
};
short dsd_input_filter(short sample, int mode);
short
dmr_filter(short sample)
{
return dsd_input_filter(sample, 1);
}
short
nxdn_filter(short sample)
{
return dsd_input_filter(sample, 2);
}
short
dsd_input_filter(short sample, int mode)
{
float sum; int i;
float gain;
int zeros;
float *v, *coeffs;
switch(mode) {
case 1:
gain = ngain;
v = xv;
coeffs = xcoeffs;
zeros = NZEROS;
break;
case 2:
gain = nxgain;
v = nxv;
coeffs = nxcoeffs;
zeros = NXZEROS;
break;
default:
return sample;
}
for (i = 0; i < zeros; i++)
v[i] = v[i+1];
v[zeros] = sample; // unfiltered sample in
sum = 0.0f;
for (i = 0; i <= zeros; i++)
sum += (coeffs[i] * v[i]);
return (short)(sum / ngain); // filtered sample out
}

571
src/dsd_frame.c Normal file
View File

@@ -0,0 +1,571 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
#if !defined(NULL)
#define NULL 0
#endif
#include "p25p1_check_nid.h"
void
printFrameInfo (dsd_opts * opts, dsd_state * state)
{
int level;
level = (int) state->max / 164;
if (opts->verbose > 0)
{
printf ("inlvl: %2i%% ", level);
}
if (state->nac != 0)
{
printf ("nac: %4X ", state->nac);
}
if (opts->verbose > 1)
{
printf ("src: %8i ", state->lastsrc);
}
printf ("tg: %5i ", state->lasttg);
}
void
processFrame (dsd_opts * opts, dsd_state * state)
{
int i, j, dibit;
char duid[3];
char nac[13];
int level;
char status_0;
char bch_code[63];
int index_bch_code;
unsigned char parity;
char v;
int new_nac;
char new_duid[3];
int check_result;
nac[12] = 0;
duid[2] = 0;
j = 0;
if (state->rf_mod == 1)
{
state->maxref = (int)(state->max * 0.80F);
state->minref = (int)(state->min * 0.80F);
}
else
{
state->maxref = state->max;
state->minref = state->min;
}
if ((state->synctype == 8) || (state->synctype == 9))
{
state->rf_mod = 2;
state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{
level = (int) state->max / 164;
printf ("inlvl: %2i%% ", level);
}
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " VOICE ");
processNXDNVoice (opts, state);
return;
}
else if ((state->synctype == 16) || (state->synctype == 17))
{
state->rf_mod = 2;
state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{
level = (int) state->max / 164;
printf ("inlvl: %2i%% ", level);
}
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " DATA ");
processNXDNData (opts, state);
return;
}
else if ((state->synctype == 6) || (state->synctype == 7))
{
state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{
level = (int) state->max / 164;
printf ("inlvl: %2i%% ", level);
}
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " VOICE ");
processDSTAR (opts, state);
return;
}
else if ((state->synctype == 18) || (state->synctype == 19))
{
state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{
level = (int) state->max / 164;
printf ("inlvl: %2i%% ", level);
}
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " DATA ");
processDSTAR_HD (opts, state);
return;
}
else if ((state->synctype >= 10) && (state->synctype <= 13))
{
state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{
level = (int) state->max / 164;
printf ("inlvl: %2i%% ", level);
}
}
if ((state->synctype == 11) || (state->synctype == 12))
{
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " VOICE ");
processDMRvoice (opts, state);
}
else
{
closeMbeOutFile (opts, state);
state->err_str[0] = 0;
processDMRdata (opts, state);
}
return;
}
else if ((state->synctype >= 2) && (state->synctype <= 5))
{
state->nac = 0;
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
}
if ((state->synctype == 3) || (state->synctype == 4))
{
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " VOICE ");
processX2TDMAvoice (opts, state);
}
else
{
closeMbeOutFile (opts, state);
state->err_str[0] = 0;
processX2TDMAdata (opts, state);
}
return;
}
else if ((state->synctype == 14) || (state->synctype == 15))
{
state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{
level = (int) state->max / 164;
printf ("inlvl: %2i%% ", level);
}
}
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " VOICE ");
processProVoice (opts, state);
return;
}
else
{
// Read the NAC, 12 bits
j = 0;
index_bch_code = 0;
for (i = 0; i < 6; i++)
{
dibit = getDibit (opts, state);
v = 1 & (dibit >> 1); // bit 1
nac[j] = v + '0';
j++;
bch_code[index_bch_code] = v;
index_bch_code++;
v = 1 & dibit; // bit 0
nac[j] = v + '0';
j++;
bch_code[index_bch_code] = v;
index_bch_code++;
}
state->nac = strtol (nac, NULL, 2);
// Read the DUID, 4 bits
for (i = 0; i < 2; i++)
{
dibit = getDibit (opts, state);
duid[i] = dibit + '0';
bch_code[index_bch_code] = 1 & (dibit >> 1); // bit 1
index_bch_code++;
bch_code[index_bch_code] = 1 & dibit; // bit 0
index_bch_code++;
}
// Read the BCH data for error correction of NAC and DUID
for (i = 0; i < 3; i++)
{
dibit = getDibit (opts, state);
bch_code[index_bch_code] = 1 & (dibit >> 1); // bit 1
index_bch_code++;
bch_code[index_bch_code] = 1 & dibit; // bit 0
index_bch_code++;
}
// Intermission: read the status dibit
status_0 = getDibit (opts, state) + '0';
// ... continue reading the BCH error correction data
for (i = 0; i < 20; i++)
{
dibit = getDibit (opts, state);
bch_code[index_bch_code] = 1 & (dibit >> 1); // bit 1
index_bch_code++;
bch_code[index_bch_code] = 1 & dibit; // bit 0
index_bch_code++;
}
// Read the parity bit
dibit = getDibit (opts, state);
bch_code[index_bch_code] = 1 & (dibit >> 1); // bit 1
parity = (1 & dibit); // bit 0
// Check if the NID is correct
check_result = check_NID (bch_code, &new_nac, new_duid, parity);
if (check_result) {
if (new_nac != state->nac) {
// NAC fixed by error correction
state->nac = new_nac;
state->debug_header_errors++;
}
if (strcmp(new_duid, duid) != 0) {
// DUID fixed by error correction
//printf("Fixing DUID %s -> %s\n", duid, new_duid);
duid[0] = new_duid[0];
duid[1] = new_duid[1];
state->debug_header_errors++;
}
} else {
// Check of NID failed and unable to recover its value
//printf("NID error\n");
duid[0] = 'E';
duid[1] = 'E';
state->debug_header_critical_errors++;
}
}
if (strcmp (duid, "00") == 0)
{
// Header Data Unit
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" HDU\n");
}
if (opts->mbe_out_dir[0] != 0)
{
closeMbeOutFile (opts, state);
openMbeOutFile (opts, state);
}
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->lastp25type = 2;
sprintf (state->fsubtype, " HDU ");
processHDU (opts, state);
}
else if (strcmp (duid, "11") == 0)
{
// Logical Link Data Unit 1
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" LDU1 ");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
state->lastp25type = 1;
sprintf (state->fsubtype, " LDU1 ");
state->numtdulc = 0;
processLDU1 (opts, state);
}
else if (strcmp (duid, "22") == 0)
{
// Logical Link Data Unit 2
if (state->lastp25type != 1)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" Ignoring LDU2 not preceeded by LDU1\n");
}
state->lastp25type = 0;
sprintf (state->fsubtype, " ");
}
else
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" LDU2 ");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
state->lastp25type = 2;
sprintf (state->fsubtype, " LDU2 ");
state->numtdulc = 0;
processLDU2 (opts, state);
}
}
else if (strcmp (duid, "33") == 0)
{
// Terminator with subsequent Link Control
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" TDULC\n");
}
if (opts->mbe_out_dir[0] != 0)
{
closeMbeOutFile (opts, state);
}
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->lasttg = 0;
state->lastsrc = 0;
state->lastp25type = 0;
state->err_str[0] = 0;
sprintf (state->fsubtype, " TDULC ");
state->numtdulc++;
if ((opts->resume > 0) && (state->numtdulc > opts->resume))
{
resumeScan (opts, state);
}
processTDULC (opts, state);
state->err_str[0] = 0;
}
else if (strcmp (duid, "03") == 0)
{
// Terminator without subsequent Link Control
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" TDU\n");
}
if (opts->mbe_out_dir[0] != 0)
{
closeMbeOutFile (opts, state);
}
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->lasttg = 0;
state->lastsrc = 0;
state->lastp25type = 0;
state->err_str[0] = 0;
sprintf (state->fsubtype, " TDU ");
processTDU (opts, state);
}
else if (strcmp (duid, "13") == 0)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" TSDU\n");
}
if (opts->resume > 0)
{
resumeScan (opts, state);
}
state->lasttg = 0;
state->lastsrc = 0;
state->lastp25type = 3;
sprintf (state->fsubtype, " TSDU ");
// Now processing NID
skipDibit (opts, state, 328-25);
}
else if (strcmp (duid, "30") == 0)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" PDU\n");
}
if (opts->resume > 0)
{
resumeScan (opts, state);
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
state->lastp25type = 4;
sprintf (state->fsubtype, " PDU ");
}
// try to guess based on previous frame if unknown type
else if (state->lastp25type == 1)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf ("(LDU2) ");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
//state->lastp25type = 0;
// Guess that the state is LDU2
state->lastp25type = 2;
sprintf (state->fsubtype, "(LDU2) ");
state->numtdulc = 0;
processLDU2 (opts, state);
}
else if (state->lastp25type == 2)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf ("(LDU1) ");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
//state->lastp25type = 0;
// Guess that the state is LDU1
state->lastp25type = 1;
sprintf (state->fsubtype, "(LDU1) ");
state->numtdulc = 0;
processLDU1 (opts, state);
}
else if (state->lastp25type == 3)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" (TSDU)\n");
}
//state->lastp25type = 0;
// Guess that the state is TSDU
state->lastp25type = 3;
sprintf (state->fsubtype, "(TSDU) ");
// Now processing NID
skipDibit (opts, state, 328-25);
}
else if (state->lastp25type == 4)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" (PDU)\n");
}
state->lastp25type = 0;
}
else
{
state->lastp25type = 0;
sprintf (state->fsubtype, " ");
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
printf (" duid:%s *Unknown DUID*\n", duid);
}
}
}

830
src/dsd_frame_sync.c Normal file
View File

@@ -0,0 +1,830 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
void
printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation)
{
if (opts->verbose > 0)
{
printf ("Sync: %s ", frametype);
}
if (opts->verbose > 2)
{
printf ("o: %4i ", offset);
}
if (opts->verbose > 1)
{
printf ("mod: %s ", modulation);
}
if (opts->verbose > 2)
{
printf ("g: %f ", state->aout_gain);
}
}
int
getFrameSync (dsd_opts * opts, dsd_state * state)
{
/* detects frame sync and returns frame type
* 0 = +P25p1
* 1 = -P25p1
* 2 = +X2-TDMA (non inverted signal data frame)
* 3 = -X2-TDMA (inverted signal voice frame)
* 4 = +X2-TDMA (non inverted signal voice frame)
* 5 = -X2-TDMA (inverted signal data frame)
* 6 = +D-STAR
* 7 = -D-STAR
* 8 = +NXDN (non inverted voice frame)
* 9 = -NXDN (inverted voice frame)
* 10 = +DMR (non inverted signal data frame)
* 11 = -DMR (inverted signal voice frame)
* 12 = +DMR (non inverted signal voice frame)
* 13 = -DMR (inverted signal data frame)
* 14 = +ProVoice
* 15 = -ProVoice
* 16 = +NXDN (non inverted data frame)
* 17 = -NXDN (inverted data frame)
* 18 = +D-STAR_HD
* 19 = -D-STAR_HD
*/
int i, j, t, o, dibit, sync, symbol, synctest_pos, lastt;
char synctest[25];
char synctest18[19];
char synctest32[33];
char modulation[8];
char *synctest_p;
char synctest_buf[10240];
int lmin, lmax, lidx;
int lbuf[24], lbuf2[24];
int lsum;
char spectrum[64];
for (i = 18; i < 24; i++)
{
lbuf[i] = 0;
lbuf2[i] = 0;
}
// detect frame sync
t = 0;
synctest[24] = 0;
synctest18[18] = 0;
synctest32[32] = 0;
synctest_pos = 0;
synctest_p = synctest_buf + 10;
sync = 0;
lmin = 0;
lmax = 0;
lidx = 0;
lastt = 0;
state->numflips = 0;
if ((opts->symboltiming == 1) && (state->carrier == 1))
{
printf ("\nSymbol Timing:\n");
}
while (sync == 0)
{
t++;
symbol = getSymbol (opts, state, 0);
lbuf[lidx] = symbol;
state->sbuf[state->sidx] = symbol;
if (lidx == 23)
{
lidx = 0;
}
else
{
lidx++;
}
if (state->sidx == (opts->ssize - 1))
{
state->sidx = 0;
}
else
{
state->sidx++;
}
if (lastt == 23)
{
lastt = 0;
if (state->numflips > opts->mod_threshold)
{
if (opts->mod_qpsk == 1)
{
state->rf_mod = 1;
}
}
else if (state->numflips > 18)
{
if (opts->mod_gfsk == 1)
{
state->rf_mod = 2;
}
}
else
{
if (opts->mod_c4fm == 1)
{
state->rf_mod = 0;
}
}
state->numflips = 0;
}
else
{
lastt++;
}
if (state->dibit_buf_p > state->dibit_buf + 900000)
{
state->dibit_buf_p = state->dibit_buf + 200;
}
//determine dibit state
if (symbol > 0)
{
*state->dibit_buf_p = 1;
state->dibit_buf_p++;
dibit = 49; // '1'
}
else
{
*state->dibit_buf_p = 3;
state->dibit_buf_p++;
dibit = 51; // '3'
}
*synctest_p = dibit;
if (t >= 18)
{
for (i = 0; i < 24; i++)
{
lbuf2[i] = lbuf[i];
}
qsort (lbuf2, 24, sizeof (int), comp);
lmin = (lbuf2[2] + lbuf2[3] + lbuf2[4]) / 3;
lmax = (lbuf2[21] + lbuf2[20] + lbuf2[19]) / 3;
if (state->rf_mod == 1)
{
state->minbuf[state->midx] = lmin;
state->maxbuf[state->midx] = lmax;
if (state->midx == (opts->msize - 1))
{
state->midx = 0;
}
else
{
state->midx++;
}
lsum = 0;
for (i = 0; i < opts->msize; i++)
{
lsum += state->minbuf[i];
}
state->min = lsum / opts->msize;
lsum = 0;
for (i = 0; i < opts->msize; i++)
{
lsum += state->maxbuf[i];
}
state->max = lsum / opts->msize;
state->center = ((state->max) + (state->min)) / 2;
state->maxref = (int)((state->max) * 0.80F);
state->minref = (int)((state->min) * 0.80F);
}
else
{
state->maxref = state->max;
state->minref = state->min;
}
if (state->rf_mod == 0)
{
sprintf (modulation, "C4FM");
}
else if (state->rf_mod == 1)
{
sprintf (modulation, "QPSK");
}
else if (state->rf_mod == 2)
{
sprintf (modulation, "GFSK");
}
if (opts->datascope == 1)
{
if (lidx == 0)
{
for (i = 0; i < 64; i++)
{
spectrum[i] = 0;
}
for (i = 0; i < 24; i++)
{
o = (lbuf2[i] + 32768) / 1024;
spectrum[o]++;
}
if (state->symbolcnt > (4800 / opts->scoperate))
{
state->symbolcnt = 0;
printf ("\n");
printf ("Demod mode: %s Nac: %4X\n", modulation, state->nac);
printf ("Frame Type: %s Talkgroup: %7i\n", state->ftype, state->lasttg);
printf ("Frame Subtype: %s Source: %12i\n", state->fsubtype, state->lastsrc);
printf ("TDMA activity: %s %s Voice errors: %s\n", state->slot0light, state->slot1light, state->err_str);
printf ("+----------------------------------------------------------------+\n");
for (i = 0; i < 10; i++)
{
printf ("|");
for (j = 0; j < 64; j++)
{
if (i == 0)
{
if ((j == ((state->min) + 32768) / 1024) || (j == ((state->max) + 32768) / 1024))
{
printf ("#");
}
else if (j == (state->center + 32768) / 1024)
{
printf ("!");
}
else
{
if (j == 32)
{
printf ("|");
}
else
{
printf (" ");
}
}
}
else
{
if (spectrum[j] > 9 - i)
{
printf ("*");
}
else
{
if (j == 32)
{
printf ("|");
}
else
{
printf (" ");
}
}
}
}
printf ("|\n");
}
printf ("+----------------------------------------------------------------+\n");
}
}
}
strncpy (synctest, (synctest_p - 23), 24);
if (opts->frame_p25p1 == 1)
{
if (strcmp (synctest, P25P1_SYNC) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, " P25 Phase 1 ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +P25p1 ", synctest_pos + 1, modulation);
}
state->lastsynctype = 0;
return (0);
}
if (strcmp (synctest, INV_P25P1_SYNC) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, " P25 Phase 1 ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -P25p1 ", synctest_pos + 1, modulation);
}
state->lastsynctype = 1;
return (1);
}
}
if (opts->frame_x2tdma == 1)
{
if ((strcmp (synctest, X2TDMA_BS_DATA_SYNC) == 0) || (strcmp (synctest, X2TDMA_MS_DATA_SYNC) == 0))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + (lmax)) / 2;
state->min = ((state->min) + (lmin)) / 2;
if (opts->inverted_x2tdma == 0)
{
// data frame
sprintf (state->ftype, " X2-TDMA ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +X2-TDMA ", synctest_pos + 1, modulation);
}
state->lastsynctype = 2;
return (2);
}
else
{
// inverted voice frame
sprintf (state->ftype, " X2-TDMA ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -X2-TDMA ", synctest_pos + 1, modulation);
}
if (state->lastsynctype != 3)
{
state->firstframe = 1;
}
state->lastsynctype = 3;
return (3);
}
}
if ((strcmp (synctest, X2TDMA_BS_VOICE_SYNC) == 0) || (strcmp (synctest, X2TDMA_MS_VOICE_SYNC) == 0))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (opts->inverted_x2tdma == 0)
{
// voice frame
sprintf (state->ftype, " X2-TDMA ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +X2-TDMA ", synctest_pos + 1, modulation);
}
if (state->lastsynctype != 4)
{
state->firstframe = 1;
}
state->lastsynctype = 4;
return (4);
}
else
{
// inverted data frame
sprintf (state->ftype, " X2-TDMA ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -X2-TDMA ", synctest_pos + 1, modulation);
}
state->lastsynctype = 5;
return (5);
}
}
}
if (opts->frame_dmr == 1)
{
if ((strcmp (synctest, DMR_MS_DATA_SYNC) == 0) || (strcmp (synctest, DMR_BS_DATA_SYNC) == 0))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + (lmax)) / 2;
state->min = ((state->min) + (lmin)) / 2;
if (opts->inverted_dmr == 0)
{
// data frame
sprintf (state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 10;
return (10);
}
else
{
// inverted voice frame
sprintf (state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
}
if (state->lastsynctype != 11)
{
state->firstframe = 1;
}
state->lastsynctype = 11;
return (11);
}
}
if ((strcmp (synctest, DMR_MS_VOICE_SYNC) == 0) || (strcmp (synctest, DMR_BS_VOICE_SYNC) == 0))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (opts->inverted_dmr == 0)
{
// voice frame
sprintf (state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
}
if (state->lastsynctype != 12)
{
state->firstframe = 1;
}
state->lastsynctype = 12;
return (12);
}
else
{
// inverted data frame
sprintf (state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 13;
return (13);
}
}
}
if (opts->frame_provoice == 1)
{
strncpy (synctest32, (synctest_p - 31), 32);
if ((strcmp (synctest32, PROVOICE_SYNC) == 0) || (strcmp (synctest32, PROVOICE_EA_SYNC) == 0))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, " ProVoice ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -ProVoice ", synctest_pos + 1, modulation);
}
state->lastsynctype = 14;
return (14);
}
else if ((strcmp (synctest32, INV_PROVOICE_SYNC) == 0) || (strcmp (synctest32, INV_PROVOICE_EA_SYNC) == 0))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, " ProVoice ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -ProVoice ", synctest_pos + 1, modulation);
}
state->lastsynctype = 15;
return (15);
}
}
if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
{
strncpy (synctest18, (synctest_p - 17), 18);
if ((strcmp (synctest18, NXDN_BS_VOICE_SYNC) == 0) || (strcmp (synctest18, NXDN_MS_VOICE_SYNC) == 0))
{
if ((state->lastsynctype == 8) || (state->lastsynctype == 16))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (state->samplesPerSymbol == 20)
{
sprintf (state->ftype, " NXDN48 ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +NXDN48 ", synctest_pos + 1, modulation);
}
}
else
{
sprintf (state->ftype, " NXDN96 ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +NXDN96 ", synctest_pos + 1, modulation);
}
}
state->lastsynctype = 8;
return (8);
}
else
{
state->lastsynctype = 8;
}
}
else if ((strcmp (synctest18, INV_NXDN_BS_VOICE_SYNC) == 0) || (strcmp (synctest18, INV_NXDN_MS_VOICE_SYNC) == 0))
{
if ((state->lastsynctype == 9) || (state->lastsynctype == 17))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (state->samplesPerSymbol == 20)
{
sprintf (state->ftype, " NXDN48 ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -NXDN48 ", synctest_pos + 1, modulation);
}
}
else
{
sprintf (state->ftype, " NXDN96 ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -NXDN96 ", synctest_pos + 1, modulation);
}
}
state->lastsynctype = 9;
return (9);
}
else
{
state->lastsynctype = 9;
}
}
else if ((strcmp (synctest18, NXDN_BS_DATA_SYNC) == 0) || (strcmp (synctest18, NXDN_MS_DATA_SYNC) == 0))
{
if ((state->lastsynctype == 8) || (state->lastsynctype == 16))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (state->samplesPerSymbol == 20)
{
sprintf (state->ftype, " NXDN48 ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +NXDN48 ", synctest_pos + 1, modulation);
}
}
else
{
sprintf (state->ftype, " NXDN96 ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +NXDN96 ", synctest_pos + 1, modulation);
}
}
state->lastsynctype = 16;
return (16);
}
else
{
state->lastsynctype = 16;
}
}
else if ((strcmp (synctest18, INV_NXDN_BS_DATA_SYNC) == 0) || (strcmp (synctest18, INV_NXDN_MS_DATA_SYNC) == 0))
{
if ((state->lastsynctype == 9) || (state->lastsynctype == 17))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, " NXDN ");
if (state->samplesPerSymbol == 20)
{
sprintf (state->ftype, " NXDN48 ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -NXDN48 ", synctest_pos + 1, modulation);
}
}
else
{
sprintf (state->ftype, " NXDN96 ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -NXDN96 ", synctest_pos + 1, modulation);
}
}
state->lastsynctype = 17;
return (17);
}
else
{
state->lastsynctype = 17;
}
}
}
if (opts->frame_dstar == 1)
{
if (strcmp (synctest, DSTAR_SYNC) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, " D-STAR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +D-STAR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 6;
return (6);
}
if (strcmp (synctest, INV_DSTAR_SYNC) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, " D-STAR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -D-STAR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 7;
return (7);
}
if (strcmp (synctest, DSTAR_HD) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, " D-STAR_HD ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +D-STAR_HD ", synctest_pos + 1, modulation);
}
state->lastsynctype = 18;
return (18);
}
if (strcmp (synctest, INV_DSTAR_HD) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, " D-STAR_HD ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -D-STAR_HD ", synctest_pos + 1, modulation);
}
state->lastsynctype = 19;
return (19);
}
}
if ((t == 24) && (state->lastsynctype != -1))
{
if ((state->lastsynctype == 0) && ((state->lastp25type == 1) || (state->lastp25type == 2)))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + (lmax)) / 2;
state->min = ((state->min) + (lmin)) / 2;
sprintf (state->ftype, "(P25 Phase 1)");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, "(+P25p1) ", synctest_pos + 1, modulation);
}
state->lastsynctype = -1;
return (0);
}
else if ((state->lastsynctype == 1) && ((state->lastp25type == 1) || (state->lastp25type == 2)))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, "(P25 Phase 1)");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, "(-P25p1) ", synctest_pos + 1, modulation);
}
state->lastsynctype = -1;
return (1);
}
else if ((state->lastsynctype == 3) && ((strcmp (synctest, X2TDMA_BS_VOICE_SYNC) != 0) || (strcmp (synctest, X2TDMA_MS_VOICE_SYNC) != 0)))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, "(X2-TDMA) ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, "(-X2-TDMA) ", synctest_pos + 1, modulation);
}
state->lastsynctype = -1;
return (3);
}
else if ((state->lastsynctype == 4) && ((strcmp (synctest, X2TDMA_BS_DATA_SYNC) != 0) || (strcmp (synctest, X2TDMA_MS_DATA_SYNC) != 0)))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, "(X2-TDMA) ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, "(+X2-TDMA) ", synctest_pos + 1, modulation);
}
state->lastsynctype = -1;
return (4);
}
else if ((state->lastsynctype == 11) && ((strcmp (synctest, DMR_BS_VOICE_SYNC) != 0) || (strcmp (synctest, DMR_MS_VOICE_SYNC) != 0)))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, "(DMR) ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, "(-DMR) ", synctest_pos + 1, modulation);
}
state->lastsynctype = -1;
return (11);
}
else if ((state->lastsynctype == 12) && ((strcmp (synctest, DMR_BS_DATA_SYNC) != 0) || (strcmp (synctest, DMR_MS_DATA_SYNC) != 0)))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, "(DMR) ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, "(+DMR) ", synctest_pos + 1, modulation);
}
state->lastsynctype = -1;
return (12);
}
}
}
if (exitflag == 1)
{
cleanupAndExit (opts, state);
}
if (synctest_pos < 10200)
{
synctest_pos++;
synctest_p++;
}
else
{
// buffer reset
synctest_pos = 0;
synctest_p = synctest_buf;
noCarrier (opts, state);
}
if (state->lastsynctype != 1)
{
if (synctest_pos >= 1800)
{
if ((opts->errorbars == 1) && (opts->verbose > 1) && (state->carrier == 1))
{
printf ("Sync: no sync\n");
}
noCarrier (opts, state);
return (-1);
}
}
}
return (-1);
}

872
src/dsd_main.c Normal file
View File

@@ -0,0 +1,872 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#define _MAIN
#include "dsd.h"
#include "p25p1_const.h"
#include "x2tdma_const.h"
#include "dstar_const.h"
#include "nxdn_const.h"
#include "dmr_const.h"
#include "provoice_const.h"
#include "git_ver.h"
#include "p25p1_heuristics.h"
#include "pa_devs.h"
int
comp (const void *a, const void *b)
{
if (*((const int *) a) == *((const int *) b))
return 0;
else if (*((const int *) a) < *((const int *) b))
return -1;
else
return 1;
}
void
noCarrier (dsd_opts * opts, dsd_state * state)
{
state->dibit_buf_p = state->dibit_buf + 200;
memset (state->dibit_buf, 0, sizeof (int) * 200);
if (opts->mbe_out_f != NULL)
{
closeMbeOutFile (opts, state);
}
state->jitter = -1;
state->lastsynctype = -1;
state->carrier = 0;
state->max = 15000;
state->min = -15000;
state->center = 0;
state->err_str[0] = 0;
sprintf (state->fsubtype, " ");
sprintf (state->ftype, " ");
state->errs = 0;
state->errs2 = 0;
state->lasttg = 0;
state->lastsrc = 0;
state->lastp25type = 0;
state->repeat = 0;
state->nac = 0;
state->numtdulc = 0;
sprintf (state->slot0light, " slot0 ");
sprintf (state->slot1light, " slot1 ");
state->firstframe = 0;
if (opts->audio_gain == (float) 0)
{
state->aout_gain = 25;
}
memset (state->aout_max_buf, 0, sizeof (float) * 200);
state->aout_max_buf_p = state->aout_max_buf;
state->aout_max_buf_idx = 0;
sprintf (state->algid, "________");
sprintf (state->keyid, "________________");
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
}
void
initOpts (dsd_opts * opts)
{
opts->onesymbol = 10;
opts->mbe_in_file[0] = 0;
opts->mbe_in_f = NULL;
opts->errorbars = 1;
opts->datascope = 0;
opts->symboltiming = 0;
opts->verbose = 2;
opts->p25enc = 0;
opts->p25lc = 0;
opts->p25status = 0;
opts->p25tg = 0;
opts->scoperate = 15;
sprintf (opts->audio_in_dev, "/dev/audio");
opts->audio_in_fd = -1;
#ifdef USE_PORTAUDIO
opts->audio_in_pa_stream = NULL;
#endif
sprintf (opts->audio_out_dev, "/dev/audio");
opts->audio_out_fd = -1;
#ifdef USE_PORTAUDIO
opts->audio_out_pa_stream = NULL;
#endif
opts->split = 0;
opts->playoffset = 0;
opts->mbe_out_dir[0] = 0;
opts->mbe_out_file[0] = 0;
opts->mbe_out_path[0] = 0;
opts->mbe_out_f = NULL;
opts->audio_gain = 0;
opts->audio_out = 1;
opts->wav_out_file[0] = 0;
opts->wav_out_f = NULL;
//opts->wav_out_fd = -1;
opts->serial_baud = 115200;
sprintf (opts->serial_dev, "/dev/ttyUSB0");
opts->resume = 0;
opts->frame_dstar = 0;
opts->frame_x2tdma = 1;
opts->frame_p25p1 = 1;
opts->frame_nxdn48 = 0;
opts->frame_nxdn96 = 1;
opts->frame_dmr = 1;
opts->frame_provoice = 0;
opts->mod_c4fm = 1;
opts->mod_qpsk = 1;
opts->mod_gfsk = 1;
opts->uvquality = 3;
opts->inverted_x2tdma = 1; // most transmitter + scanner + sound card combinations show inverted signals for this
opts->inverted_dmr = 0; // most transmitter + scanner + sound card combinations show non-inverted signals for this
opts->mod_threshold = 26;
opts->ssize = 36;
opts->msize = 15;
opts->playfiles = 0;
opts->delay = 0;
opts->use_cosine_filter = 1;
opts->unmute_encrypted_p25 = 0;
}
void
initState (dsd_state * state)
{
int i, j;
state->dibit_buf = malloc (sizeof (int) * 1000000);
state->dibit_buf_p = state->dibit_buf + 200;
memset (state->dibit_buf, 0, sizeof (int) * 200);
state->repeat = 0;
state->audio_out_buf = malloc (sizeof (short) * 1000000);
memset (state->audio_out_buf, 0, 100 * sizeof (short));
state->audio_out_buf_p = state->audio_out_buf + 100;
state->audio_out_float_buf = malloc (sizeof (float) * 1000000);
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
state->audio_out_idx = 0;
state->audio_out_idx2 = 0;
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
//state->wav_out_bytes = 0;
state->center = 0;
state->jitter = -1;
state->synctype = -1;
state->min = -15000;
state->max = 15000;
state->lmid = 0;
state->umid = 0;
state->minref = -12000;
state->maxref = 12000;
state->lastsample = 0;
for (i = 0; i < 128; i++)
{
state->sbuf[i] = 0;
}
state->sidx = 0;
for (i = 0; i < 1024; i++)
{
state->maxbuf[i] = 15000;
}
for (i = 0; i < 1024; i++)
{
state->minbuf[i] = -15000;
}
state->midx = 0;
state->err_str[0] = 0;
sprintf (state->fsubtype, " ");
sprintf (state->ftype, " ");
state->symbolcnt = 0;
state->rf_mod = 0;
state->numflips = 0;
state->lastsynctype = -1;
state->lastp25type = 0;
state->offset = 0;
state->carrier = 0;
for (i = 0; i < 25; i++)
{
for (j = 0; j < 16; j++)
{
state->tg[i][j] = 48;
}
}
state->tgcount = 0;
state->lasttg = 0;
state->lastsrc = 0;
state->nac = 0;
state->errs = 0;
state->errs2 = 0;
state->mbe_file_type = -1;
state->optind = 0;
state->numtdulc = 0;
state->firstframe = 0;
sprintf (state->slot0light, " slot0 ");
sprintf (state->slot1light, " slot1 ");
state->aout_gain = 25;
memset (state->aout_max_buf, 0, sizeof (float) * 200);
state->aout_max_buf_p = state->aout_max_buf;
state->aout_max_buf_idx = 0;
state->samplesPerSymbol = 10;
state->symbolCenter = 4;
sprintf (state->algid, "________");
sprintf (state->keyid, "________________");
state->currentslot = 0;
state->cur_mp = malloc (sizeof (mbe_parms));
state->prev_mp = malloc (sizeof (mbe_parms));
state->prev_mp_enhanced = malloc (sizeof (mbe_parms));
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->p25kid = 0;
state->debug_audio_errors = 0;
state->debug_header_errors = 0;
state->debug_header_critical_errors = 0;
#ifdef TRACE_DSD
state->debug_sample_index = 0;
state->debug_label_file = NULL;
state->debug_label_dibit_file = NULL;
state->debug_label_imbe_file = NULL;
#endif
initialize_p25_heuristics(&state->p25_heuristics);
}
void
usage ()
{
printf ("\n");
printf ("Usage:\n");
printf (" dsd [options] Live scanner mode\n");
printf (" dsd [options] -r <files> Read/Play saved mbe data from file(s)\n");
printf (" dsd -h Show help\n");
printf ("\n");
printf ("Display Options:\n");
printf (" -e Show Frame Info and errorbars (default)\n");
printf (" -pe Show P25 encryption sync bits\n");
printf (" -pl Show P25 link control bits\n");
printf (" -ps Show P25 status bits and low speed data\n");
printf (" -pt Show P25 talkgroup info\n");
printf (" -q Don't show Frame Info/errorbars\n");
printf (" -s Datascope (disables other display options)\n");
printf (" -t Show symbol timing during sync\n");
printf (" -v <num> Frame information Verbosity\n");
printf (" -z <num> Frame rate for datascope\n");
printf ("\n");
printf ("Input/Output options:\n");
printf (" -i <device> Audio input device (default is /dev/audio, - for piped stdin)\n");
printf (" -o <device> Audio output device (default is /dev/audio)\n");
printf (" -d <dir> Create mbe data files, use this directory\n");
printf (" -r <files> Read/Play saved mbe data from file(s)\n");
printf (" -g <num> Audio output gain (default = 0 = auto, disable = -1)\n");
printf (" -n Do not send synthesized speech to audio output device\n");
printf (" -w <file> Output synthesized speech to a .wav file\n");
printf (" -a Display port audio devices\n");
printf ("\n");
printf ("Scanner control options:\n");
printf (" -B <num> Serial port baud rate (default=115200)\n");
printf (" -C <device> Serial port for scanner control (default=/dev/ttyUSB0)\n");
printf (" -R <num> Resume scan after <num> TDULC frames or any PDU or TSDU\n");
printf ("\n");
printf ("Decoder options:\n");
printf (" -fa Auto-detect frame type (default)\n");
printf (" -f1 Decode only P25 Phase 1\n");
printf (" -fd Decode only D-STAR\n");
printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n");
printf (" -fn Decode only NXDN96 (12.5 kHz)\n");
printf (" -fp Decode only ProVoice*\n");
printf (" -fr Decode only DMR/MOTOTRBO\n");
printf (" -fx Decode only X2-TDMA\n");
printf (" -l Disable DMR/MOTOTRBO and NXDN input filtering\n");
printf (" -ma Auto-select modulation optimizations (default)\n");
printf (" -mc Use only C4FM modulation optimizations\n");
printf (" -mg Use only GFSK modulation optimizations\n");
printf (" -mq Use only QPSK modulation optimizations\n");
printf (" -pu Unmute Encrypted P25\n");
printf (" -u <num> Unvoiced speech quality (default=3)\n");
printf (" -xx Expect non-inverted X2-TDMA signal\n");
printf (" -xr Expect inverted DMR/MOTOTRBO signal\n");
printf ("\n");
printf (" * denotes frame types that cannot be auto-detected.\n");
printf ("\n");
printf ("Advanced decoder options:\n");
printf (" -A <num> QPSK modulation auto detection threshold (default=26)\n");
printf (" -S <num> Symbol buffer size for QPSK decision point tracking\n");
printf (" (default=36)\n");
printf (" -M <num> Min/Max buffer size for QPSK decision point tracking\n");
printf (" (default=15)\n");
exit (0);
}
void
liveScanner (dsd_opts * opts, dsd_state * state)
{
#ifdef USE_PORTAUDIO
if(opts->audio_in_type == 2)
{
PaError err = Pa_StartStream( opts->audio_in_pa_stream );
if( err != paNoError )
{
fprintf( stderr, "An error occured while starting the portaudio input stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return;
}
}
#endif
while (1)
{
noCarrier (opts, state);
state->synctype = getFrameSync (opts, state);
// recalibrate center/umid/lmid
state->center = ((state->max) + (state->min)) / 2;
state->umid = (((state->max) - state->center) * 5 / 8) + state->center;
state->lmid = (((state->min) - state->center) * 5 / 8) + state->center;
while (state->synctype != -1)
{
processFrame (opts, state);
#ifdef TRACE_DSD
state->debug_prefix = 'S';
#endif
state->synctype = getFrameSync (opts, state);
#ifdef TRACE_DSD
state->debug_prefix = '\0';
#endif
// recalibrate center/umid/lmid
state->center = ((state->max) + (state->min)) / 2;
state->umid = (((state->max) - state->center) * 5 / 8) + state->center;
state->lmid = (((state->min) - state->center) * 5 / 8) + state->center;
}
}
}
void
cleanupAndExit (dsd_opts * opts, dsd_state * state)
{
noCarrier (opts, state);
if (opts->wav_out_f != NULL)
{
closeWavOutFile (opts, state);
}
#ifdef USE_PORTAUDIO
if((opts->audio_in_type == 2) || (opts->audio_out_type == 2))
{
printf("Terminating portaudio.\n");
PaError err = paNoError;
if(opts->audio_in_pa_stream != NULL)
{
err = Pa_CloseStream( opts->audio_in_pa_stream );
if( err != paNoError )
{
fprintf( stderr, "An error occured while closing the portaudio input stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
}
if(opts->audio_out_pa_stream != NULL)
{
err = Pa_IsStreamActive( opts->audio_out_pa_stream );
if(err == 1)
err = Pa_StopStream( opts->audio_out_pa_stream );
if( err != paNoError )
{
fprintf( stderr, "An error occured while closing the portaudio output stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
err = Pa_CloseStream( opts->audio_out_pa_stream );
if( err != paNoError )
{
fprintf( stderr, "An error occured while closing the portaudio output stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
}
err = Pa_Terminate();
if( err != paNoError )
{
fprintf( stderr, "An error occured while terminating portaudio\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
}
#endif
printf("\n");
printf("Total audio errors: %i\n", state->debug_audio_errors);
printf("Total header errors: %i\n", state->debug_header_errors);
printf("Total irrecoverable header errors: %i\n", state->debug_header_critical_errors);
//debug_print_heuristics(&(state->p25_heuristics));
printf("\n");
printf("+P25 BER estimate: %.2f%%\n", get_P25_BER_estimate(&state->p25_heuristics));
printf("-P25 BER estimate: %.2f%%\n", get_P25_BER_estimate(&state->inv_p25_heuristics));
printf("\n");
#ifdef TRACE_DSD
if (state->debug_label_file != NULL) {
fclose(state->debug_label_file);
state->debug_label_file = NULL;
}
if(state->debug_label_dibit_file != NULL) {
fclose(state->debug_label_dibit_file);
state->debug_label_dibit_file = NULL;
}
if(state->debug_label_imbe_file != NULL) {
fclose(state->debug_label_imbe_file);
state->debug_label_imbe_file = NULL;
}
#endif
printf ("Exiting.\n");
exit (0);
}
void
sigfun (int sig)
{
exitflag = 1;
signal (SIGINT, SIG_DFL);
}
int
main (int argc, char **argv)
{
int c;
extern char *optarg;
extern int optind, opterr, optopt;
dsd_opts opts;
dsd_state state;
char versionstr[25];
mbe_printVersion (versionstr);
printf ("Digital Speech Decoder 1.7.0-dev (build:%s)\n", GIT_TAG);
printf ("mbelib version %s\n", versionstr);
initOpts (&opts);
initState (&state);
exitflag = 0;
signal (SIGINT, sigfun);
while ((c = getopt (argc, argv, "haep:qstv:z:i:o:d:g:nw:B:C:R:f:m:u:x:A:S:M:rl")) != -1)
{
opterr = 0;
switch (c)
{
case 'h':
usage ();
exit (0);
case 'a':
printPortAudioDevices();
exit(0);
case 'e':
opts.errorbars = 1;
opts.datascope = 0;
break;
case 'p':
if (optarg[0] == 'e')
{
opts.p25enc = 1;
}
else if (optarg[0] == 'l')
{
opts.p25lc = 1;
}
else if (optarg[0] == 's')
{
opts.p25status = 1;
}
else if (optarg[0] == 't')
{
opts.p25tg = 1;
}
else if (optarg[0] == 'u')
{
opts.unmute_encrypted_p25 = 1;
}
break;
case 'q':
opts.errorbars = 0;
opts.verbose = 0;
break;
case 's':
opts.errorbars = 0;
opts.p25enc = 0;
opts.p25lc = 0;
opts.p25status = 0;
opts.p25tg = 0;
opts.datascope = 1;
opts.symboltiming = 0;
break;
case 't':
opts.symboltiming = 1;
opts.errorbars = 1;
opts.datascope = 0;
break;
case 'v':
sscanf (optarg, "%d", &opts.verbose);
break;
case 'z':
sscanf (optarg, "%d", &opts.scoperate);
opts.errorbars = 0;
opts.p25enc = 0;
opts.p25lc = 0;
opts.p25status = 0;
opts.p25tg = 0;
opts.datascope = 1;
opts.symboltiming = 0;
printf ("Setting datascope frame rate to %i frame per second.\n", opts.scoperate);
break;
case 'i':
strncpy(opts.audio_in_dev, optarg, 1023);
opts.audio_in_dev[1023] = '\0';
break;
case 'o':
strncpy(opts.audio_out_dev, optarg, 1023);
opts.audio_out_dev[1023] = '\0';
break;
case 'd':
strncpy(opts.mbe_out_dir, optarg, 1023);
opts.mbe_out_dir[1023] = '\0';
printf ("Writing mbe data files to directory %s\n", opts.mbe_out_dir);
break;
case 'g':
sscanf (optarg, "%f", &opts.audio_gain);
if (opts.audio_gain < (float) 0 )
{
printf ("Disabling audio out gain setting\n");
}
else if (opts.audio_gain == (float) 0)
{
opts.audio_gain = (float) 0;
printf ("Enabling audio out auto-gain\n");
}
else
{
printf ("Setting audio out gain to %f\n", opts.audio_gain);
state.aout_gain = opts.audio_gain;
}
break;
case 'n':
opts.audio_out = 0;
printf ("Disabling audio output to soundcard.\n");
break;
case 'w':
strncpy(opts.wav_out_file, optarg, 1023);
opts.wav_out_file[1023] = '\0';
printf ("Writing audio to file %s\n", opts.wav_out_file);
openWavOutFile (&opts, &state);
break;
case 'B':
sscanf (optarg, "%d", &opts.serial_baud);
break;
case 'C':
strncpy(opts.serial_dev, optarg, 1023);
opts.serial_dev[1023] = '\0';
break;
case 'R':
sscanf (optarg, "%d", &opts.resume);
printf ("Enabling scan resume after %i TDULC frames\n", opts.resume);
break;
case 'f':
if (optarg[0] == 'a')
{
opts.frame_dstar = 1;
opts.frame_x2tdma = 1;
opts.frame_p25p1 = 1;
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 1;
opts.frame_dmr = 1;
opts.frame_provoice = 0;
}
else if (optarg[0] == 'd')
{
opts.frame_dstar = 1;
opts.frame_x2tdma = 0;
opts.frame_p25p1 = 0;
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_provoice = 0;
printf ("Decoding only D-STAR frames.\n");
}
else if (optarg[0] == 'x')
{
opts.frame_dstar = 0;
opts.frame_x2tdma = 1;
opts.frame_p25p1 = 0;
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_provoice = 0;
printf ("Decoding only X2-TDMA frames.\n");
}
else if (optarg[0] == 'p')
{
opts.frame_dstar = 0;
opts.frame_x2tdma = 0;
opts.frame_p25p1 = 0;
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_provoice = 1;
state.samplesPerSymbol = 5;
state.symbolCenter = 2;
opts.mod_c4fm = 0;
opts.mod_qpsk = 0;
opts.mod_gfsk = 1;
state.rf_mod = 2;
printf ("Setting symbol rate to 9600 / second\n");
printf ("Enabling only GFSK modulation optimizations.\n");
printf ("Decoding only ProVoice frames.\n");
}
else if (optarg[0] == '1')
{
opts.frame_dstar = 0;
opts.frame_x2tdma = 0;
opts.frame_p25p1 = 1;
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_provoice = 0;
printf ("Decoding only P25 Phase 1 frames.\n");
}
else if (optarg[0] == 'i')
{
opts.frame_dstar = 0;
opts.frame_x2tdma = 0;
opts.frame_p25p1 = 0;
opts.frame_nxdn48 = 1;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_provoice = 0;
state.samplesPerSymbol = 20;
state.symbolCenter = 10;
opts.mod_c4fm = 0;
opts.mod_qpsk = 0;
opts.mod_gfsk = 1;
state.rf_mod = 2;
printf ("Setting symbol rate to 2400 / second\n");
printf ("Enabling only GFSK modulation optimizations.\n");
printf ("Decoding only NXDN 4800 baud frames.\n");
}
else if (optarg[0] == 'n')
{
opts.frame_dstar = 0;
opts.frame_x2tdma = 0;
opts.frame_p25p1 = 0;
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 1;
opts.frame_dmr = 0;
opts.frame_provoice = 0;
opts.mod_c4fm = 0;
opts.mod_qpsk = 0;
opts.mod_gfsk = 1;
state.rf_mod = 2;
printf ("Enabling only GFSK modulation optimizations.\n");
printf ("Decoding only NXDN 9600 baud frames.\n");
}
else if (optarg[0] == 'r')
{
opts.frame_dstar = 0;
opts.frame_x2tdma = 0;
opts.frame_p25p1 = 0;
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 1;
opts.frame_provoice = 0;
printf ("Decoding only DMR/MOTOTRBO frames.\n");
}
break;
case 'm':
if (optarg[0] == 'a')
{
opts.mod_c4fm = 1;
opts.mod_qpsk = 1;
opts.mod_gfsk = 1;
state.rf_mod = 0;
}
else if (optarg[0] == 'c')
{
opts.mod_c4fm = 1;
opts.mod_qpsk = 0;
opts.mod_gfsk = 0;
state.rf_mod = 0;
printf ("Enabling only C4FM modulation optimizations.\n");
}
else if (optarg[0] == 'g')
{
opts.mod_c4fm = 0;
opts.mod_qpsk = 0;
opts.mod_gfsk = 1;
state.rf_mod = 2;
printf ("Enabling only GFSK modulation optimizations.\n");
}
else if (optarg[0] == 'q')
{
opts.mod_c4fm = 0;
opts.mod_qpsk = 1;
opts.mod_gfsk = 0;
state.rf_mod = 1;
printf ("Enabling only QPSK modulation optimizations.\n");
}
break;
case 'u':
sscanf (optarg, "%i", &opts.uvquality);
if (opts.uvquality < 1)
{
opts.uvquality = 1;
}
else if (opts.uvquality > 64)
{
opts.uvquality = 64;
}
printf ("Setting unvoice speech quality to %i waves per band.\n", opts.uvquality);
break;
case 'x':
if (optarg[0] == 'x')
{
opts.inverted_x2tdma = 0;
printf ("Expecting non-inverted X2-TDMA signals.\n");
}
else if (optarg[0] == 'r')
{
opts.inverted_dmr = 1;
printf ("Expecting inverted DMR/MOTOTRBO signals.\n");
}
break;
case 'A':
sscanf (optarg, "%i", &opts.mod_threshold);
printf ("Setting C4FM/QPSK auto detection threshold to %i\n", opts.mod_threshold);
break;
case 'S':
sscanf (optarg, "%i", &opts.ssize);
if (opts.ssize > 128)
{
opts.ssize = 128;
}
else if (opts.ssize < 1)
{
opts.ssize = 1;
}
printf ("Setting QPSK symbol buffer to %i\n", opts.ssize);
break;
case 'M':
sscanf (optarg, "%i", &opts.msize);
if (opts.msize > 1024)
{
opts.msize = 1024;
}
else if (opts.msize < 1)
{
opts.msize = 1;
}
printf ("Setting QPSK Min/Max buffer to %i\n", opts.msize);
break;
case 'r':
opts.playfiles = 1;
opts.errorbars = 0;
opts.datascope = 0;
state.optind = optind;
break;
case 'l':
opts.use_cosine_filter = 0;
break;
default:
usage ();
exit (0);
}
}
if (opts.resume > 0)
{
openSerial (&opts, &state);
}
#ifdef USE_PORTAUDIO
if((strncmp(opts.audio_in_dev, "pa:", 3) == 0)
|| (strncmp(opts.audio_out_dev, "pa:", 3) == 0))
{
printf("Initializing portaudio.\n");
PaError err = Pa_Initialize();
if( err != paNoError )
{
fprintf( stderr, "An error occured while initializing portaudio\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
exit(err);
}
}
#endif
if (opts.playfiles == 1)
{
opts.split = 1;
opts.playoffset = 0;
opts.delay = 0;
if (strlen(opts.wav_out_file) > 0)
{
openWavOutFile (&opts, &state);
}
else
{
openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
}
}
else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0)
{
opts.split = 1;
opts.playoffset = 0;
opts.delay = 0;
if (strlen(opts.wav_out_file) > 0)
{
openWavOutFile (&opts, &state);
}
else
{
openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
}
openAudioInDevice (&opts);
}
else
{
opts.split = 0;
opts.playoffset = 25; // 38
opts.delay = 0;
openAudioInDevice (&opts);
opts.audio_out_fd = opts.audio_in_fd;
}
if (opts.playfiles == 1)
{
playMbeFiles (&opts, &state, argc, argv);
}
else
{
liveScanner (&opts, &state);
}
cleanupAndExit (&opts, &state);
return (0);
}

152
src/dsd_mbe.c Normal file
View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
void
playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
{
int i;
char imbe_d[88];
char ambe_d[49];
for (i = state->optind; i < argc; i++)
{
sprintf (opts->mbe_in_file, "%s", argv[i]);
openMbeInFile (opts, state);
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
printf ("playing %s\n", opts->mbe_in_file);
while (feof (opts->mbe_in_f) == 0)
{
if (state->mbe_file_type == 0)
{
readImbe4400Data (opts, state, imbe_d);
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
processAudio (opts, state);
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1)
{
playSynthesizedVoice (opts, state);
}
}
else if (state->mbe_file_type == 1)
{
readAmbe2450Data (opts, state, ambe_d);
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
processAudio (opts, state);
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1)
{
playSynthesizedVoice (opts, state);
}
}
if (exitflag == 1)
{
cleanupAndExit (opts, state);
}
}
}
}
void
processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24])
{
int i;
char imbe_d[88];
char ambe_d[49];
#ifdef AMBE_PACKET_OUT
char ambe_d_str[50];
#endif
for (i = 0; i < 88; i++)
{
imbe_d[i] = 0;
}
if ((state->synctype == 0) || (state->synctype == 1))
{
// 0 +P25p1
// 1 -P25p1
mbe_processImbe7200x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->mbe_out_f != NULL)
{
saveImbe4400Data (opts, state, imbe_d);
}
}
else if ((state->synctype == 14) || (state->synctype == 15))
{
mbe_processImbe7100x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe7100_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->mbe_out_f != NULL)
{
saveImbe4400Data (opts, state, imbe_d);
}
}
else if ((state->synctype == 6) || (state->synctype == 7))
{
mbe_processAmbe3600x2400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->mbe_out_f != NULL)
{
saveAmbe2450Data (opts, state, ambe_d);
}
}
else
{
mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
#ifdef AMBE_PACKET_OUT
for(i=0; i<49; i++) {
ambe_d_str[i] = ambe_d[i] + '0';
}
ambe_d_str[49] = '\0';
// print binary string
fprintf(stderr, "\n?\t?\t%s\t", ambe_d_str);
// print error data
fprintf(stderr, "E1: %d; E2: %d; S: %s", state->errs, state->errs2, state->err_str);
#endif
if (opts->mbe_out_f != NULL)
{
saveAmbe2450Data (opts, state, ambe_d);
}
}
if (opts->errorbars == 1)
{
printf ("%s", state->err_str);
}
state->debug_audio_errors += state->errs2;
processAudio (opts, state);
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1)
{
playSynthesizedVoice (opts, state);
}
}

90
src/dsd_serial.c Normal file
View File

@@ -0,0 +1,90 @@
#include <termios.h>
#include "dsd.h"
void
openSerial (dsd_opts * opts, dsd_state * state)
{
struct termios tty;
speed_t baud;
printf ("Opening serial port %s and setting baud to %i\n", opts->serial_dev, opts->serial_baud);
opts->serial_fd = open (opts->serial_dev, O_WRONLY);
if (opts->serial_fd == -1)
{
printf ("Error, couldn't open %s\n", opts->serial_dev);
exit (1);
}
tty.c_cflag = 0;
baud = B115200;
switch (opts->serial_baud)
{
case 1200:
baud = B1200;
case 2400:
baud = B2400;
case 4800:
baud = B4800;
case 9600:
baud = B9600;
break;
case 19200:
baud = B19200;
break;
case 38400:
baud = B38400;
break;
case 57600:
baud = B57600;
break;
case 115200:
baud = B115200;
break;
case 230400:
baud = B230400;
break;
}
if (opts->serial_baud > 0)
{
cfsetospeed (&tty, baud);
cfsetispeed (&tty, baud);
}
tty.c_cflag |= (tty.c_cflag & ~CSIZE) | CS8;
tty.c_iflag = IGNBRK;
tty.c_lflag = 0;
tty.c_oflag = 0;
tty.c_cflag &= ~CRTSCTS;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag &= ~CSTOPB;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 5;
tcsetattr (opts->serial_fd, TCSANOW, &tty);
}
void
resumeScan (dsd_opts * opts, dsd_state * state)
{
char cmd[16];
ssize_t result;
if (opts->serial_fd > 0)
{
sprintf (cmd, "\rKEY00\r");
result = write (opts->serial_fd, cmd, 7);
cmd[0] = 2;
cmd[1] = 75;
cmd[2] = 15;
cmd[3] = 3;
cmd[4] = 93;
cmd[5] = 0;
result = write (opts->serial_fd, cmd, 5);
state->numtdulc = 0;
}
}

308
src/dsd_symbol.c Normal file
View File

@@ -0,0 +1,308 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
int
getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
{
short sample;
int i, sum, symbol, count;
ssize_t result;
sum = 0;
count = 0;
for (i = 0; i < state->samplesPerSymbol; i++)
{
// timing control
if ((i == 0) && (have_sync == 0))
{
if (state->samplesPerSymbol == 20)
{
if ((state->jitter >= 7) && (state->jitter <= 10))
{
i--;
}
else if ((state->jitter >= 11) && (state->jitter <= 14))
{
i++;
}
}
else if (state->rf_mod == 1)
{
if ((state->jitter >= 0) && (state->jitter < state->symbolCenter))
{
i++; // fall back
}
else if ((state->jitter > state->symbolCenter) && (state->jitter < 10))
{
i--; // catch up
}
}
else if (state->rf_mod == 2)
{
if ((state->jitter >= state->symbolCenter - 1) && (state->jitter <= state->symbolCenter))
{
i--;
}
else if ((state->jitter >= state->symbolCenter + 1) && (state->jitter <= state->symbolCenter + 2))
{
i++;
}
}
else if (state->rf_mod == 0)
{
if ((state->jitter > 0) && (state->jitter <= state->symbolCenter))
{
i--; // catch up
}
else if ((state->jitter > state->symbolCenter) && (state->jitter < state->samplesPerSymbol))
{
i++; // fall back
}
}
state->jitter = -1;
}
// Read the new sample from the input
if(opts->audio_in_type == 0) {
result = read (opts->audio_in_fd, &sample, 2);
}
else if (opts->audio_in_type == 1) {
result = sf_read_short(opts->audio_in_file, &sample, 1);
if(result == 0) {
cleanupAndExit (opts, state);
}
}
else
{
#ifdef USE_PORTAUDIO
PaError err = Pa_ReadStream( opts->audio_in_pa_stream, &sample, 1 );
if( err != paNoError )
{
fprintf( stderr, "An error occured while using the portaudio input stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
#endif
}
#ifdef TRACE_DSD
state->debug_sample_index++;
#endif
// printf("res: %zd\n, offset: %lld", result, sf_seek(opts->audio_in_file, 0, SEEK_CUR));
if (opts->use_cosine_filter)
{
if (state->lastsynctype >= 10 && state->lastsynctype <= 13)
sample = dmr_filter(sample);
else if (state->lastsynctype == 8 || state->lastsynctype == 9 ||
state->lastsynctype == 16 || state->lastsynctype == 17)
{
if(state->samplesPerSymbol == 20)
{
sample = nxdn_filter(sample);
}
else // the 12.5KHz NXDN filter is the same as the DMR filter
{
sample = dmr_filter(sample);
}
}
}
if ((sample > state->max) && (have_sync == 1) && (state->rf_mod == 0))
{
sample = state->max;
}
else if ((sample < state->min) && (have_sync == 1) && (state->rf_mod == 0))
{
sample = state->min;
}
if (sample > state->center)
{
if (state->lastsample < state->center)
{
state->numflips += 1;
}
if (sample > (state->maxref * 1.25))
{
if (state->lastsample < (state->maxref * 1.25))
{
state->numflips += 1;
}
if ((state->jitter < 0) && (state->rf_mod == 1))
{ // first spike out of place
state->jitter = i;
}
if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1))
{
printf ("O");
}
}
else
{
if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1))
{
printf ("+");
}
if ((state->jitter < 0) && (state->lastsample < state->center) && (state->rf_mod != 1))
{ // first transition edge
state->jitter = i;
}
}
}
else
{ // sample < 0
if (state->lastsample > state->center)
{
state->numflips += 1;
}
if (sample < (state->minref * 1.25))
{
if (state->lastsample > (state->minref * 1.25))
{
state->numflips += 1;
}
if ((state->jitter < 0) && (state->rf_mod == 1))
{ // first spike out of place
state->jitter = i;
}
if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1))
{
printf ("X");
}
}
else
{
if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1))
{
printf ("-");
}
if ((state->jitter < 0) && (state->lastsample > state->center) && (state->rf_mod != 1))
{ // first transition edge
state->jitter = i;
}
}
}
if (state->samplesPerSymbol == 20)
{
if ((i >= 9) && (i <= 11))
{
sum += sample;
count++;
}
}
if (state->samplesPerSymbol == 5)
{
if (i == 2)
{
sum += sample;
count++;
}
}
else
{
if (state->rf_mod == 0)
{
// 0: C4FM modulation
if ((i >= state->symbolCenter - 1) && (i <= state->symbolCenter + 2))
{
sum += sample;
count++;
}
#ifdef TRACE_DSD
if (i == state->symbolCenter - 1) {
state->debug_sample_left_edge = state->debug_sample_index - 1;
}
if (i == state->symbolCenter + 2) {
state->debug_sample_right_edge = state->debug_sample_index - 1;
}
#endif
}
else
{
// 1: QPSK modulation
// 2: GFSK modulation
// Note: this has been changed to use an additional symbol to the left
// On the p25_raw_unencrypted.flac it is evident that the timing
// comes one sample too late.
// This change makes a significant improvement in the BER, at least for
// this file.
//if ((i == state->symbolCenter) || (i == state->symbolCenter + 1))
if ((i == state->symbolCenter - 1) || (i == state->symbolCenter + 1))
{
sum += sample;
count++;
}
#ifdef TRACE_DSD
//if (i == state->symbolCenter) {
if (i == state->symbolCenter - 1) {
state->debug_sample_left_edge = state->debug_sample_index - 1;
}
if (i == state->symbolCenter + 1) {
state->debug_sample_right_edge = state->debug_sample_index - 1;
}
#endif
}
}
state->lastsample = sample;
} // for
symbol = (sum / count);
if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1))
{
if (state->jitter >= 0)
{
printf (" %i\n", state->jitter);
}
else
{
printf ("\n");
}
}
#ifdef TRACE_DSD
if (state->samplesPerSymbol == 10) {
float left, right;
if (state->debug_label_file == NULL) {
state->debug_label_file = fopen ("pp_label.txt", "w");
}
left = state->debug_sample_left_edge / SAMPLE_RATE_IN;
right = state->debug_sample_right_edge / SAMPLE_RATE_IN;
if (state->debug_prefix != '\0') {
if (state->debug_prefix == 'I') {
fprintf(state->debug_label_file, "%f\t%f\t%c%c %i\n", left, right, state->debug_prefix, state->debug_prefix_2, symbol);
} else {
fprintf(state->debug_label_file, "%f\t%f\t%c %i\n", left, right, state->debug_prefix, symbol);
}
} else {
fprintf(state->debug_label_file, "%f\t%f\t%i\n", left, right, symbol);
}
}
#endif
state->symbolcnt++;
return (symbol);
}

68
src/dsd_upsample.c Normal file
View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
void
upsample (dsd_state * state, float invalue)
{
int i, j, sum;
float *outbuf1, c, d;
outbuf1 = state->audio_out_float_buf_p;
outbuf1--;
c = *outbuf1;
d = invalue;
// basic triangle interpolation
outbuf1++;
*outbuf1 = ((invalue * (float) 0.166) + (c * (float) 0.834));
outbuf1++;
*outbuf1 = ((invalue * (float) 0.332) + (c * (float) 0.668));
outbuf1++;
*outbuf1 = ((invalue * (float) 0.5) + (c * (float) 0.5));
outbuf1++;
*outbuf1 = ((invalue * (float) 0.668) + (c * (float) 0.332));
outbuf1++;
*outbuf1 = ((invalue * (float) 0.834) + (c * (float) 0.166));
outbuf1++;
*outbuf1 = d;
outbuf1++;
if (state->audio_out_idx2 > 24)
{
// smoothing
outbuf1 -= 16;
for (j = 0; j < 4; j++)
{
for (i = 0; i < 6; i++)
{
sum = 0;
outbuf1 -= 2;
sum += (int)*outbuf1;
outbuf1 += 2;
sum += (int)*outbuf1;
outbuf1 += 2;
sum += (int)*outbuf1;
outbuf1 -= 2;
*outbuf1 = (sum / (float) 3);
outbuf1++;
}
outbuf1 -= 8;
}
}
}

163
src/dstar.c Normal file
View File

@@ -0,0 +1,163 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Note: D-STAR support is fairly complete at this point.
* The ambe3600x2450 decoder is similar butnot compatible with D-STAR voice frames.
* The dstar interleave pattern is different as well.
* GMSK modulation optimizations will also required to get a usable bit error
*/
#include "dsd.h"
#include "dstar_const.h"
#include "dstar_header.h"
void processDSTAR(dsd_opts * opts, dsd_state * state) {
// extracts AMBE frames from D-STAR voice frame
int i, j, dibit;
char ambe_fr[4][24];
unsigned char data[9];
unsigned int bits[4];
int framecount;
int sync_missed = 0;
unsigned char slowdata[4];
unsigned int bitbuffer = 0;
const int *w, *x;
if (opts->errorbars == 1) {
printf("e:");
}
#ifdef DSTAR_DUMP
printf ("\n");
#endif
if (state->synctype == 18) {
framecount = 0;
state->synctype = 6;
} else if (state->synctype == 19) {
framecount = 0;
state->synctype = 7;
} else {
framecount = 1; //just saw a sync frame; there should be 20 not 21 till the next
}
while (sync_missed < 3) {
memset(ambe_fr, 0, 96);
// voice frame
w = dW;
x = dX;
for (i = 0; i < 72; i++) {
dibit = getDibit(opts, state);
bitbuffer <<= 1;
if (dibit == 1) {
bitbuffer |= 0x01;
}
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) {
// we're slipping bits
printf("sync in voice after i=%d, restarting\n", i);
//ugh just start over
i = 0;
w = dW;
x = dX;
framecount = 1;
continue;
}
ambe_fr[*w][*x] = (1 & dibit);
w++;
x++;
}
processMbeFrame(opts, state, NULL, ambe_fr, NULL);
// data frame - 24 bits
for (i = 73; i < 97; i++) {
dibit = getDibit(opts, state);
bitbuffer <<= 1;
if (dibit == 1) {
bitbuffer |= 0x01;
}
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) {
// looking if we're slipping bits
if (i != 96) {
printf("sync after i=%d\n", i);
i = 96;
}
}
}
slowdata[0] = (bitbuffer >> 16) & 0x000000FF;
slowdata[1] = (bitbuffer >> 8) & 0x000000FF;
slowdata[2] = (bitbuffer) & 0x000000FF;
slowdata[3] = 0;
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) {
//We got sync!
//printf("Sync on framecount = %d\n", framecount);
sync_missed = 0;
} else if ((bitbuffer & 0x00FFFFFF) == 0xAAAAAA) {
//End of transmission
printf("End of transmission\n");
goto end;
} else if (framecount % 21 == 0) {
printf("Missed sync on framecount = %d, value = %x/%x/%x\n",
framecount, slowdata[0], slowdata[1], slowdata[2]);
sync_missed++;
} else if (framecount != 0 && (bitbuffer & 0x00FFFFFF) != 0x000000) {
slowdata[0] ^= 0x70;
slowdata[1] ^= 0x4f;
slowdata[2] ^= 0x93;
//printf("unscrambled- %s",slowdata);
} else if (framecount == 0) {
//printf("never scrambled-%s\n",slowdata);
}
framecount++;
}
end: if (opts->errorbars == 1) {
printf("\n");
}
}
void processDSTAR_HD(dsd_opts * opts, dsd_state * state) {
int i, j;
int radioheaderbuffer[660];
for (j = 0; j < 660; j++) {
radioheaderbuffer[j] = getDibit(opts, state);
}
// Note: These routines contain GPLed code. Remove if you object to that.
// Due to this, they are in a separate source file.
dstar_header_decode(radioheaderbuffer);
//We officially have sync now, so just pass on to the above routine:
processDSTAR(opts, state);
}

76
src/dstar_header.c Normal file
View File

@@ -0,0 +1,76 @@
/*
*
* This code is taken largely from on1arf's GMSK code. Original copyright below:
*
*
* Copyright (C) 2011 by Kristoff Bonne, ON1ARF
*
* This program 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; version 2 of the License.
*
* This program 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.
*
*/
#include "fcs.h"
#include "descramble.h"
#include "dstar_header.h"
void dstar_header_decode(int radioheaderbuffer[660]) {
int radioheaderbuffer2[660];
unsigned char radioheader[41];
int octetcount, bitcount, loop;
unsigned char bit2octet[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
unsigned int FCSinheader;
unsigned int FCScalculated;
int len;
scramble(radioheaderbuffer, radioheaderbuffer2);
deinterleave(radioheaderbuffer2, radioheaderbuffer);
len = FECdecoder(radioheaderbuffer, radioheaderbuffer2);
memset(radioheader, 0, 41);
// note we receive 330 bits, but we only use 328 of them (41 octets)
// bits 329 and 330 are unused
octetcount = 0;
bitcount = 0;
for (loop = 0; loop < 328; loop++) {
if (radioheaderbuffer2[loop]) {
radioheader[octetcount] |= bit2octet[bitcount];
};
bitcount++;
// increase octetcounter and reset bitcounter every 8 bits
if (bitcount >= 8) {
octetcount++;
bitcount = 0;
}
}
// print header
printf("\nDSTAR HEADER: ");
//printf("FLAG1: %02X - FLAG2: %02X - FLAG3: %02X\n", radioheader[0],
// radioheader[1], radioheader[2]);
printf("RPT 2: %c%c%c%c%c%c%c%c ", radioheader[3], radioheader[4],
radioheader[5], radioheader[6], radioheader[7], radioheader[8],
radioheader[9], radioheader[10]);
printf("RPT 1: %c%c%c%c%c%c%c%c ", radioheader[11], radioheader[12],
radioheader[13], radioheader[14], radioheader[15], radioheader[16],
radioheader[17], radioheader[18]);
printf("YOUR: %c%c%c%c%c%c%c%c ", radioheader[19], radioheader[20],
radioheader[21], radioheader[22], radioheader[23], radioheader[24],
radioheader[25], radioheader[26]);
printf("MY: %c%c%c%c%c%c%c%c/%c%c%c%c\n", radioheader[27],
radioheader[28], radioheader[29], radioheader[30], radioheader[31],
radioheader[32], radioheader[33], radioheader[34], radioheader[35],
radioheader[36], radioheader[37], radioheader[38]);
//FCSinheader = ((radioheader[39] << 8) | radioheader[40]) & 0xFFFF;
//FCScalculated = calc_fcs((unsigned char*) radioheader, 39);
//printf("Check sum = %04X ", FCSinheader);
//if (FCSinheader == FCScalculated) {
// printf("(OK)\n");
//} else {
// printf("(NOT OK- Calculated FCS = %04X)\n", FCScalculated);
//}; // end else - if
}

2
src/git_ver.c.in Normal file
View File

@@ -0,0 +1,2 @@
#define _GIT_TAG "@GIT_TAG@"
const char GIT_TAG[] = _GIT_TAG;

124
src/nxdn96.c Normal file
View File

@@ -0,0 +1,124 @@
#include "dsd.h"
#include "nxdn96_const.h"
void
processNXDN96 (dsd_opts * opts, dsd_state * state)
{
int i, j, k, dibit;
char ambe_fr[4][24];
const int *w, *x, *y, *z;
if (opts->errorbars == 1)
{
printf ("VOICE e:");
}
#ifdef NXDN_DUMP
printf ("\n");
#endif
for (k = 0; k < 4; k++)
{
for (i = 0; i < 222; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
printf ("%c", dibit + 48);
#endif
}
#ifdef NXDN_DUMP
printf (" ");
#endif
if (k < 3)
{
for (j = 0; j < 4; j++)
{
w = nW;
x = nX;
y = nY;
z = nZ;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
printf ("%c", dibit + 48);
#endif
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
#ifdef NXDN_DUMP
printf (" ");
#endif
}
}
else
{
for (j = 0; j < 3; j++) // we skip the last voice frame until frame sync can work with < 24 symbols
{
w = nW;
x = nX;
y = nY;
z = nZ;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
printf ("%c", dibit + 48);
#endif
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
#ifdef NXDN_DUMP
printf (" ");
#endif
}
}
if (k < 3)
{
for (i = 0; i < 18; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
printf ("%c", dibit + 48);
#endif
}
#ifdef NXDN_DUMP
printf (" ");
#endif
}
else
{
for (i = 0; i < 30; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
printf ("%c", dibit + 48);
#endif
}
}
}
#ifdef NXDN_DUMP
printf ("\n");
#endif
if (opts->errorbars == 1)
{
printf ("\n");
}
}

36
src/nxdn_data.c Normal file
View File

@@ -0,0 +1,36 @@
#include "dsd.h"
void
processNXDNData (dsd_opts * opts, dsd_state * state)
{
int i, dibit;
if (opts->errorbars == 1)
{
printf ("DATA ");
}
for (i = 0; i < 30; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
printf ("%c", dibit + 48);
#endif
}
#ifdef NXDN_DUMP
printf (" ");
#endif
for (i = 0; i < 144; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
printf ("%c", dibit + 48);
#endif
}
if (opts->errorbars == 1)
{
printf ("\n");
}
}

59
src/nxdn_voice.c Normal file
View File

@@ -0,0 +1,59 @@
#include "dsd.h"
#include "nxdn_const.h"
void
processNXDNVoice (dsd_opts * opts, dsd_state * state)
{
int i, j, dibit;
char ambe_fr[4][24];
const int *w, *x, *y, *z;
const char *pr;
if (opts->errorbars == 1)
{
printf ("VOICE e:");
}
for (i = 0; i < 30; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
printf ("%c", dibit + 48);
#endif
}
#ifdef NXDN_DUMP
printf (" ");
#endif
pr = nxdnpr;
for (j = 0; j < 4; j++)
{
w = nW;
x = nX;
y = nY;
z = nZ;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
printf ("%c", dibit + 48);
#endif
ambe_fr[*w][*x] = *pr ^ (1 & (dibit >> 1)); // bit 1
pr++;
ambe_fr[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
#ifdef NXDN_DUMP
printf (" ");
#endif
}
if (opts->errorbars == 1)
{
printf ("\n");
}
}

160
src/p25_lcw.c Normal file
View File

@@ -0,0 +1,160 @@
#include "dsd.h"
void
processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo)
{
char tgid[17], tmpstr[255];
long talkgroup, source;
int i, j;
tgid[16] = 0;
if (opts->p25lc == 1)
{
printf ("lcformat: %s mfid: %s lcinfo: %s ", lcformat, mfid, lcinfo);
if (opts->p25tg == 0)
{
printf ("\n");
}
}
if (strcmp (lcformat, "00000100") == 0)
{
// first tg is the active channel
j = 0;
for (i = 40; i < 52; i++)
{
if (state->tgcount < 24)
{
state->tg[state->tgcount][j] = lcinfo[i];
}
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[12] = 48;
tmpstr[13] = 48;
tmpstr[14] = 48;
tmpstr[15] = 48;
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
state->lasttg = talkgroup;
if (state->tgcount < 24)
{
state->tgcount = state->tgcount + 1;
}
if (opts->p25tg == 1)
{
printf ("tg: %li ", talkgroup);
}
if (opts->p25tg == 1)
{
printf ("tg: %li ", talkgroup);
// the remaining 3 appear to be other active tg's on the system
j = 0;
for (i = 28; i < 40; i++)
{
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[12] = 48;
tmpstr[13] = 48;
tmpstr[14] = 48;
tmpstr[15] = 48;
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
printf ("%li ", talkgroup);
j = 0;
for (i = 16; i < 28; i++)
{
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[12] = 48;
tmpstr[13] = 48;
tmpstr[14] = 48;
tmpstr[15] = 48;
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
printf ("%li ", talkgroup);
j = 0;
for (i = 4; i < 16; i++)
{
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[12] = 48;
tmpstr[13] = 48;
tmpstr[14] = 48;
tmpstr[15] = 48;
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
printf ("%li\n", talkgroup);
}
}
else if (strcmp (lcformat, "00000000") == 0)
{
j = 0;
if (strcmp (mfid, "10010000") == 0)
{
for (i = 20; i < 32; i++)
{
if (state->tgcount < 24)
{
state->tg[state->tgcount][j] = lcinfo[i];
}
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[12] = 48;
tmpstr[13] = 48;
tmpstr[14] = 48;
tmpstr[15] = 48;
}
else
{
for (i = 16; i < 32; i++)
{
if (state->tgcount < 24)
{
state->tg[state->tgcount][j] = lcinfo[i];
}
tmpstr[j] = lcinfo[i];
j++;
}
}
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
state->lasttg = talkgroup;
if (state->tgcount < 24)
{
state->tgcount = state->tgcount + 1;
}
if (opts->p25tg == 1)
{
printf ("tg: %li ", talkgroup);
}
j = 0;
for (i = 32; i < 56; i++)
{
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[24] = 0;
source = strtol (tmpstr, NULL, 2);
state->lastsrc = source;
if (opts->p25tg == 1)
{
printf ("src: %li emr: %c\n", source, lcinfo[0]);
}
}
else if ((opts->p25tg == 1) && (opts->p25lc == 1))
{
printf ("\n");
}
}

142
src/p25p1_check_hdu.cpp Normal file
View File

@@ -0,0 +1,142 @@
#include "p25p1_check_hdu.h"
#include "ReedSolomon.hpp"
#include "Golay24.hpp"
// Uncomment for very verbose trace messages
//#define CHECK_HDU_DEBUG
// The following methods are just a C bridge for the C++ implementations of the Golay and ReedSolomon
// algorithms.
static DSDGolay24 golay24;
static DSDReedSolomon_36_20_17 reed_solomon_36_20_17;
int check_and_fix_golay_24_6(char* hex, char* parity, int* fixed_errors)
{
#ifdef CHECK_HDU_DEBUG
printf("[");
for(unsigned int i=0; i<6; i++) {
printf("%c", (hex[i] != 0)? 'X': ' ');
}
printf("] [");
for(unsigned int i=12; i<24; i++) {
printf("%c", (parity[i-12] != 0)? 'X': ' ');
}
printf("]");
#endif
int irrecoverable_errors = golay24.decode_6(hex, parity, fixed_errors);
#ifdef CHECK_HDU_DEBUG
printf(" -> [");
for(unsigned int i=0; i<6; i++) {
printf("%c", (hex[i] != 0)? 'X': ' ');
}
printf("]");
if (irrecoverable_errors) {
printf(" Errors: >4");
} else {
printf(" Errors: %i", *fixed_errors);
}
printf("\n");
#endif
return irrecoverable_errors;
}
int check_and_fix_golay_24_12(char* dodeca, char* parity, int* fixed_errors)
{
#ifdef CHECK_HDU_DEBUG
printf("[");
for(unsigned int i=0; i<12; i++) {
printf("%c", (dodeca[i] != 0)? 'X': ' ');
}
printf("] [");
for(unsigned int i=12; i<24; i++) {
printf("%c", (parity[i-12] != 0)? 'X': ' ');
}
printf("]");
#endif
int irrecoverable_errors = golay24.decode_12(dodeca, parity, fixed_errors);
#ifdef CHECK_HDU_DEBUG
printf(" -> [");
for(unsigned int i=0; i<12; i++) {
printf("%c", (dodeca[i] != 0)? 'X': ' ');
}
printf("]");
if (irrecoverable_errors) {
printf(" Errors: >4");
} else {
printf(" Errors: %i", *fixed_errors);
}
printf("\n");
#endif
return irrecoverable_errors;
}
void encode_golay_24_6(char* hex, char* out_parity)
{
golay24.encode_6(hex, out_parity);
}
void encode_golay_24_12(char* dodeca, char* out_parity)
{
golay24.encode_12(dodeca, out_parity);
}
int check_and_fix_redsolomon_36_20_17(char* data, char* parity)
{
#ifdef CHECK_HDU_DEBUG
char original[20][6];
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 6; j++) {
original[i][j] = data[i*6+j];
}
}
#endif
int irrecoverable_errors = reed_solomon_36_20_17.decode(data, parity);
#ifdef CHECK_HDU_DEBUG
printf("Results for Reed-Solomon code (36,20,17)\n\n");
if (irrecoverable_errors == 0) {
printf(" i original fixed\n");
for (int i = 0; i < 20; i++) {
printf("%3d [", i);
for (int j = 0; j < 6; j++) {
printf("%c", (original[i][j] == 1)? 'X' : ' ');
}
printf("] [");
for (int j = 0; j < 6; j++) {
printf("%c", (data[i*6+j] == 1)? 'X' : ' ');
}
printf("]\n");
}
} else {
printf("Irrecoverable errors found\n");
printf(" i original fixed\n");
for (int i = 0; i < 20; i++) {
printf("%3d [", i);
for (int j = 0; j < 6; j++) {
printf("%c", (original[i][j] == 1)? 'X' : ' ');
}
printf("]\n");
}
}
printf("\n");
#endif
return irrecoverable_errors;
}
void encode_reedsolomon_36_20_17(char* hex_data, char* fixed_parity)
{
reed_solomon_36_20_17.encode(hex_data, fixed_parity);
}

125
src/p25p1_check_ldu.cpp Normal file
View File

@@ -0,0 +1,125 @@
#include "p25p1_check_ldu.h"
#include "Hamming.hpp"
#include "ReedSolomon.hpp"
// Uncomment for very verbose trace messages
//#define CHECK_LDU_DEBUG
// The following methods are just a C bridge for the C++ implementations of the Golay and ReedSolomon
// algorithms.
static Hamming_10_6_3_TableImpl hamming;
static DSDReedSolomon_24_12_13 reed_solomon_24_12_13;
static DSDReedSolomon_24_16_9 reed_solomon_24_16_9;
int check_and_fix_hamming_10_6_3(char* hex, char* parity)
{
return hamming.decode(hex, parity);
}
void encode_hamming_10_6_3(char* hex, char* out_parity)
{
hamming.encode(hex, out_parity);
}
int check_and_fix_reedsolomon_24_12_13(char* data, char* parity)
{
#ifdef CHECK_LDU_DEBUG
char original[12][6];
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 6; j++) {
original[i][j] = data[i*6+j];
}
}
#endif
int irrecoverable_error = reed_solomon_24_12_13.decode(data, parity);
#ifdef CHECK_LDU_DEBUG
printf("Results for Reed-Solomon code (24,12,13)\n\n");
if (irrecoverable_error == 0) {
printf(" i original fixed\n");
for (int i = 0; i < 12; i++) {
printf("%3d [", i);
for (int j = 0; j < 6; j++) {
printf("%c", (original[i][j] == 1)? 'X' : ' ');
}
printf("] [");
for (int j = 0; j < 6; j++) {
printf("%c", (data[i*6+j] == 1)? 'X' : ' ');
}
printf("]\n");
}
} else {
printf("Irrecoverable errors found\n");
printf(" i original fixed\n");
for (int i = 0; i < 12; i++) {
printf("%3d [", i);
for (int j = 0; j < 6; j++) {
printf("%c", (original[i][j] == 1)? 'X' : ' ');
}
printf("]\n");
}
}
printf("\n");
#endif
return irrecoverable_error;
}
void encode_reedsolomon_24_12_13(char* hex_data, char* fixed_parity)
{
reed_solomon_24_12_13.encode(hex_data, fixed_parity);
}
int check_and_fix_reedsolomon_24_16_9(char* data, char* parity)
{
#ifdef CHECK_LDU_DEBUG
char original[16][6];
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 6; j++) {
original[i][j] = data[i*6+j];
}
}
#endif
int irrecoverable_error = reed_solomon_24_16_9.decode(data, parity);
#ifdef CHECK_LDU_DEBUG
printf("Results for Reed-Solomon code (24,16,9)\n\n");
if (irrecoverable_error == 0) {
printf(" i original fixed\n");
for (int i = 0; i < 16; i++) {
printf("%3d [", i);
for (int j = 0; j < 6; j++) {
printf("%c", (original[i][j] == 1)? 'X' : ' ');
}
printf("] [");
for (int j = 0; j < 6; j++) {
printf("%c", (data[i*6+j] == 1)? 'X' : ' ');
}
printf("]\n");
}
} else {
printf("Irrecoverable errors found\n");
printf(" i original fixed\n");
for (int i = 0; i < 16; i++) {
printf("%3d [", i);
for (int j = 0; j < 6; j++) {
printf("%c", (original[i][j] == 1)? 'X' : ' ');
}
printf("]\n");
}
}
printf("\n");
#endif
return irrecoverable_error;
}
void encode_reedsolomon_24_16_9(char* hex_data, char* fixed_parity)
{
reed_solomon_24_16_9.encode(hex_data, fixed_parity);
}

93
src/p25p1_check_nid.cpp Normal file
View File

@@ -0,0 +1,93 @@
#include <itpp/itcomm.h>
#include "p25p1_check_nid.h"
using namespace itpp;
// Ideas taken from http://op25.osmocom.org/trac/wiki.png/browser/op25/gr-op25/lib/decoder_ff_impl.cc
// See also p25_training_guide.pdf page 48.
// See also tia-102-baaa-a-project_25-fdma-common_air_interface.pdf page 40.
// BCH encoder/decoder implementation from IT++. GNU GPL 3 license.
itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true);
/**
* Convenience class to calculate the parity of the DUID values. Keeps a table with the expected outcomes
* for fast lookup.
*/
class ParityTable
{
private:
unsigned char table[16];
unsigned char get_index(unsigned char x, unsigned char y)
{
return (x<<2) + y;
}
public:
ParityTable()
{
for (unsigned int i=0; i<sizeof(table); i++) {
table[i] = 0;
}
table[get_index(1,1)] = 1;
table[get_index(2,2)] = 1;
}
unsigned char get_value(unsigned char x, unsigned char y)
{
return table[get_index(x,y)];
}
} parity_table;
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity)
{
int result;
// Fill up with the given input
bvec input(63);
for(unsigned int i=0; i<63; i++) {
input[i] = bch_code[i];
}
// Decode it
bvec decoded, cw_isvalid;
bool ok = bch.decode(input, decoded, cw_isvalid);
if (!ok) {
// Decode failed
result = 0;
} else {
// Take the NAC from the decoded output. It's a 12 bit number starting from position 0.
// Just convert the output from a binary sequence to an integer.
int nac = 0;
for (int i=0; i<12; i++) {
nac <<= 1;
nac |= (int)decoded[i];
}
*new_nac = nac;
// Take the fixed DUID from the encoded output. 4 bit value starting at position 12.
unsigned char new_duid_0 = (((int)decoded[12])<<1) + ((int)decoded[13]);
unsigned char new_duid_1 = (((int)decoded[14])<<1) + ((int)decoded[15]);
new_duid[0] = new_duid_0 + '0';
new_duid[1] = new_duid_1 + '0';
new_duid[2] = 0; // Null terminate
// Check the parity
unsigned char expected_parity = parity_table.get_value(new_duid_0, new_duid_1);
if (expected_parity != parity) {
// Ignore, not sure what to do
//printf("Error in parity detected?");
}
result = 1;
}
return result;
}

511
src/p25p1_hdu.c Normal file
View File

@@ -0,0 +1,511 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
#include "p25p1_hdu.h"
#include "p25p1_check_hdu.h"
#include "p25p1_heuristics.h"
int
read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count, int* analog_signal, int* did_read_status)
{
int dibit;
int status;
if (*status_count == 35) {
#ifdef TRACE_DSD
char prev_prefix = state->debug_prefix;
state->debug_prefix = 's';
#endif
// Status bits now
status = getDibit (opts, state);
// TODO: do something useful with the status bits...
if (did_read_status != NULL) {
*did_read_status = 1;
}
*status_count = 1;
#ifdef TRACE_DSD
state->debug_prefix = prev_prefix;
#endif
} else {
if (did_read_status != NULL) {
*did_read_status = 0;
}
(*status_count)++;
}
dibit = get_dibit_and_analog_signal (opts, state, analog_signal);
output[0] = (1 & (dibit >> 1)); // bit 1
output[1] = (1 & dibit); // bit 0
return dibit;
}
void
read_dibit_update_analog_data (dsd_opts* opts, dsd_state* state, char* output, unsigned int count, int* status_count,
AnalogSignal* analog_signal_array, int* analog_signal_index)
{
unsigned int i;
unsigned int debug_left, debug_right;
for (i=0; i<count; i+=2)
{
// We read two bits on each call
int analog_signal;
int did_read_status;
int dibit;
dibit = read_dibit(opts, state, output + i, status_count, &analog_signal, &did_read_status);
if (analog_signal_array != NULL)
{
// Fill up the AnalogSignal struct
analog_signal_array[*analog_signal_index].value = analog_signal;
analog_signal_array[*analog_signal_index].dibit = dibit;
analog_signal_array[*analog_signal_index].sequence_broken = did_read_status;
(*analog_signal_index)++;
}
}
}
void
read_word (dsd_opts* opts, dsd_state* state, char* word, unsigned int length, int* status_count,
AnalogSignal* analog_signal_array, int* analog_signal_index)
{
read_dibit_update_analog_data(opts, state, word, length, status_count, analog_signal_array, analog_signal_index);
}
void
read_golay24_parity (dsd_opts* opts, dsd_state* state, char* parity, int* status_count,
AnalogSignal* analog_signal_array, int* analog_signal_index)
{
read_dibit_update_analog_data(opts, state, parity, 12, status_count, analog_signal_array, analog_signal_index);
}
void
read_hamm_parity (dsd_opts* opts, dsd_state* state, char* parity, int* status_count,
AnalogSignal* analog_signal_array, int* analog_signal_index)
{
// Read 2 dibits = read 4 bits.
read_dibit_update_analog_data(opts, state, parity, 4, status_count, analog_signal_array, analog_signal_index);
}
/**
* Corrects a hex (6 bit) word using the Golay 24 FEC.
*/
static void
correct_hex_word (dsd_state* state, char* hex, char* parity)
{
int fixed_errors;
int irrecoverable_errors;
irrecoverable_errors = check_and_fix_golay_24_6(hex, parity, &fixed_errors);
state->debug_header_errors += fixed_errors;
if (irrecoverable_errors != 0)
{
state->debug_header_critical_errors++;
}
}
/**
* Reads an hex word, its parity bits and attempts to error correct it using the Golay24 algorithm.
*/
static void
read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count,
AnalogSignal* analog_signal_array, int* analog_signal_index)
{
char parity[12];
// Read the hex word
read_word (opts, state, hex, 6, status_count, analog_signal_array, analog_signal_index);
// Read the parity
read_golay24_parity (opts, state, parity, status_count, analog_signal_array, analog_signal_index);
// Use the Golay24 FEC to correct it. This call modifies the content of hex to fix it, hopefully
correct_hex_word (state, hex, parity);
}
/**
* Uses the information from a corrected sequence of hex words to update the AnalogSignal data.
* The proper Golay 24 parity is calculated from the corrected hex word so we can also fix the Golay parity
* that we read originally from the signal.
* \param corrected_hex_data Pointer to a sequence of hex words that has been error corrected and therefore
* we trust it's correct. Typically this are hex words that has been decoded successfully using a
* Reed-Solomon variant.
* \param hex_count The number of hex words in the sequence.
* \param analog_signal_array A pointer to the AnalogSignal information for the sequence of hex words.
*/
static void
correct_golay_dibits_6(char* corrected_hex_data, int hex_count, AnalogSignal* analog_signal_array)
{
int i, j;
int analog_signal_index;
int dibit;
char parity[12];
analog_signal_index = 0;
for (i=hex_count-1; i>=0; i--)
{
for (j=0; j<6; j+=2) // 3 iterations -> 3 dibits
{
// Given the bits, calculates the dibit
dibit = (corrected_hex_data[i*6+j] << 1) | corrected_hex_data[i*6+j+1];
// Now we know the dibit we should have read from the signal
analog_signal_array[analog_signal_index].corrected_dibit = dibit;
#ifdef HEURISTICS_DEBUG
if (analog_signal_array[analog_signal_index].dibit != dibit)
{
printf("HDU data word corrected from %i to %i, analog value %i\n",
analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value);
}
#endif
analog_signal_index++;
}
// Calculate the Golay 24 parity for the corrected hex word
encode_golay_24_6(corrected_hex_data+i*6, parity);
// Now we know the parity we should have read from the signal. Use this information
for (j=0; j<12; j+=2) // 6 iterations -> 6 dibits
{
// Given the bits, calculates the dibit
dibit = (parity[j] << 1) | parity[j+1];
// Now we know the dibit we should have read from the signal
analog_signal_array[analog_signal_index].corrected_dibit = dibit;
#ifdef HEURISTICS_DEBUG
if (analog_signal_array[analog_signal_index].dibit != dibit)
{
printf("HDU parity corrected from %i to %i, analog value %i\n",
analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value);
}
#endif
analog_signal_index++;
}
}
}
/**
* The important method that processes a full P25 HD unit.
*/
void
processHDU(dsd_opts* opts, dsd_state* state)
{
char mi[73], mfid[9], algid[9], kid[17], tgid[17], tmpstr[255];
int i, j;
long talkgroup;
int algidhex, kidhex;
char hex[6];
int status_count;
int status;
char hex_data[20][6]; // Data in hex-words (6 bit words). A total of 20 hex words.
char hex_parity[16][6]; // Parity of the data, again in hex-word format. A total of 16 parity hex words.
int irrecoverable_errors;
AnalogSignal analog_signal_array[20*(3+6)+16*(3+6)];
int analog_signal_index;
analog_signal_index = 0;
// we skip the status dibits that occur every 36 symbols
// the next status symbol comes in 14 dibits from here
// so we start counter at 36-14-1 = 21
status_count = 21;
// Read 20 hex words, correct them using their Golay 24 parity data.
for (i=19; i>=0; i--)
{
read_and_correct_hex_word (opts, state, hex, &status_count, analog_signal_array, &analog_signal_index);
// Store the corrected hex word into the hex_data store:
for (j=0; j<6; j++)
{
hex_data[i][j] = hex[j];
}
}
// Read the 16 parity hex word. These are used to FEC the 20 hex words using Reed-Solomon.
for (i=15; i>=0; i--)
{
read_and_correct_hex_word (opts, state, hex, &status_count, analog_signal_array, &analog_signal_index);
// Store the corrected hex word into the hex_parity store:
for (j=0; j<6; j++)
{
hex_parity[i][j] = hex[j];
}
}
// Don't forget to mark the first element as the start of a new sequence
analog_signal_array[0].sequence_broken = 1;
// Use the Reed-Solomon algorithm to correct the data. hex_data is modified in place
irrecoverable_errors = check_and_fix_redsolomon_36_20_17((char*)hex_data, (char*)hex_parity);
if (irrecoverable_errors != 0)
{
// The hex words failed the Reed-Solomon check. There were too many errors. Still we can use this
// information to update an estimate of the BER.
state->debug_header_critical_errors++;
// We can correct (17-1)/2 = 8 errors. If we failed, it means that there were more than 8 errors in
// these 20+16 words. But take into account that each hex word was already error corrected with
// Golay 24, which can correct 3 bits on each sequence of (6+12) bits. We could say that there were
// 9 errors of 4 bits.
update_error_stats(&state->p25_heuristics, 20*6+16*6, 9*4);
}
else
{
// The hex words passed the Reed-Solomon check. This means that very likely they are correct and we
// can trust that the digitizer did a good job with them. In other words, each analog value was
// correctly assigned to a dibit. This is extremely useful information for the digitizer and we are
// going to exploit it.
char fixed_parity[16*6];
// Correct the dibits that we did read according with the newly corrected hex_data values
correct_golay_dibits_6((char*)hex_data, 20, analog_signal_array);
// Generate again the Reed-Solomon parity for the corrected data
encode_reedsolomon_36_20_17((char*)hex_data, fixed_parity);
// Correct the dibits that we read according with the corrected parity values
correct_golay_dibits_6(fixed_parity, 16, analog_signal_array+20*(3+6));
// Now we have a bunch of dibits (composed of data and parity of different kinds) that we trust are all
// correct. We also keep a record of the analog values from where each dibit is coming from.
// This information is gold for the heuristics module.
contribute_to_heuristics(state->rf_mod, &(state->p25_heuristics), analog_signal_array, 20*(3+6)+16*(3+6));
}
// Now put the corrected data on the DSD structures
mi[72] = 0;
mfid[8] = 0;
algid[8] = 0;
kid[16] = 0;
tgid[16] = 0;
mi[ 0] = hex_data[19][0] + '0';
mi[ 1] = hex_data[19][1] + '0';
mi[ 2] = hex_data[19][2] + '0';
mi[ 3] = hex_data[19][3] + '0';
mi[ 4] = hex_data[19][4] + '0';
mi[ 5] = hex_data[19][5] + '0';
mi[ 6] = hex_data[18][0] + '0';
mi[ 7] = hex_data[18][1] + '0';
mi[ 8] = hex_data[18][2] + '0';
mi[ 9] = hex_data[18][3] + '0';
mi[10] = hex_data[18][4] + '0';
mi[11] = hex_data[18][5] + '0';
mi[12] = hex_data[17][0] + '0';
mi[13] = hex_data[17][1] + '0';
mi[14] = hex_data[17][2] + '0';
mi[15] = hex_data[17][3] + '0';
mi[16] = hex_data[17][4] + '0';
mi[17] = hex_data[17][5] + '0';
mi[18] = hex_data[16][0] + '0';
mi[19] = hex_data[16][1] + '0';
mi[20] = hex_data[16][2] + '0';
mi[21] = hex_data[16][3] + '0';
mi[22] = hex_data[16][4] + '0';
mi[23] = hex_data[16][5] + '0';
mi[24] = hex_data[15][0] + '0';
mi[25] = hex_data[15][1] + '0';
mi[26] = hex_data[15][2] + '0';
mi[27] = hex_data[15][3] + '0';
mi[28] = hex_data[15][4] + '0';
mi[29] = hex_data[15][5] + '0';
mi[30] = hex_data[14][0] + '0';
mi[31] = hex_data[14][1] + '0';
mi[32] = hex_data[14][2] + '0';
mi[33] = hex_data[14][3] + '0';
mi[34] = hex_data[14][4] + '0';
mi[35] = hex_data[14][5] + '0';
mi[36] = hex_data[13][0] + '0';
mi[37] = hex_data[13][1] + '0';
mi[38] = hex_data[13][2] + '0';
mi[39] = hex_data[13][3] + '0';
mi[40] = hex_data[13][4] + '0';
mi[41] = hex_data[13][5] + '0';
mi[42] = hex_data[12][0] + '0';
mi[43] = hex_data[12][1] + '0';
mi[44] = hex_data[12][2] + '0';
mi[45] = hex_data[12][3] + '0';
mi[46] = hex_data[12][4] + '0';
mi[47] = hex_data[12][5] + '0';
mi[48] = hex_data[11][0] + '0';
mi[49] = hex_data[11][1] + '0';
mi[50] = hex_data[11][2] + '0';
mi[51] = hex_data[11][3] + '0';
mi[52] = hex_data[11][4] + '0';
mi[53] = hex_data[11][5] + '0';
mi[54] = hex_data[10][0] + '0';
mi[55] = hex_data[10][1] + '0';
mi[56] = hex_data[10][2] + '0';
mi[57] = hex_data[10][3] + '0';
mi[58] = hex_data[10][4] + '0';
mi[59] = hex_data[10][5] + '0';
mi[60] = hex_data[ 9][0] + '0';
mi[61] = hex_data[ 9][1] + '0';
mi[62] = hex_data[ 9][2] + '0';
mi[63] = hex_data[ 9][3] + '0';
mi[64] = hex_data[ 9][4] + '0';
mi[65] = hex_data[ 9][5] + '0';
mi[66] = hex_data[ 8][0] + '0';
mi[67] = hex_data[ 8][1] + '0';
mi[68] = hex_data[ 8][2] + '0';
mi[69] = hex_data[ 8][3] + '0';
mi[70] = hex_data[ 8][4] + '0';
mi[71] = hex_data[ 8][5] + '0';
mfid[0] = hex_data[ 7][0] + '0';
mfid[1] = hex_data[ 7][1] + '0';
mfid[2] = hex_data[ 7][2] + '0';
mfid[3] = hex_data[ 7][3] + '0';
mfid[4] = hex_data[ 7][4] + '0';
mfid[5] = hex_data[ 7][5] + '0';
mfid[6] = hex_data[ 6][0] + '0';
mfid[7] = hex_data[ 6][1] + '0';
algid[0] = hex_data[ 6][2] + '0'; // The important algorithm ID. This indicates whether the data is
algid[1] = hex_data[ 6][3] + '0'; // encrypted and if so what is the encryption algorithm used.
algid[2] = hex_data[ 6][4] + '0'; // A code 0x80 here means that the data is unencrypted.
algid[3] = hex_data[ 6][5] + '0';
algid[4] = hex_data[ 5][0] + '0';
algid[5] = hex_data[ 5][1] + '0';
algid[6] = hex_data[ 5][2] + '0';
algid[7] = hex_data[ 5][3] + '0';
kid[ 0] = hex_data[ 5][4] + '0';
kid[ 1] = hex_data[ 5][5] + '0';
kid[ 2] = hex_data[ 4][0] + '0'; // The encryption key ID
kid[ 3] = hex_data[ 4][1] + '0';
kid[ 4] = hex_data[ 4][2] + '0';
kid[ 5] = hex_data[ 4][3] + '0';
kid[ 6] = hex_data[ 4][4] + '0';
kid[ 7] = hex_data[ 4][5] + '0';
kid[ 8] = hex_data[ 3][0] + '0';
kid[ 9] = hex_data[ 3][1] + '0';
kid[10] = hex_data[ 3][2] + '0';
kid[11] = hex_data[ 3][3] + '0';
kid[12] = hex_data[ 3][4] + '0';
kid[13] = hex_data[ 3][5] + '0';
kid[14] = hex_data[ 2][0] + '0';
kid[15] = hex_data[ 2][1] + '0';
tgid[ 0] = hex_data[ 2][2] + '0'; // Talk group ID
tgid[ 1] = hex_data[ 2][3] + '0';
tgid[ 2] = hex_data[ 2][4] + '0';
tgid[ 3] = hex_data[ 2][5] + '0';
tgid[ 4] = hex_data[ 1][0] + '0';
tgid[ 5] = hex_data[ 1][1] + '0';
tgid[ 6] = hex_data[ 1][2] + '0';
tgid[ 7] = hex_data[ 1][3] + '0';
tgid[ 8] = hex_data[ 1][4] + '0';
tgid[ 9] = hex_data[ 1][5] + '0';
tgid[10] = hex_data[ 0][0] + '0';
tgid[11] = hex_data[ 0][1] + '0';
tgid[12] = hex_data[ 0][2] + '0';
tgid[13] = hex_data[ 0][3] + '0';
tgid[14] = hex_data[ 0][4] + '0';
tgid[15] = hex_data[ 0][5] + '0';
state->p25kid = strtol(kid, NULL, 2);
skipDibit (opts, state, 5);
status = getDibit (opts, state);
//TODO: Do something useful with the status bits...
if (opts->p25enc == 1)
{
algidhex = strtol (algid, NULL, 2);
kidhex = strtol (kid, NULL, 2);
printf ("mi: %s algid: $%x kid: $%x\n", mi, algidhex, kidhex);
}
if (opts->p25lc == 1)
{
printf ("mfid: %s tgid: %s ", mfid, tgid);
if (opts->p25tg == 0)
{
printf ("\n");
}
}
j = 0;
if (strcmp (mfid, "10010000") == 0)
{
for (i = 4; i < 16; i++)
{
if (state->tgcount < 24)
{
state->tg[state->tgcount][j] = tgid[i];
}
tmpstr[j] = tgid[i];
j++;
}
tmpstr[12] = '0';
tmpstr[13] = '0';
tmpstr[14] = '0';
tmpstr[15] = '0';
}
else
{
for (i = 0; i < 16; i++)
{
if (state->tgcount < 24)
{
state->tg[state->tgcount][j] = tgid[i];
}
tmpstr[j] = tgid[i];
j++;
}
}
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
state->lasttg = talkgroup;
if (state->tgcount < 24)
{
state->tgcount = state->tgcount + 1;
}
if (opts->p25tg == 1)
{
printf ("tg: %li\n", talkgroup);
}
}

386
src/p25p1_heuristics.c Normal file
View File

@@ -0,0 +1,386 @@
#define _USE_MATH_DEFINES
#include <math.h>
#include "dsd.h"
#include "p25p1_heuristics.h"
/**
* This module is dedicated to improve the accuracy of the digitizer. The digitizer is the piece of code that
* translates an analog value to an actual symbol, in the case of P25, a dibit.
* It implements a simple Gaussian classifier. It's based in the assumption that the analog values from the
* signal follow normal distributions, one single distribution for each symbol.
* Analog values for the dibit "0" will fit into a Gaussian bell curve with a characteristic mean and std
* distribution and the same goes for dibits "1", "2" and "3."
* Hopefully those bell curves are well separated from each other so we can accurately discriminate dibits.
* If we could model the Gaussian of each dibit, then given an analog value, the dibit whose Gaussian fits
* better is the most likely interpretation for that value. By better fit we can calculate the PDF
* (probability density function) for the Gaussian, the one with the highest value is the best fit.
*
* The approach followed here to model the Gaussian for each dibit is to use the error corrected information
* as precise oracles. P25 uses strong error correction, some dibits are doubly protected by Hamming/Golay
* and powerful Reed-Solomon codes. If a sequence of dibits clears the last Reed-Solomon check, we can be
* quite confident that those values are correct. We can use the analog values for those cleared dibits to
* calculate mean and std deviation of our Gaussians. With this we are ready to calculate the PDF of a new
* unknown analog value when required.
* Values that don't clear the Reed-Solomon check are discarded.
* This implementation uses a circular buffer to keep track of the N latest cleared analog dibits so we can
* adapt to changes in the signal.
* A modification was made to improve results for C4FM signals. See next block comment.
*/
/**
* In the C4FM P25 recorded files from the "samples" repository, it can be observed that there is a
* correlation between the correct dibit associated for a given analog value and the value of the previous
* dibit. For instance, in one P25 recording, the dibits "0" come with an average analog signal of
* 3829 when the previous dibit was also "0," but if the previous dibit was a "3" then the average
* analog signal is 6875. These are the mean and std deviations for the full 4x4 combinations of previous and
* current dibits:
*
* 00: count: 200 mean: 3829.12 sd: 540.43 <-
* 01: count: 200 mean: 13352.45 sd: 659.74
* 02: count: 200 mean: -5238.56 sd: 1254.70
* 03: count: 200 mean: -13776.50 sd: 307.41
* 10: count: 200 mean: 3077.74 sd: 1059.00
* 11: count: 200 mean: 11935.11 sd: 776.20
* 12: count: 200 mean: -6079.46 sd: 1003.94
* 13: count: 200 mean: -13845.43 sd: 264.42
* 20: count: 200 mean: 5574.33 sd: 1414.71
* 21: count: 200 mean: 13687.75 sd: 727.68
* 22: count: 200 mean: -4753.38 sd: 765.95
* 23: count: 200 mean: -12342.17 sd: 1372.77
* 30: count: 200 mean: 6875.23 sd: 1837.38 <-
* 31: count: 200 mean: 14527.99 sd: 406.85
* 32: count: 200 mean: -3317.61 sd: 1089.02
* 33: count: 200 mean: -12576.08 sd: 1161.77
* || | | |
* || | | \_std deviation
* || | |
* || | \_mean of the current dibit
* || |
* || \_number of dibits used to calculate mean and std deviation
* ||
* |\_current dibit
* |
* \_previous dibit
*
* This effect is not observed on QPSK or GFSK signals, there the mean values are quite consistent regardless
* of the previous dibit.
*
* The following define enables taking the previous dibit into account for C4FM signals. Comment out
* to disable.
*/
#define USE_PREVIOUS_DIBIT
/**
* There is a minimum of cleared analog values we need to produce a meaningful mean and std deviation.
*/
#define MIN_ELEMENTS_FOR_HEURISTICS 10
//Uncomment to disable the behaviour of this module.
//#define DISABLE_HEURISTICS
/**
* The value of the previous dibit is only taken into account on the C4FM modulation. QPSK and GFSK are
* not improved by this technique.
*/
static int use_previous_dibit(int rf_mod)
{
// 0: C4FM modulation
// 1: QPSK modulation
// 2: GFSK modulation
// Use previoud dibit information when on C4FM
return (rf_mod == 0)? 1 : 0;
}
/**
* Update the model of a symbol's Gaussian with new information.
* \param heuristics Pointer to the P25Heuristics module with all the needed state information.
* \param previous_dibit The cleared previous dibit value.
* \param original_dibit The current dibit as it was interpreted initially.
* \param dibit The current dibit. Will be different from original_dibit if the FEC fixed it.
* \param analog_value The actual analog signal value from which the original_dibit was derived.
*/
static void update_p25_heuristics(P25Heuristics* heuristics, int previous_dibit, int original_dibit, int dibit, int analog_value)
{
float mean;
int old_value;
float old_mean;
SymbolHeuristics* sh;
int number_errors;
#ifndef USE_PREVIOUS_DIBIT
previous_dibit = 0;
#endif
// Locate the Gaussian (SymbolHeuristics structure) we are going to update
sh = &(heuristics->symbols[previous_dibit][dibit]);
// Update the circular buffers of values
old_value = sh->values[sh->index];
old_mean = sh->means[sh->index];
// Update the BER statistics
number_errors = 0;
if (original_dibit != dibit) {
if ((original_dibit == 0 && dibit == 3) || (original_dibit == 3 && dibit == 0) ||
(original_dibit == 1 && dibit == 2) || (original_dibit == 2 && dibit == 1)) {
// Interpreting a "00" as "11", "11" as "00", "01" as "10" or "10" as "01" counts as 2 errors
number_errors = 2;
} else {
// The other 8 combinations count (where original_dibit != dibit) as 1 error.
number_errors = 1;
}
}
update_error_stats(heuristics, 2, number_errors);
// Update the running mean and variance. This is to calculate the PDF faster when required
if (sh->count >= HEURISTICS_SIZE) {
sh->sum -= old_value;
sh->var_sum -= (((float)old_value) - old_mean) * (((float)old_value) - old_mean);
}
sh->sum += analog_value;
sh->values[sh->index] = analog_value;
if (sh->count < HEURISTICS_SIZE) {
sh->count++;
}
mean = sh->sum / ((float)sh->count);
sh->means[sh->index] = mean;
if (sh->index >= (HEURISTICS_SIZE-1)) {
sh->index = 0;
} else {
sh->index++;
}
sh->var_sum += (((float)analog_value) - mean) * (((float)analog_value) - mean);
}
void contribute_to_heuristics(int rf_mod, P25Heuristics* heuristics, AnalogSignal* analog_signal_array, int count)
{
int i;
int use_prev_dibit;
#ifdef USE_PREVIOUS_DIBIT
use_prev_dibit = use_previous_dibit(rf_mod);
#else
use_prev_dibit = 0;
#endif
for (i=0; i<count; i++) {
int use;
int prev_dibit;
if (use_prev_dibit) {
if (analog_signal_array[i].sequence_broken) {
// The sequence of dibits was broken here so we don't have reliable information on the actual
// value of the previous dibit. Don't use this value.
use = 0;
} else {
use = 1;
// The previous dibit is the corrected_dibit of the previous element
prev_dibit = analog_signal_array[i-1].corrected_dibit;
}
} else {
use = 1;
prev_dibit = 0;
}
if (use) {
update_p25_heuristics(heuristics, prev_dibit, analog_signal_array[i].dibit,
analog_signal_array[i].corrected_dibit, analog_signal_array[i].value);
}
}
}
/**
* Initializes the symbol's heuristics state.
* \param sh The SymbolHeuristics structure to initialize.
*/
static void initialize_symbol_heuristics(SymbolHeuristics* sh)
{
sh->count = 0;
sh->index = 0;
sh->sum = 0;
sh->var_sum = 0;
}
void initialize_p25_heuristics(P25Heuristics* heuristics)
{
int i, j;
for (i=0; i<4; i++) {
for (j=0; j<4; j++) {
initialize_symbol_heuristics(&(heuristics->symbols[i][j]));
}
}
heuristics->bit_count = 0;
heuristics->bit_error_count = 0;
}
/**
* Important method to calculate the PDF (probability density function) of the Gaussian.
* TODO: improve performance. Since we are calculating this value to compare it with other PDF we can
* simplify very much. We don't really need to know the actual PDF value, just which Gaussian's got the
* highest PDF, which is a simpler problem.
*/
static float evaluate_pdf(SymbolHeuristics* se, int value)
{
float x = (se->count*((float)value) - se->sum);
float y = -0.5F*x*x/(se->count*se->var_sum);
float pdf = sqrtf(se->count / se->var_sum) * expf(y) / sqrtf(2.0F * ((float) M_PI));
return pdf;
}
/**
* Logging of the internal PDF values for a given analog value and previous dibit.
*/
static void debug_log_pdf(P25Heuristics* heuristics, int previous_dibit, int analog_value)
{
int i;
float pdfs[4];
for (i=0; i<4; i++) {
pdfs[i] = evaluate_pdf(&(heuristics->symbols[previous_dibit][i]), analog_value);
}
printf("v: %i, (%e, %e, %e, %e)\n", analog_value, pdfs[0], pdfs[1], pdfs[2], pdfs[3]);
}
int estimate_symbol(int rf_mod, P25Heuristics* heuristics, int previous_dibit, int analog_value, int* dibit)
{
int valid;
int i;
float pdfs[4];
#ifdef USE_PREVIOUS_DIBIT
int use_prev_dibit = use_previous_dibit(rf_mod);
if (use_prev_dibit == 0)
{
// Ignore
previous_dibit = 0;
}
#else
// Use previous_dibit as it comes.
#endif
valid = 1;
// Check if we have enough values to model the Gaussians for each symbol involved.
for (i=0; i<4; i++) {
if (heuristics->symbols[previous_dibit][i].count >= MIN_ELEMENTS_FOR_HEURISTICS) {
pdfs[i] = evaluate_pdf(&(heuristics->symbols[previous_dibit][i]), analog_value);
} else {
// Not enough data, we don't trust this result
valid = 0;
break;
}
}
if (valid) {
// Find the highest pdf
int max_index;
float max;
max_index = 0;
max = pdfs[0];
for (i=1; i<4; i++) {
if (pdfs[i] > max) {
max_index = i;
max = pdfs[i];
}
}
// The symbol is the one with the highest pdf
*dibit = max_index;
}
#ifdef DISABLE_HEURISTICS
valid = 0;
#endif
return valid;
}
/**
* Logs the internal state of the heuristic's state. Good for debugging.
*/
static void debug_print_symbol_heuristics(int previous_dibit, int dibit, SymbolHeuristics* sh)
{
float mean, sd;
int k;
int n;
n = sh->count;
if (n == 0)
{
mean = 0;
sd = 0;
}
else
{
mean = sh->sum/n;
sd = sqrtf(sh->var_sum / ((float) n));
}
printf("%i%i: count: %2i mean: % 10.2f sd: % 10.2f", previous_dibit, dibit, sh->count, mean, sd);
/*
printf("(");
for (k=0; k<n; k++)
{
if (k != 0)
{
printf(", ");
}
printf("%i", sh->values[k]);
}
printf(")");
*/
printf("\n");
}
void debug_print_heuristics(P25Heuristics* heuristics)
{
int i,j;
printf("\n");
for(i=0; i<4; i++)
{
for(j=0; j<4; j++)
{
debug_print_symbol_heuristics(i, j, &(heuristics->symbols[i][j]));
}
}
}
void update_error_stats(P25Heuristics* heuristics, int bits, int errors)
{
heuristics->bit_count += bits;
heuristics->bit_error_count += errors;
// Normalize to avoid overflow in the counters
if ((heuristics->bit_count & 1) == 0 && (heuristics->bit_error_count & 1) == 0) {
// We can divide both values by 2 safely. We just care about their ratio, not the actual value
heuristics->bit_count >>= 1;
heuristics->bit_error_count >>= 1;
}
}
float get_P25_BER_estimate(P25Heuristics* heuristics)
{
float ber;
if (heuristics->bit_count == 0) {
ber = 0.0F;
} else {
ber = ((float)heuristics->bit_error_count) * 100.0F / ((float)heuristics->bit_count);
}
return ber;
}

269
src/p25p1_ldu.c Normal file
View File

@@ -0,0 +1,269 @@
#include "dsd.h"
#include "p25p1_const.h"
#include "p25p1_hdu.h"
#include "p25p1_check_ldu.h"
#include "p25p1_heuristics.h"
#ifdef TRACE_DSD
static void
debug_write_label_imbe(dsd_state* state, unsigned int cc, int bitindex, char bit)
{
float left, right;
if (state->debug_label_imbe_file == NULL)
{
state->debug_label_imbe_file = fopen ("pp_label_imbe.txt", "w");
}
left = (state->debug_sample_index-10) / 48000.0F;
right = (state->debug_sample_index) / 48000.0F;
fprintf(state->debug_label_imbe_file, "%f\t%f\tC_%i[%i]=%c\n", left, right, cc, bitindex, (bit + '0'));
}
#endif
/**
* Logs the IMBE's c0-c6 words.
*/
static void
debug_log_imbe(char imbe_fr[8][23])
{
int i, j;
printf(" ");
for (j=0; j<4; j++)
{
printf("{");
for (i=0; i<23; i++)
{
if (i>0)
{
printf(", ");
}
printf("%c", (imbe_fr[j][i] + '0'));
}
printf("}; ");
}
for (j=4; j<7; j++)
{
printf("{");
for (i=0; i<15; i++)
{
if (i>0)
{
printf(", ");
}
printf("%c", (imbe_fr[j][i] + '0'));
}
printf("}; ");
}
printf("\n");
}
void
process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count)
{
int j, dibit, status;
char imbe_fr[8][23];
const int *w, *x, *y, *z;
w = iW;
x = iX;
y = iY;
z = iZ;
#ifdef TRACE_DSD
state->debug_prefix = 'I';
#endif
for (j = 0; j < 72; j++)
{
if (*status_count == 35)
{
// Skip the status symbol
#ifdef TRACE_DSD
state->debug_prefix = 's';
#endif
status = getDibit (opts, state);
// TODO: do something useful with the status bits...
*status_count = 1;
#ifdef TRACE_DSD
state->debug_prefix = 'I';
#endif
}
else
{
(*status_count)++;
}
dibit = getDibit (opts, state);
imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
imbe_fr[*y][*z] = (1 & dibit); // bit 0
#ifdef TRACE_DSD
if (*w == 0) {
debug_write_label_imbe(state, 0, *x, (1 & (dibit >> 1)));
}
if (*y == 0) {
debug_write_label_imbe(state, 0, *z, (1 & dibit));
}
#endif
w++;
x++;
y++;
z++;
}
#ifdef TRACE_DSD
state->debug_prefix = '\0';
#endif
if (state->p25kid == 0 || opts->unmute_encrypted_p25 == 1)
{
{
// Check for a non-standard c0 transmitted
// This is explained here: https://github.com/szechyjs/dsd/issues/24
char non_standard_word[23] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0};
int match = 1;
unsigned int i;
for (i=0; i<23; i++) {
if (imbe_fr[0][i] != non_standard_word[i]) {
match = 0;
break;
}
}
if (match) {
// Skip this particular value. If we let it pass it will be signaled as an erroneus IMBE
printf("(Non-standard IMBE c0 detected, skipped)");
} else {
processMbeFrame (opts, state, imbe_fr, NULL, NULL);
}
}
}
}
// Uncomment this line for verbose information on the error correction of the LDU bits.
//#define LDU_DEBUG
void
read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count,
AnalogSignal* analog_signal_array, int* analog_signal_index)
{
char parity[4];
int error_count;
// Read the hex word
read_word (opts, state, hex, 6, status_count, analog_signal_array, analog_signal_index);
// Read the parity
read_hamm_parity (opts, state, parity, status_count, analog_signal_array, analog_signal_index);
#ifdef LDU_DEBUG
printf("[");
for (i = 0; i < 6; i++)
{
printf("%c", (hex[i] == 1)? 'X' : ' ');
}
printf("-");
for (i = 0; i < 4; i++)
{
printf("%c", (parity[i] == 1)? 'X' : ' ');
}
printf("]");
#endif
// Use Hamming to error correct the hex word
error_count = check_and_fix_hamming_10_6_3(hex, parity);
if (error_count == 1)
{
state->debug_header_errors++;
}
else if (error_count ==2)
{
state->debug_header_critical_errors++;
}
#ifdef LDU_DEBUG
printf(" -> [");
for (i = 0; i < 6; i++)
{
printf("%c", (hex[i] == 1)? 'X' : ' ');
}
printf("]");
if (error_count == 1)
{
printf(" fixed!");
}
else if (error_count ==2)
{
printf(" IRRECOVERABLE");
}
printf("\n");
#endif
}
void
correct_hamming_dibits(char* data, int count, AnalogSignal* analog_signal_array)
{
char parity[4];
int i, j;
int analog_signal_index;
analog_signal_index = 0;
for (i=count-1; i>=0; i--)
{
// Take the next 3 dibits (1 hex word) as they are
for (j=0; j<6; j+=2) // 3 iterations -> 3 dibits
{
int dibit = (data[i*6+j] << 1) | data[i*6+j+1];
// This dibit is the correct value we should have read in the first place
analog_signal_array[analog_signal_index].corrected_dibit = dibit;
#ifdef HEURISTICS_DEBUG
if (analog_signal_array[analog_signal_index].dibit != dibit)
{
printf("LDU word corrected from %i to %i, analog value %i\n",
analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value);
}
#endif
analog_signal_index++;
}
// The next two dibits are calculated has the hamming parity of the hex word
encode_hamming_10_6_3(data+i*6, parity);
for (j=0; j<4; j+=2) // 2 iterations -> 2 dibits
{
int dibit = (parity[j] << 1) | parity[j+1];
// Again, this dibit is the correct value we should have read in the first place
analog_signal_array[analog_signal_index].corrected_dibit = dibit;
#ifdef HEURISTICS_DEBUG
if (analog_signal_array[analog_signal_index].dibit != dibit)
{
printf("LDU-HM parity corrected from %i to %i, analog value %i\n",
analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value);
}
#endif
analog_signal_index++;
}
}
}
void
debug_ldu_header(dsd_state* state)
{
#ifdef TRACE_DSD
float s = state->debug_sample_index / 48000.0F;
printf("Start of LDU at sample %f\n", s);
#endif
debug_print_heuristics(&state->p25_heuristics);
}

334
src/p25p1_ldu1.c Normal file
View File

@@ -0,0 +1,334 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
#include "p25p1_const.h"
#include "p25p1_ldu.h"
#include "p25p1_check_ldu.h"
#include "p25p1_hdu.h"
void
processLDU1 (dsd_opts* opts, dsd_state* state)
{
// extracts IMBE frames from LDU frame
int i;
char lcformat[9], mfid[9], lcinfo[57];
char lsd1[9], lsd2[9];
int status_count;
char hex_data[12][6]; // Data in hex-words (6 bit words). A total of 12 hex words.
char hex_parity[12][6]; // Parity of the data, again in hex-word format. A total of 12 parity hex words.
int irrecoverable_errors;
AnalogSignal analog_signal_array[12*(3+2)+12*(3+2)];
int analog_signal_index;
analog_signal_index = 0;
// we skip the status dibits that occur every 36 symbols
// the first IMBE frame starts 14 symbols before next status
// so we start counter at 36-14-1 = 21
status_count = 21;
if (opts->errorbars == 1)
{
printf ("e:");
}
// IMBE 1
#ifdef TRACE_DSD
state->debug_prefix_2 = '0';
#endif
process_IMBE (opts, state, &status_count);
// IMBE 2
#ifdef TRACE_DSD
state->debug_prefix_2 = '1';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 2
read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 9][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 8][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[0*5].sequence_broken = 1;
// IMBE 3
#ifdef TRACE_DSD
state->debug_prefix_2 = '2';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 3
read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 5][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 4][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[4*5].sequence_broken = 1;
// IMBE 4
#ifdef TRACE_DSD
state->debug_prefix_2 = '3';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 4
read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 1][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 0][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[8*5].sequence_broken = 1;
// IMBE 5
#ifdef TRACE_DSD
state->debug_prefix_2 = '4';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 5
read_and_correct_hex_word (opts, state, &(hex_parity[11][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[10][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 9][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 8][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[12*5].sequence_broken = 1;
// IMBE 6
#ifdef TRACE_DSD
state->debug_prefix_2 = '5';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 6
read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 5][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 4][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[16*5].sequence_broken = 1;
// IMBE 7
#ifdef TRACE_DSD
state->debug_prefix_2 = '6';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 7
read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 1][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 0][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[20*5].sequence_broken = 1;
// IMBE 8
#ifdef TRACE_DSD
state->debug_prefix_2 = '7';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 8: LSD (low speed data)
{
char lsd[8];
char cyclic_parity[8];
for (i=0; i<=6; i+=2)
{
read_dibit(opts, state, lsd+i, &status_count, NULL, NULL);
}
for (i=0; i<=6; i+=2)
{
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
}
for (i=0; i<8; i++)
{
lsd1[i] = lsd[i] + '0';
}
for (i=0; i<=6; i+=2)
{
read_dibit(opts, state, lsd+i, &status_count, NULL, NULL);
}
for (i=0; i<=6; i+=2)
{
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
}
for (i=0; i<8; i++)
{
lsd2[i] = lsd[i] + '0';
}
// TODO: error correction of the LSD bytes...
// TODO: do something useful with the LSD bytes...
}
// IMBE 9
#ifdef TRACE_DSD
state->debug_prefix_2 = '8';
#endif
process_IMBE (opts, state, &status_count);
if (opts->errorbars == 1)
{
printf ("\n");
}
if (opts->p25status == 1)
{
printf ("lsd1: %s lsd2: %s\n", lsd1, lsd2);
}
// trailing status symbol
{
int status;
status = getDibit (opts, state) + '0';
// TODO: do something useful with the status bits...
}
// Error correct the hex_data using Reed-Solomon hex_parity
irrecoverable_errors = check_and_fix_reedsolomon_24_12_13((char*)hex_data, (char*)hex_parity);
if (irrecoverable_errors == 1)
{
state->debug_header_critical_errors++;
// We can correct (13-1)/2 = 6 errors. If we failed, it means that there were more than 6 errors in
// these 12+12 words. But take into account that each hex word was already error corrected with
// Hamming(10,6,3), which can correct 1 bits on each sequence of (6+4) bits. We could say that there
// were 7 errors of 2 bits.
update_error_stats(&state->p25_heuristics, 12*6+12*6, 7*2);
}
else
{
// Same comments as in processHDU. See there.
char fixed_parity[12*6];
// Correct the dibits that we read according with hex_data values
correct_hamming_dibits((char*)hex_data, 12, analog_signal_array);
// Generate again the Reed-Solomon parity
encode_reedsolomon_24_12_13((char*)hex_data, fixed_parity);
// Correct the dibits that we read according with the fixed parity values
correct_hamming_dibits(fixed_parity, 12, analog_signal_array+12*(3+2));
// Once corrected, contribute this information to the heuristics module
contribute_to_heuristics(state->rf_mod, &(state->p25_heuristics), analog_signal_array, 12*(3+2)+12*(3+2));
}
#ifdef HEURISTICS_DEBUG
printf("(audio errors, header errors, critical header errors) (%i,%i,%i)\n",
state->debug_audio_errors, state->debug_header_errors, state->debug_header_critical_errors);
#endif
// Now put the corrected data into the DSD structures
lcformat[8] = 0;
mfid[8] = 0;
lcinfo[56] = 0;
lsd1[8] = 0;
lsd2[8] = 0;
lcformat[0] = hex_data[11][0] + '0';
lcformat[1] = hex_data[11][1] + '0';
lcformat[2] = hex_data[11][2] + '0';
lcformat[3] = hex_data[11][3] + '0';
lcformat[4] = hex_data[11][4] + '0';
lcformat[5] = hex_data[11][5] + '0';
lcformat[6] = hex_data[10][0] + '0';
lcformat[7] = hex_data[10][1] + '0';
mfid[0] = hex_data[10][2] + '0';
mfid[1] = hex_data[10][3] + '0';
mfid[2] = hex_data[10][4] + '0';
mfid[3] = hex_data[10][5] + '0';
mfid[4] = hex_data[ 9][0] + '0';
mfid[5] = hex_data[ 9][1] + '0';
mfid[6] = hex_data[ 9][2] + '0';
mfid[7] = hex_data[ 9][3] + '0';
lcinfo[0] = hex_data[ 9][4] + '0';
lcinfo[1] = hex_data[ 9][5] + '0';
lcinfo[2] = hex_data[ 8][0] + '0';
lcinfo[3] = hex_data[ 8][1] + '0';
lcinfo[4] = hex_data[ 8][2] + '0';
lcinfo[5] = hex_data[ 8][3] + '0';
lcinfo[6] = hex_data[ 8][4] + '0';
lcinfo[7] = hex_data[ 8][5] + '0';
lcinfo[8] = hex_data[ 7][0] + '0';
lcinfo[9] = hex_data[ 7][1] + '0';
lcinfo[10] = hex_data[ 7][2] + '0';
lcinfo[11] = hex_data[ 7][3] + '0';
lcinfo[12] = hex_data[ 7][4] + '0';
lcinfo[13] = hex_data[ 7][5] + '0';
lcinfo[14] = hex_data[ 6][0] + '0';
lcinfo[15] = hex_data[ 6][1] + '0';
lcinfo[16] = hex_data[ 6][2] + '0';
lcinfo[17] = hex_data[ 6][3] + '0';
lcinfo[18] = hex_data[ 6][4] + '0';
lcinfo[19] = hex_data[ 6][5] + '0';
lcinfo[20] = hex_data[ 5][0] + '0';
lcinfo[21] = hex_data[ 5][1] + '0';
lcinfo[22] = hex_data[ 5][2] + '0';
lcinfo[23] = hex_data[ 5][3] + '0';
lcinfo[24] = hex_data[ 5][4] + '0';
lcinfo[25] = hex_data[ 5][5] + '0';
lcinfo[26] = hex_data[ 4][0] + '0';
lcinfo[27] = hex_data[ 4][1] + '0';
lcinfo[28] = hex_data[ 4][2] + '0';
lcinfo[29] = hex_data[ 4][3] + '0';
lcinfo[30] = hex_data[ 4][4] + '0';
lcinfo[31] = hex_data[ 4][5] + '0';
lcinfo[32] = hex_data[ 3][0] + '0';
lcinfo[33] = hex_data[ 3][1] + '0';
lcinfo[34] = hex_data[ 3][2] + '0';
lcinfo[35] = hex_data[ 3][3] + '0';
lcinfo[36] = hex_data[ 3][4] + '0';
lcinfo[37] = hex_data[ 3][5] + '0';
lcinfo[38] = hex_data[ 2][0] + '0';
lcinfo[39] = hex_data[ 2][1] + '0';
lcinfo[40] = hex_data[ 2][2] + '0';
lcinfo[41] = hex_data[ 2][3] + '0';
lcinfo[42] = hex_data[ 2][4] + '0';
lcinfo[43] = hex_data[ 2][5] + '0';
lcinfo[44] = hex_data[ 1][0] + '0';
lcinfo[45] = hex_data[ 1][1] + '0';
lcinfo[46] = hex_data[ 1][2] + '0';
lcinfo[47] = hex_data[ 1][3] + '0';
lcinfo[48] = hex_data[ 1][4] + '0';
lcinfo[49] = hex_data[ 1][5] + '0';
lcinfo[50] = hex_data[ 0][0] + '0';
lcinfo[51] = hex_data[ 0][1] + '0';
lcinfo[52] = hex_data[ 0][2] + '0';
lcinfo[53] = hex_data[ 0][3] + '0';
lcinfo[54] = hex_data[ 0][4] + '0';
lcinfo[55] = hex_data[ 0][5] + '0';
processP25lcw (opts, state, lcformat, mfid, lcinfo);
}

370
src/p25p1_ldu2.c Normal file
View File

@@ -0,0 +1,370 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
#include "p25p1_const.h"
#include "p25p1_ldu.h"
#include "p25p1_check_ldu.h"
#include "p25p1_hdu.h"
void
processLDU2 (dsd_opts * opts, dsd_state * state)
{
// extracts IMBE frames from LDU frame
int i;
char mi[73], algid[9], kid[17];
char lsd1[9], lsd2[9];
int algidhex, kidhex;
int status_count;
char hex_data[16][6]; // Data in hex-words (6 bit words). A total of 16 hex words.
char hex_parity[8][6]; // Parity of the data, again in hex-word format. A total of 12 parity hex words.
int irrecoverable_errors;
AnalogSignal analog_signal_array[16*(3+2)+8*(3+2)];
int analog_signal_index;
analog_signal_index = 0;
// we skip the status dibits that occur every 36 symbols
// the first IMBE frame starts 14 symbols before next status
// so we start counter at 36-14-1 = 21
status_count = 21;
if (opts->errorbars == 1)
{
printf ("e:");
}
// IMBE 1
#ifdef TRACE_DSD
state->debug_prefix_2 = '0';
#endif
process_IMBE (opts, state, &status_count);
// IMBE 2
#ifdef TRACE_DSD
state->debug_prefix_2 = '1';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 2
read_and_correct_hex_word (opts, state, &(hex_data[15][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[14][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[13][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[12][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[0*5].sequence_broken = 1;
// IMBE 3
#ifdef TRACE_DSD
state->debug_prefix_2 = '2';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 3
read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 9][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 8][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[4*5].sequence_broken = 1;
// IMBE 4
#ifdef TRACE_DSD
state->debug_prefix_2 = '3';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 4
read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 5][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 4][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[8*5].sequence_broken = 1;
// IMBE 5
#ifdef TRACE_DSD
state->debug_prefix_2 = '4';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 5
read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 1][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_data[ 0][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[12*5].sequence_broken = 1;
// IMBE 6
#ifdef TRACE_DSD
state->debug_prefix_2 = '5';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 6
read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 5][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 4][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[16*5].sequence_broken = 1;
// IMBE 7
#ifdef TRACE_DSD
state->debug_prefix_2 = '6';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 7
read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 1][0]), &status_count, analog_signal_array, &analog_signal_index);
read_and_correct_hex_word (opts, state, &(hex_parity[ 0][0]), &status_count, analog_signal_array, &analog_signal_index);
analog_signal_array[20*5].sequence_broken = 1;
// IMBE 8
#ifdef TRACE_DSD
state->debug_prefix_2 = '7';
#endif
process_IMBE (opts, state, &status_count);
// Read data after IMBE 8: LSD (low speed data)
{
char lsd[8];
char cyclic_parity[8];
for (i=0; i<=6; i+=2)
{
read_dibit(opts, state, lsd+i, &status_count, NULL, NULL);
}
for (i=0; i<=6; i+=2)
{
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
}
for (i=0; i<8; i++)
{
lsd1[i] = lsd[i] + '0';
}
for (i=0; i<=6; i+=2)
{
read_dibit(opts, state, lsd+i, &status_count, NULL, NULL);
}
for (i=0; i<=6; i+=2)
{
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
}
for (i=0; i<8; i++)
{
lsd2[i] = lsd[i] + '0';
}
// TODO: error correction of the LSD bytes...
// TODO: do something useful with the LSD bytes...
}
// IMBE 9
#ifdef TRACE_DSD
state->debug_prefix_2 = '8';
#endif
process_IMBE (opts, state, &status_count);
if (opts->errorbars == 1)
{
printf ("\n");
}
if (opts->p25status == 1)
{
printf ("lsd1: %s lsd2: %s\n", lsd1, lsd2);
}
// trailing status symbol
{
int status;
status = getDibit (opts, state) + '0';
// TODO: do something useful with the status bits...
}
// Error correct the hex_data using Reed-Solomon hex_parity
irrecoverable_errors = check_and_fix_reedsolomon_24_16_9((char*)hex_data, (char*)hex_parity);
if (irrecoverable_errors == 1)
{
state->debug_header_critical_errors++;
// We can correct (9-1)/2 = 4 errors. If we failed, it means that there were more than 4 errors in
// these 12+12 words. But take into account that each hex word was already error corrected with
// Hamming(10,6,3), which can correct 1 bits on each sequence of (6+4) bits. We could say that there
// were 5 errors of 2 bits.
update_error_stats(&state->p25_heuristics, 12*6+12*6, 5*2);
}
else
{
// Same comments as in processHDU. See there.
char fixed_parity[8*6];
// Correct the dibits that we read according with hex_data values
correct_hamming_dibits((char*)hex_data, 16, analog_signal_array);
// Generate again the Reed-Solomon parity
encode_reedsolomon_24_16_9((char*)hex_data, fixed_parity);
// Correct the dibits that we read according with the fixed parity values
correct_hamming_dibits(fixed_parity, 8, analog_signal_array+16*(3+2));
// Once corrected, contribute this information to the heuristics module
contribute_to_heuristics(state->rf_mod, &(state->p25_heuristics), analog_signal_array, 16*(3+2)+8*(3+2));
}
#ifdef HEURISTICS_DEBUG
printf("(audio errors, header errors, critical header errors) (%i,%i,%i)\n",
state->debug_audio_errors, state->debug_header_errors, state->debug_header_critical_errors);
#endif
// Now put the corrected data into the DSD structures
mi[72] = 0;
algid[8] = 0;
kid[16] = 0;
lsd1[8] = 0;
lsd2[8] = 0;
mi[ 0] = hex_data[15][0] + '0';
mi[ 1] = hex_data[15][1] + '0';
mi[ 2] = hex_data[15][2] + '0';
mi[ 3] = hex_data[15][3] + '0';
mi[ 4] = hex_data[15][4] + '0';
mi[ 5] = hex_data[15][5] + '0';
mi[ 6] = hex_data[14][0] + '0';
mi[ 7] = hex_data[14][1] + '0';
mi[ 8] = hex_data[14][2] + '0';
mi[ 9] = hex_data[14][3] + '0';
mi[10] = hex_data[14][4] + '0';
mi[11] = hex_data[14][5] + '0';
mi[12] = hex_data[13][0] + '0';
mi[13] = hex_data[13][1] + '0';
mi[14] = hex_data[13][2] + '0';
mi[15] = hex_data[13][3] + '0';
mi[16] = hex_data[13][4] + '0';
mi[17] = hex_data[13][5] + '0';
mi[18] = hex_data[12][0] + '0';
mi[19] = hex_data[12][1] + '0';
mi[20] = hex_data[12][2] + '0';
mi[21] = hex_data[12][3] + '0';
mi[22] = hex_data[12][4] + '0';
mi[23] = hex_data[12][5] + '0';
mi[24] = hex_data[11][0] + '0';
mi[25] = hex_data[11][1] + '0';
mi[26] = hex_data[11][2] + '0';
mi[27] = hex_data[11][3] + '0';
mi[28] = hex_data[11][4] + '0';
mi[29] = hex_data[11][5] + '0';
mi[30] = hex_data[10][0] + '0';
mi[31] = hex_data[10][1] + '0';
mi[32] = hex_data[10][2] + '0';
mi[33] = hex_data[10][3] + '0';
mi[34] = hex_data[10][4] + '0';
mi[35] = hex_data[10][5] + '0';
mi[36] = hex_data[ 9][0] + '0';
mi[37] = hex_data[ 9][1] + '0';
mi[38] = hex_data[ 9][2] + '0';
mi[39] = hex_data[ 9][3] + '0';
mi[40] = hex_data[ 9][4] + '0';
mi[41] = hex_data[ 9][5] + '0';
mi[42] = hex_data[ 8][0] + '0';
mi[43] = hex_data[ 8][1] + '0';
mi[44] = hex_data[ 8][2] + '0';
mi[45] = hex_data[ 8][3] + '0';
mi[46] = hex_data[ 8][4] + '0';
mi[47] = hex_data[ 8][5] + '0';
mi[48] = hex_data[ 7][0] + '0';
mi[49] = hex_data[ 7][1] + '0';
mi[50] = hex_data[ 7][2] + '0';
mi[51] = hex_data[ 7][3] + '0';
mi[52] = hex_data[ 7][4] + '0';
mi[53] = hex_data[ 7][5] + '0';
mi[54] = hex_data[ 6][0] + '0';
mi[55] = hex_data[ 6][1] + '0';
mi[56] = hex_data[ 6][2] + '0';
mi[57] = hex_data[ 6][3] + '0';
mi[58] = hex_data[ 6][4] + '0';
mi[59] = hex_data[ 6][5] + '0';
mi[60] = hex_data[ 5][0] + '0';
mi[61] = hex_data[ 5][1] + '0';
mi[62] = hex_data[ 5][2] + '0';
mi[63] = hex_data[ 5][3] + '0';
mi[64] = hex_data[ 5][4] + '0';
mi[65] = hex_data[ 5][5] + '0';
mi[66] = hex_data[ 4][0] + '0';
mi[67] = hex_data[ 4][1] + '0';
mi[68] = hex_data[ 4][2] + '0';
mi[69] = hex_data[ 4][3] + '0';
mi[70] = hex_data[ 4][4] + '0';
mi[71] = hex_data[ 4][5] + '0';
algid[0] = hex_data[ 3][0] + '0';
algid[1] = hex_data[ 3][1] + '0';
algid[2] = hex_data[ 3][2] + '0';
algid[3] = hex_data[ 3][3] + '0';
algid[4] = hex_data[ 3][4] + '0';
algid[5] = hex_data[ 3][5] + '0';
algid[6] = hex_data[ 2][0] + '0';
algid[7] = hex_data[ 2][1] + '0';
kid[0] = hex_data[ 2][2] + '0';
kid[1] = hex_data[ 2][3] + '0';
kid[2] = hex_data[ 2][4] + '0';
kid[3] = hex_data[ 2][5] + '0';
kid[4] = hex_data[ 1][0] + '0';
kid[5] = hex_data[ 1][1] + '0';
kid[6] = hex_data[ 1][2] + '0';
kid[7] = hex_data[ 1][3] + '0';
kid[8] = hex_data[ 1][4] + '0';
kid[9] = hex_data[ 1][5] + '0';
kid[10] = hex_data[ 0][0] + '0';
kid[11] = hex_data[ 0][1] + '0';
kid[12] = hex_data[ 0][2] + '0';
kid[13] = hex_data[ 0][3] + '0';
kid[14] = hex_data[ 0][4] + '0';
kid[15] = hex_data[ 0][5] + '0';
if (opts->p25enc == 1)
{
algidhex = strtol (algid, NULL, 2);
kidhex = strtol (kid, NULL, 2);
printf ("mi: %s algid: $%x kid: $%x\n", mi, algidhex, kidhex);
}
}

34
src/p25p1_tdu.c Normal file
View File

@@ -0,0 +1,34 @@
#include "dsd.h"
#include "p25p1_hdu.h"
#include "p25p1_heuristics.h"
void
processTDU (dsd_opts* opts, dsd_state* state)
{
AnalogSignal analog_signal_array[14];
int status_count;
// we skip the status dibits that occur every 36 symbols
// the first IMBE frame starts 14 symbols before next status
// so we start counter at 36-14-1 = 21
status_count = 21;
// Next 14 dibits should be zeros
read_zeros(opts, state, analog_signal_array, 28, &status_count, 1);
// Next we should find an status dibit
if (status_count != 35) {
printf("*** SYNC ERROR\n");
}
// trailing status symbol
{
int status;
status = getDibit (opts, state) + '0';
// TODO: do something useful with the status bits...
}
}

391
src/p25p1_tdulc.c Normal file
View File

@@ -0,0 +1,391 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
#include "p25p1_hdu.h"
#include "p25p1_check_hdu.h"
#include "p25p1_check_ldu.h"
#include "p25p1_heuristics.h"
// Uncomment for some verbose debug info
//#define TDULC_DEBUG
/**
* Reverse the order of bits in a 12-bit word. We need this to accommodate to the expected bit order in
* some algorithms.
* \param dodeca The 12-bit word to reverse.
*/
static void
swap_hex_words_bits(char* dodeca)
{
int j;
for(j=0; j<6; j++)
{
int swap;
swap = dodeca[j];
dodeca[j] = dodeca[j+6];
dodeca[j+6] = swap;
}
}
/**
* Reverse the order of bits in a sequence of six pairs of 12-bit words and their parities.
* \param dodeca_data Pointer to the start of the 12-bit words sequence.
* \param dodeca_parity Pointer to the parities sequence.
*/
static void
swap_hex_words(char* dodeca_data, char* dodeca_parity)
{
int i;
for(i=0; i<6; i++)
{
swap_hex_words_bits(dodeca_data + i*12);
swap_hex_words_bits(dodeca_parity + i*12);
}
}
/**
* Read an hex word, its parity bits and attempts to error correct it using the Hamming algorithm.
*/
static void
read_and_correct_dodeca_word (dsd_opts* opts, dsd_state* state, char* dodeca, int* status_count,
AnalogSignal* analog_signal_array, int* analog_signal_index)
{
char parity[12];
int fixed_errors;
int irrecoverable_errors;
// Read the hex word
read_word (opts, state, dodeca, 12, status_count, analog_signal_array, analog_signal_index);
// Read the parity
read_golay24_parity (opts, state, parity, status_count, analog_signal_array, analog_signal_index);
#ifdef TDULC_DEBUG
printf("[");
for (i = 0; i < 12; i++)
{
printf("%c", (dodeca[i] == 1)? 'X' : ' ');
}
printf("-");
for (i = 0; i < 12; i++)
{
printf("%c", (parity[i] == 1)? 'X' : ' ');
}
printf("]");
#endif
// Use extended golay to error correct the dodeca word
irrecoverable_errors = check_and_fix_golay_24_12(dodeca, parity, &fixed_errors);
state->debug_header_errors += fixed_errors;
if (irrecoverable_errors != 0)
{
state->debug_header_critical_errors++;
}
#ifdef TDULC_DEBUG
printf(" -> [");
for (i = 0; i < 12; i++)
{
printf("%c", (dodeca[i] == 1)? 'X' : ' ');
}
printf("]");
if (irrecoverable_errors == 0)
{
if (fixed_errors > 0)
{
printf(" fixed!");
}
}
else
{
printf(" IRRECOVERABLE");
}
printf("\n");
#endif
}
/**
* Correct the information in analog_signal_array according with the content of data, which has been
* error corrected and should be valid.
* \param data A sequence of 12-bit words.
* \param count Number of words in the sequence.
* \param analog_signal_array Pointer to a sequence of AnalogSignal elements, as many as the value of count.
*/
static void
correct_golay_dibits_12(char* data, int count, AnalogSignal* analog_signal_array)
{
int i, j;
int analog_signal_index;
int dibit;
char parity[12];
analog_signal_index = 0;
for (i=count-1; i>=0; i--)
{
for (j=0; j<12; j+=2) // 6 iterations -> 6 dibits
{
dibit = (data[i*12+j] << 1) | data[i*12+j+1];
analog_signal_array[analog_signal_index].corrected_dibit = dibit;
#ifdef HEURISTICS_DEBUG
if (analog_signal_array[analog_signal_index].dibit != dibit)
{
printf("TDULC data word corrected from %i to %i, analog value %i\n",
analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value);
}
#endif
analog_signal_index++;
}
// Calculate the golay parity for the hex word
encode_golay_24_12(data+i*12, parity);
for (j=0; j<12; j+=2) // 6 iterations -> 6 dibits
{
dibit = (parity[j] << 1) | parity[j+1];
analog_signal_array[analog_signal_index].corrected_dibit = dibit;
#ifdef HEURISTICS_DEBUG
if (analog_signal_array[analog_signal_index].dibit != dibit)
{
printf("TDULC parity corrected from %i to %i, analog value %i\n",
analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value);
}
#endif
analog_signal_index++;
}
}
}
void
read_zeros(dsd_opts* opts, dsd_state* state, AnalogSignal* analog_signal_array, unsigned int length,
int* status_count, int new_sequence)
{
char* buffer;
unsigned int i;
int analog_signal_index;
analog_signal_index = 0;
buffer = malloc(length);
read_dibit_update_analog_data (opts, state, buffer, length, status_count, analog_signal_array, &analog_signal_index);
free(buffer);
if (new_sequence)
{
analog_signal_array[0].sequence_broken = 1;
}
for (i=0;i<length/2;i++)
{
analog_signal_array[i].corrected_dibit = 0;
#ifdef HEURISTICS_DEBUG
if (analog_signal_array[i].corrected_dibit != analog_signal_array[i].dibit)
{
printf("TDULC ending zeros corrected from %i to %i, analog value %i\n",
analog_signal_array[i].dibit, 0, analog_signal_array[i].value);
}
#endif
}
// We know that all these bits should be zero. Use this information for the heuristics module
contribute_to_heuristics(state->rf_mod, &(state->p25_heuristics), analog_signal_array, length/2);
}
void
processTDULC (dsd_opts* opts, dsd_state* state)
{
int i;
char lcinfo[57], lcformat[9], mfid[9];
int status_count;
char dodeca_data[6][12]; // Data in 12-bit words. A total of 6 words.
char dodeca_parity[6][12]; // Reed-Solomon parity of the data. A total of 6 parity 12-bit words.
int irrecoverable_errors;
AnalogSignal analog_signal_array[6*(6+6)+6*(6+6)+10];
int analog_signal_index;
analog_signal_index = 0;
// we skip the status dibits that occur every 36 symbols
// the first IMBE frame starts 14 symbols before next status
// so we start counter at 36-14-1 = 21
status_count = 21;
for(i=5; i>=0; i--) {
read_and_correct_dodeca_word (opts, state, &(dodeca_data[i][0]), &status_count, analog_signal_array, &analog_signal_index);
}
for(i=5; i>=0; i--) {
read_and_correct_dodeca_word (opts, state, &(dodeca_parity[i][0]), &status_count, analog_signal_array, &analog_signal_index);
}
// Swap the two 6-bit words to accommodate for the expected word order of the Reed-Solomon decoding
swap_hex_words((char*)dodeca_data, (char*)dodeca_parity);
// Error correct the hex_data using Reed-Solomon hex_parity
irrecoverable_errors = check_and_fix_reedsolomon_24_12_13((char*)dodeca_data, (char*)dodeca_parity);
// Recover the original order
swap_hex_words((char*)dodeca_data, (char*)dodeca_parity);
if (irrecoverable_errors == 1)
{
state->debug_header_critical_errors++;
// We can correct (13-1)/2 = 6 errors. If we failed, it means that there were more than 6 errors in
// these 12+12 words. But take into account that each hex word was already error corrected with
// Golay 24, which can correct 3 bits on each sequence of (12+12) bits. We could say that there were
// 7 errors of 4 bits.
update_error_stats(&state->p25_heuristics, 12*6+12*6, 7*4);
}
else
{
// Same comments as in processHDU. See there.
char fixed_parity[6*12];
// Correct the dibits that we read according with hex_data values
correct_golay_dibits_12((char*)dodeca_data, 6, analog_signal_array);
// Generate again the Reed-Solomon parity
// Now, swap again for Reed-Solomon
swap_hex_words((char*)dodeca_data, (char*)dodeca_parity);
encode_reedsolomon_24_12_13((char*)dodeca_data, fixed_parity);
// Swap again to recover the original order
swap_hex_words((char*)dodeca_data, fixed_parity);
// Correct the dibits that we read according with the fixed parity values
correct_golay_dibits_12(fixed_parity, 6, analog_signal_array+6*(6+6));
// Once corrected, contribute this information to the heuristics module
analog_signal_array[0].sequence_broken = 1;
contribute_to_heuristics(state->rf_mod, &(state->p25_heuristics), analog_signal_array, 6*(6+6)+6*(6+6));
}
// Next 10 dibits should be zeros
// If an irrecoverable error happens, you should start a new sequence since the previous dibit was not set
read_zeros(opts, state, analog_signal_array + 6*(6+6)+6*(6+6), 20, &status_count, irrecoverable_errors);
// Next we should find an status dibit
if (status_count != 35) {
printf("*** SYNC ERROR\n");
}
// trailing status symbol
{
int status;
status = getDibit (opts, state) + '0';
// TODO: do something useful with the status bits...
}
// Put the corrected data into the DSD structures
lcformat[8] = 0;
mfid[8] = 0;
lcinfo[56] = 0;
lcformat[0] = dodeca_data[5][ 0] + '0';
lcformat[1] = dodeca_data[5][ 1] + '0';
lcformat[2] = dodeca_data[5][ 2] + '0';
lcformat[3] = dodeca_data[5][ 3] + '0';
lcformat[4] = dodeca_data[5][ 4] + '0';
lcformat[5] = dodeca_data[5][ 5] + '0';
lcformat[6] = dodeca_data[5][ 6] + '0';
lcformat[7] = dodeca_data[5][ 7] + '0';
mfid[0] = dodeca_data[5][ 8] + '0';
mfid[1] = dodeca_data[5][ 9] + '0';
mfid[2] = dodeca_data[5][10] + '0';
mfid[3] = dodeca_data[5][11] + '0';
mfid[4] = dodeca_data[4][ 0] + '0';
mfid[5] = dodeca_data[4][ 1] + '0';
mfid[6] = dodeca_data[4][ 2] + '0';
mfid[7] = dodeca_data[4][ 3] + '0';
lcinfo[0] = dodeca_data[4][ 4] + '0';
lcinfo[1] = dodeca_data[4][ 5] + '0';
lcinfo[2] = dodeca_data[4][ 6] + '0';
lcinfo[3] = dodeca_data[4][ 7] + '0';
lcinfo[4] = dodeca_data[4][ 8] + '0';
lcinfo[5] = dodeca_data[4][ 9] + '0';
lcinfo[6] = dodeca_data[4][10] + '0';
lcinfo[7] = dodeca_data[4][11] + '0';
lcinfo[8] = dodeca_data[3][ 0] + '0';
lcinfo[9] = dodeca_data[3][ 1] + '0';
lcinfo[10] = dodeca_data[3][ 2] + '0';
lcinfo[11] = dodeca_data[3][ 3] + '0';
lcinfo[12] = dodeca_data[3][ 4] + '0';
lcinfo[13] = dodeca_data[3][ 5] + '0';
lcinfo[14] = dodeca_data[3][ 6] + '0';
lcinfo[15] = dodeca_data[3][ 7] + '0';
lcinfo[16] = dodeca_data[3][ 8] + '0';
lcinfo[17] = dodeca_data[3][ 9] + '0';
lcinfo[18] = dodeca_data[3][10] + '0';
lcinfo[19] = dodeca_data[3][11] + '0';
lcinfo[20] = dodeca_data[2][ 0] + '0';
lcinfo[21] = dodeca_data[2][ 1] + '0';
lcinfo[22] = dodeca_data[2][ 2] + '0';
lcinfo[23] = dodeca_data[2][ 3] + '0';
lcinfo[24] = dodeca_data[2][ 4] + '0';
lcinfo[25] = dodeca_data[2][ 5] + '0';
lcinfo[26] = dodeca_data[2][ 6] + '0';
lcinfo[27] = dodeca_data[2][ 7] + '0';
lcinfo[28] = dodeca_data[2][ 8] + '0';
lcinfo[29] = dodeca_data[2][ 9] + '0';
lcinfo[30] = dodeca_data[2][10] + '0';
lcinfo[31] = dodeca_data[2][11] + '0';
lcinfo[32] = dodeca_data[1][ 0] + '0';
lcinfo[33] = dodeca_data[1][ 1] + '0';
lcinfo[34] = dodeca_data[1][ 2] + '0';
lcinfo[35] = dodeca_data[1][ 3] + '0';
lcinfo[36] = dodeca_data[1][ 4] + '0';
lcinfo[37] = dodeca_data[1][ 5] + '0';
lcinfo[38] = dodeca_data[1][ 6] + '0';
lcinfo[39] = dodeca_data[1][ 7] + '0';
lcinfo[40] = dodeca_data[1][ 8] + '0';
lcinfo[41] = dodeca_data[1][ 9] + '0';
lcinfo[42] = dodeca_data[1][10] + '0';
lcinfo[43] = dodeca_data[1][11] + '0';
lcinfo[44] = dodeca_data[0][ 0] + '0';
lcinfo[45] = dodeca_data[0][ 1] + '0';
lcinfo[46] = dodeca_data[0][ 2] + '0';
lcinfo[47] = dodeca_data[0][ 3] + '0';
lcinfo[48] = dodeca_data[0][ 4] + '0';
lcinfo[49] = dodeca_data[0][ 5] + '0';
lcinfo[50] = dodeca_data[0][ 6] + '0';
lcinfo[51] = dodeca_data[0][ 7] + '0';
lcinfo[52] = dodeca_data[0][ 8] + '0';
lcinfo[53] = dodeca_data[0][ 9] + '0';
lcinfo[54] = dodeca_data[0][10] + '0';
lcinfo[55] = dodeca_data[0][11] + '0';
processP25lcw (opts, state, lcformat, mfid, lcinfo);
}

104
src/pa_devs.c Normal file
View File

@@ -0,0 +1,104 @@
#include <stdio.h>
#ifdef USE_PORTAUDIO
#include <portaudio.h>
#ifdef WIN32
#include <windows.h>
#endif
void printPortAudioDevices()
{
int i, numDevices, defaultDisplayed;
const PaDeviceInfo *deviceInfo;
PaStreamParameters inputParameters, outputParameters;
PaError err;
Pa_Initialize();
printf( "\nPortAudio version number = %d\nPortAudio version text = '%s'\n",
Pa_GetVersion(), Pa_GetVersionText() );
numDevices = Pa_GetDeviceCount();
if( numDevices < 0 )
{
printf( "ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices );
err = numDevices;
goto error;
}
printf( "Number of devices = %d\n", numDevices );
for( i=0; i<numDevices; i++ )
{
deviceInfo = Pa_GetDeviceInfo( i );
printf( "--------------------------------------- device #%d\n", i );
/* Mark global and API specific default devices */
defaultDisplayed = 0;
if( i == Pa_GetDefaultInputDevice() )
{
printf( "[ Default Input" );
defaultDisplayed = 1;
}
else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultInputDevice )
{
const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
printf( "[ Default %s Input", hostInfo->name );
defaultDisplayed = 1;
}
if( i == Pa_GetDefaultOutputDevice() )
{
printf( (defaultDisplayed ? "," : "[") );
printf( " Default Output" );
defaultDisplayed = 1;
}
else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultOutputDevice )
{
const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
printf( (defaultDisplayed ? "," : "[") );
printf( " Default %s Output", hostInfo->name );
defaultDisplayed = 1;
}
if( defaultDisplayed )
printf( " ]\n" );
/* print device info fields */
#ifdef WIN32
{ /* Use wide char on windows, so we can show UTF-8 encoded device names */
wchar_t wideName[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, deviceInfo->name, -1, wideName, MAX_PATH-1);
wprintf( L"Name = %s\n", wideName );
}
#else
printf( "Name = %s\n", deviceInfo->name );
#endif
printf( "Host API = %s\n", Pa_GetHostApiInfo( deviceInfo->hostApi )->name );
printf( "Max inputs = %d", deviceInfo->maxInputChannels );
printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels );
printf( "Default sample rate = %8.2f\n", deviceInfo->defaultSampleRate );
}
Pa_Terminate();
printf("----------------------------------------------\n");
return;
error:
Pa_Terminate();
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
#else
void printPortAudioDevices()
{
printf("PortAudio not supported in this build of dsd\n");
}
#endif

519
src/provoice.c Normal file
View File

@@ -0,0 +1,519 @@
#include "dsd.h"
#include "provoice_const.h"
void
processProVoice (dsd_opts * opts, dsd_state * state)
{
int i, j, dibit;
char imbe7100_fr1[7][24];
char imbe7100_fr2[7][24];
const int *w, *x;
if (opts->errorbars == 1)
{
printf ("VOICE e:");
}
for (i = 0; i < 64; i++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
}
#ifdef PROVOICE_DUMP
printf (" ");
#endif
// lid
for (i = 0; i < 16; i++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
}
#ifdef PROVOICE_DUMP
printf (" ");
#endif
for (i = 0; i < 64; i++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
}
#ifdef PROVOICE_DUMP
printf (" ");
#endif
// imbe frames 1,2 first half
w = pW;
x = pX;
for (i = 0; i < 11; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
}
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 4; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf (" ");
#endif
// spacer bits
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
printf (" ");
#endif
// imbe frames 1,2 second half
for (j = 0; j < 2; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
for (i = 0; i < 3; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
}
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
for (i = 0; i < 7; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
}
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf (" ");
#endif
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
// spacer bits
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
printf (" ");
#endif
for (i = 0; i < 16; i++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
}
#ifdef PROVOICE_DUMP
printf (" ");
#endif
// imbe frames 3,4 first half
w = pW;
x = pX;
for (i = 0; i < 11; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
}
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 4; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf (" ");
#endif
// spacer bits
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
printf ("_");
#endif
// imbe frames 3,4 second half
for (j = 0; j < 2; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
for (i = 0; i < 3; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
}
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf (" ");
#endif
for (i = 0; i < 7; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
}
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf ("_");
#endif
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
printf (" ");
#endif
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
// spacer bits
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
#endif
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
printf ("%i", dibit);
printf (" ");
#endif
if (opts->errorbars == 1)
{
printf ("\n");
}
}

241
src/x2tdma_data.c Normal file
View File

@@ -0,0 +1,241 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
void
processX2TDMAdata (dsd_opts * opts, dsd_state * state)
{
int i, dibit;
int *dibit_p;
char sync[25];
char syncdata[25];
char cachdata[13];
char cc[4];
int aiei;
char bursttype[5];
#ifdef X2TDMA_DUMP
int k;
char syncbits[49];
char cachbits[25];
#endif
cc[3] = 0;
bursttype[4] = 0;
dibit_p = state->dibit_buf_p - 90;
// CACH
for (i = 0; i < 12; i++)
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
cachdata[i] = dibit;
if (i == 2)
{
state->currentslot = (1 & (dibit >> 1)); // bit 1
if (state->currentslot == 0)
{
state->slot0light[0] = '[';
state->slot0light[6] = ']';
state->slot1light[0] = ' ';
state->slot1light[6] = ' ';
}
else
{
state->slot1light[0] = '[';
state->slot1light[6] = ']';
state->slot0light[0] = ' ';
state->slot0light[6] = ' ';
}
}
}
cachdata[12] = 0;
#ifdef X2TDMA_DUMP
k = 0;
for (i = 0; i < 12; i++)
{
dibit = cachdata[i];
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
cachbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
cachbits[24] = 0;
printf ("%s ", cachbits);
#endif
// current slot
dibit_p += 49;
// slot type
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
cc[0] = (1 & (dibit >> 1)) + 48; // bit 1
cc[1] = (1 & dibit) + 48; // bit 0
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
cc[2] = (1 & (dibit >> 1)) + 48; // bit 1
aiei = (1 & dibit); // bit 0
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
bursttype[0] = (1 & (dibit >> 1)) + 48; // bit 1
bursttype[1] = (1 & dibit) + 48; // bit 0
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
bursttype[2] = (1 & (dibit >> 1)) + 48; // bit 1
bursttype[3] = (1 & dibit) + 48; // bit 0
// parity bit
dibit_p++;
if (strcmp (bursttype, "0000") == 0)
{
sprintf (state->fsubtype, " PI Header ");
}
else if (strcmp (bursttype, "0001") == 0)
{
sprintf (state->fsubtype, " VOICE Header ");
}
else if (strcmp (bursttype, "0010") == 0)
{
sprintf (state->fsubtype, " TLC ");
}
else if (strcmp (bursttype, "0011") == 0)
{
sprintf (state->fsubtype, " CSBK ");
}
else if (strcmp (bursttype, "0100") == 0)
{
sprintf (state->fsubtype, " MBC Header ");
}
else if (strcmp (bursttype, "0101") == 0)
{
sprintf (state->fsubtype, " MBC ");
}
else if (strcmp (bursttype, "0110") == 0)
{
sprintf (state->fsubtype, " DATA Header ");
}
else if (strcmp (bursttype, "0111") == 0)
{
sprintf (state->fsubtype, " RATE 1/2 DATA");
}
else if (strcmp (bursttype, "1000") == 0)
{
sprintf (state->fsubtype, " RATE 3/4 DATA");
}
else if (strcmp (bursttype, "1001") == 0)
{
sprintf (state->fsubtype, " Slot idle ");
}
else if (strcmp (bursttype, "1010") == 0)
{
sprintf (state->fsubtype, " Rate 1 DATA ");
}
else
{
sprintf (state->fsubtype, " ");
}
// signaling data or sync
for (i = 0; i < 24; i++)
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
syncdata[i] = dibit;
sync[i] = (dibit | 1) + 48;
}
sync[24] = 0;
syncdata[24] = 0;
#ifdef X2TDMA_DUMP
k = 0;
for (i = 0; i < 24; i++)
{
dibit = syncdata[i];
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
syncbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
syncbits[48] = 0;
printf ("%s ", syncbits);
#endif
if ((strcmp (sync, X2TDMA_BS_DATA_SYNC) == 0) || (strcmp (sync, X2TDMA_BS_DATA_SYNC) == 0))
{
if (state->currentslot == 0)
{
sprintf (state->slot0light, "[slot0]");
}
else
{
sprintf (state->slot1light, "[slot1]");
}
}
if (opts->errorbars == 1)
{
printf ("%s %s ", state->slot0light, state->slot1light);
}
// current slot second half, cach, next slot 1st half
skipDibit (opts, state, 120);
if (opts->errorbars == 1)
{
if (strcmp (state->fsubtype, " ") == 0)
{
printf (" Unknown burst type: %s\n", bursttype);
}
else
{
printf ("%s\n", state->fsubtype);
}
}
}

642
src/x2tdma_voice.c Normal file
View File

@@ -0,0 +1,642 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
#include "x2tdma_const.h"
void
processX2TDMAvoice (dsd_opts * opts, dsd_state * state)
{
// extracts AMBE frames from X2TDMA frame
int i, j, dibit;
int *dibit_p;
char ambe_fr[4][24];
char ambe_fr2[4][24];
char ambe_fr3[4][24];
const int *w, *x, *y, *z;
char sync[25];
char syncdata[25];
char lcformat[9], mfid[9], lcinfo[57];
char cachdata[13];
char parity;
int eeei, aiei;
char mi[73];
int burstd;
int mutecurrentslot;
int algidhex, kidhex;
int msMode;
#ifdef X2TDMA_DUMP
int k;
char cachbits[25];
char syncbits[49];
#endif
lcformat[8] = 0;
mfid[8] = 0;
lcinfo[56] = 0;
sprintf (mi, "________________________________________________________________________");
eeei = 0;
aiei = 0;
burstd = 0;
mutecurrentslot = 0;
msMode = 0;
dibit_p = state->dibit_buf_p - 144;
for (j = 0; j < 6; j++)
{
// 2nd half of previous slot
for (i = 0; i < 54; i++)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
}
}
// CACH
for (i = 0; i < 12; i++)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
}
cachdata[i] = dibit;
if (i == 2)
{
state->currentslot = (1 & (dibit >> 1)); // bit 1
if (state->currentslot == 0)
{
state->slot0light[0] = '[';
state->slot0light[6] = ']';
state->slot1light[0] = ' ';
state->slot1light[6] = ' ';
}
else
{
state->slot1light[0] = '[';
state->slot1light[6] = ']';
state->slot0light[0] = ' ';
state->slot0light[6] = ' ';
}
}
}
cachdata[12] = 0;
#ifdef X2TDMA_DUMP
k = 0;
for (i = 0; i < 12; i++)
{
dibit = cachdata[i];
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
cachbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
cachbits[24] = 0;
printf ("%s ", cachbits);
#endif
// current slot frame 1
w = aW;
x = aX;
y = aY;
z = aZ;
for (i = 0; i < 36; i++)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
}
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
// current slot frame 2 first half
w = aW;
x = aX;
y = aY;
z = aZ;
for (i = 0; i < 18; i++)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
}
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
// signaling data or sync
for (i = 0; i < 24; i++)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_x2tdma == 1)
{
dibit = (dibit ^ 2);
}
}
syncdata[i] = dibit;
sync[i] = (dibit | 1) + 48;
}
sync[24] = 0;
syncdata[24] = 0;
if ((strcmp (sync, X2TDMA_BS_DATA_SYNC) == 0) || (strcmp (sync, X2TDMA_MS_DATA_SYNC) == 0))
{
mutecurrentslot = 1;
if (state->currentslot == 0)
{
sprintf (state->slot0light, "[slot0]");
}
else
{
sprintf (state->slot1light, "[slot1]");
}
}
else if ((strcmp (sync, X2TDMA_BS_VOICE_SYNC) == 0) || (strcmp (sync, X2TDMA_MS_VOICE_SYNC) == 0))
{
mutecurrentslot = 0;
if (state->currentslot == 0)
{
sprintf (state->slot0light, "[SLOT0]");
}
else
{
sprintf (state->slot1light, "[SLOT1]");
}
}
if ((strcmp (sync, X2TDMA_MS_VOICE_SYNC) == 0) || (strcmp (sync, X2TDMA_MS_DATA_SYNC) == 0))
{
msMode = 1;
}
if ((j == 0) && (opts->errorbars == 1))
{
printf ("%s %s VOICE e:", state->slot0light, state->slot1light);
}
#ifdef X2TDMA_DUMP
k = 0;
for (i = 0; i < 24; i++)
{
dibit = syncdata[i];
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
syncbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
syncbits[48] = 0;
printf ("%s ", syncbits);
#endif
if (j == 1)
{
eeei = (1 & syncdata[1]); // bit 0
aiei = (1 & (syncdata[2] >> 1)); // bit 1
if ((eeei == 0) && (aiei == 0))
{
lcformat[0] = (1 & (syncdata[4] >> 1)) + 48; // bit 1
mfid[3] = (1 & syncdata[4]) + 48; // bit 0
lcinfo[6] = (1 & (syncdata[5] >> 1)) + 48; // bit 1
lcinfo[16] = (1 & syncdata[5]) + 48; // bit 0
lcinfo[26] = (1 & (syncdata[6] >> 1)) + 48; // bit 1
lcinfo[36] = (1 & syncdata[6]) + 48; // bit 0
lcinfo[46] = (1 & (syncdata[7] >> 1)) + 48; // bit 1
parity = (1 & syncdata[7]) + 48; // bit 0
lcformat[1] = (1 & (syncdata[8] >> 1)) + 48; // bit 1
mfid[4] = (1 & syncdata[8]) + 48; // bit 0
lcinfo[7] = (1 & (syncdata[9] >> 1)) + 48; // bit 1
lcinfo[17] = (1 & syncdata[9]) + 48; // bit 0
lcinfo[27] = (1 & (syncdata[10] >> 1)) + 48; // bit 1
lcinfo[37] = (1 & syncdata[10]) + 48; // bit 0
lcinfo[47] = (1 & (syncdata[11] >> 1)) + 48; // bit 1
parity = (1 & syncdata[11]) + 48; // bit 0
lcformat[2] = (1 & (syncdata[12] >> 1)) + 48; // bit 1
mfid[5] = (1 & syncdata[12]) + 48; // bit 0
lcinfo[8] = (1 & (syncdata[13] >> 1)) + 48; // bit 1
lcinfo[18] = (1 & syncdata[13]) + 48; // bit 0
lcinfo[28] = (1 & (syncdata[14] >> 1)) + 48; // bit 1
lcinfo[38] = (1 & syncdata[14]) + 48; // bit 0
lcinfo[48] = (1 & (syncdata[15] >> 1)) + 48; // bit 1
parity = (1 & syncdata[15]) + 48; // bit 0
lcformat[3] = (1 & (syncdata[16] >> 1)) + 48; // bit 1
mfid[6] = (1 & syncdata[16]) + 48; // bit 0
lcinfo[9] = (1 & (syncdata[17] >> 1)) + 48; // bit 1
lcinfo[19] = (1 & syncdata[17]) + 48; // bit 0
lcinfo[29] = (1 & (syncdata[18] >> 1)) + 48; // bit 1
lcinfo[39] = (1 & syncdata[18]) + 48; // bit 0
lcinfo[49] = (1 & (syncdata[19] >> 1)) + 48; // bit 1
parity = (1 & syncdata[19]) + 48; // bit 0
}
else
{
mi[0] = (1 & (syncdata[4] >> 1)) + 48; // bit 1
mi[11] = (1 & syncdata[4]) + 48; // bit 0
mi[22] = (1 & (syncdata[5] >> 1)) + 48; // bit 1
mi[32] = (1 & syncdata[5]) + 48; // bit 0
mi[42] = (1 & (syncdata[6] >> 1)) + 48; // bit 1
mi[52] = (1 & syncdata[6]) + 48; // bit 0
mi[62] = (1 & (syncdata[7] >> 1)) + 48; // bit 1
parity = (1 & syncdata[7]) + 48; // bit 0
mi[1] = (1 & (syncdata[8] >> 1)) + 48; // bit 1
mi[12] = (1 & syncdata[8]) + 48; // bit 0
mi[23] = (1 & (syncdata[9] >> 1)) + 48; // bit 1
mi[33] = (1 & syncdata[9]) + 48; // bit 0
mi[43] = (1 & (syncdata[10] >> 1)) + 48; // bit 1
mi[53] = (1 & syncdata[10]) + 48; // bit 0
mi[63] = (1 & (syncdata[11] >> 1)) + 48; // bit 1
parity = (1 & syncdata[11]) + 48; // bit 0
mi[2] = (1 & (syncdata[12] >> 1)) + 48; // bit 1
mi[13] = (1 & syncdata[12]) + 48; // bit 0
mi[24] = (1 & (syncdata[13] >> 1)) + 48; // bit 1
mi[34] = (1 & syncdata[13]) + 48; // bit 0
mi[44] = (1 & (syncdata[14] >> 1)) + 48; // bit 1
mi[54] = (1 & syncdata[14]) + 48; // bit 0
mi[64] = (1 & (syncdata[15] >> 1)) + 48; // bit 1
parity = (1 & syncdata[15]) + 48; // bit 0
mi[3] = (1 & (syncdata[16] >> 1)) + 48; // bit 1
mi[14] = (1 & syncdata[16]) + 48; // bit 0
mi[25] = (1 & (syncdata[17] >> 1)) + 48; // bit 1
mi[35] = (1 & syncdata[17]) + 48; // bit 0
mi[45] = (1 & (syncdata[18] >> 1)) + 48; // bit 1
mi[55] = (1 & syncdata[18]) + 48; // bit 0
mi[65] = (1 & (syncdata[19] >> 1)) + 48; // bit 1
parity = (1 & syncdata[19]) + 48; // bit 0
}
}
else if (j == 2)
{
if ((eeei == 0) && (aiei == 0))
{
lcformat[4] = (1 & (syncdata[4] >> 1)) + 48; // bit 1
mfid[7] = (1 & syncdata[4]) + 48; // bit 0
lcinfo[10] = (1 & (syncdata[5] >> 1)) + 48; // bit 1
lcinfo[20] = (1 & syncdata[5]) + 48; // bit 0
lcinfo[30] = (1 & (syncdata[6] >> 1)) + 48; // bit 1
lcinfo[40] = (1 & syncdata[6]) + 48; // bit 0
lcinfo[50] = (1 & (syncdata[7] >> 1)) + 48; // bit 1
parity = (1 & syncdata[7]) + 48; // bit 0
lcformat[5] = (1 & (syncdata[8] >> 1)) + 48; // bit 1
lcinfo[0] = (1 & syncdata[8]) + 48; // bit 0
lcinfo[11] = (1 & (syncdata[9] >> 1)) + 48; // bit 1
lcinfo[21] = (1 & syncdata[9]) + 48; // bit 0
lcinfo[31] = (1 & (syncdata[10] >> 1)) + 48; // bit 1
lcinfo[41] = (1 & syncdata[10]) + 48; // bit 0
lcinfo[51] = (1 & (syncdata[11] >> 1)) + 48; // bit 1
parity = (1 & syncdata[11]) + 48; // bit 0
lcformat[6] = (1 & (syncdata[12] >> 1)) + 48; // bit 1
lcinfo[1] = (1 & syncdata[12]) + 48; // bit 0
lcinfo[12] = (1 & (syncdata[13] >> 1)) + 48; // bit 1
lcinfo[22] = (1 & syncdata[13]) + 48; // bit 0
lcinfo[32] = (1 & (syncdata[14] >> 1)) + 48; // bit 1
lcinfo[42] = (1 & syncdata[14]) + 48; // bit 0
lcinfo[52] = (1 & (syncdata[15] >> 1)) + 48; // bit 1
parity = (1 & syncdata[15]) + 48; // bit 0
lcformat[7] = (1 & (syncdata[16] >> 1)) + 48; // bit 1
lcinfo[2] = (1 & syncdata[16]) + 48; // bit 0
lcinfo[13] = (1 & (syncdata[17] >> 1)) + 48; // bit 1
lcinfo[23] = (1 & syncdata[17]) + 48; // bit 0
lcinfo[33] = (1 & (syncdata[18] >> 1)) + 48; // bit 1
lcinfo[43] = (1 & syncdata[18]) + 48; // bit 0
lcinfo[53] = (1 & (syncdata[19] >> 1)) + 48; // bit 1
parity = (1 & syncdata[19]) + 48; // bit 0
}
else
{
mi[4] = (1 & (syncdata[4] >> 1)) + 48; // bit 1
mi[15] = (1 & syncdata[4]) + 48; // bit 0
mi[26] = (1 & (syncdata[5] >> 1)) + 48; // bit 1
mi[36] = (1 & syncdata[5]) + 48; // bit 0
mi[46] = (1 & (syncdata[6] >> 1)) + 48; // bit 1
mi[56] = (1 & syncdata[6]) + 48; // bit 0
mi[66] = (1 & (syncdata[7] >> 1)) + 48; // bit 1
parity = (1 & syncdata[7]) + 48; // bit 0
mi[5] = (1 & (syncdata[8] >> 1)) + 48; // bit 1
mi[16] = (1 & syncdata[8]) + 48; // bit 0
mi[27] = (1 & (syncdata[9] >> 1)) + 48; // bit 1
mi[37] = (1 & syncdata[9]) + 48; // bit 0
mi[47] = (1 & (syncdata[10] >> 1)) + 48; // bit 1
mi[57] = (1 & syncdata[10]) + 48; // bit 0
mi[67] = (1 & (syncdata[11] >> 1)) + 48; // bit 1
parity = (1 & syncdata[11]) + 48; // bit 0
mi[6] = (1 & (syncdata[12] >> 1)) + 48; // bit 1
mi[17] = (1 & syncdata[12]) + 48; // bit 0
mi[28] = (1 & (syncdata[13] >> 1)) + 48; // bit 1
mi[38] = (1 & syncdata[13]) + 48; // bit 0
mi[48] = (1 & (syncdata[14] >> 1)) + 48; // bit 1
mi[58] = (1 & syncdata[14]) + 48; // bit 0
mi[68] = (1 & (syncdata[15] >> 1)) + 48; // bit 1
parity = (1 & syncdata[15]) + 48; // bit 0
mi[7] = (1 & (syncdata[16] >> 1)) + 48; // bit 1
mi[18] = (1 & syncdata[16]) + 48; // bit 0
mi[29] = (1 & (syncdata[17] >> 1)) + 48; // bit 1
mi[39] = (1 & syncdata[17]) + 48; // bit 0
mi[49] = (1 & (syncdata[18] >> 1)) + 48; // bit 1
mi[59] = (1 & syncdata[18]) + 48; // bit 0
mi[69] = (1 & (syncdata[19] >> 1)) + 48; // bit 1
parity = (1 & syncdata[19]) + 48; // bit 0
}
}
else if (j == 3)
{
burstd = (1 & syncdata[1]); // bit 0
state->algid[0] = (1 & (syncdata[4] >> 1)) + 48; // bit 1
state->algid[1] = (1 & syncdata[4]) + 48; // bit 0
state->algid[2] = (1 & (syncdata[5] >> 1)) + 48; // bit 1
state->algid[3] = (1 & syncdata[5]) + 48; // bit 0
if (burstd == 0)
{
state->algid[4] = (1 & (syncdata[8] >> 1)) + 48; // bit 1
state->algid[5] = (1 & syncdata[8]) + 48; // bit 0
state->algid[6] = (1 & (syncdata[9] >> 1)) + 48; // bit 1
state->algid[7] = (1 & syncdata[9]) + 48; // bit 0
state->keyid[0] = (1 & (syncdata[10] >> 1)) + 48; // bit 1
state->keyid[1] = (1 & syncdata[10]) + 48; // bit 0
state->keyid[2] = (1 & (syncdata[11] >> 1)) + 48; // bit 1
state->keyid[3] = (1 & syncdata[11]) + 48; // bit 0
state->keyid[4] = (1 & (syncdata[12] >> 1)) + 48; // bit 1
state->keyid[5] = (1 & syncdata[12]) + 48; // bit 0
state->keyid[6] = (1 & (syncdata[13] >> 1)) + 48; // bit 1
state->keyid[7] = (1 & syncdata[13]) + 48; // bit 0
state->keyid[8] = (1 & (syncdata[14] >> 1)) + 48; // bit 1
state->keyid[9] = (1 & syncdata[14]) + 48; // bit 0
state->keyid[10] = (1 & (syncdata[15] >> 1)) + 48; // bit 1
state->keyid[11] = (1 & syncdata[15]) + 48; // bit 0
state->keyid[12] = (1 & (syncdata[16] >> 1)) + 48; // bit 1
state->keyid[13] = (1 & syncdata[16]) + 48; // bit 0
state->keyid[14] = (1 & (syncdata[17] >> 1)) + 48; // bit 1
state->keyid[15] = (1 & syncdata[17]) + 48; // bit 0
}
else
{
sprintf (state->algid, "________");
sprintf (state->keyid, "________________");
}
}
else if (j == 4)
{
if ((eeei == 0) && (aiei == 0))
{
mfid[0] = (1 & (syncdata[4] >> 1)) + 48; // bit 1
lcinfo[3] = (1 & syncdata[4]) + 48; // bit 0
lcinfo[14] = (1 & (syncdata[5] >> 1)) + 48; // bit 1
lcinfo[24] = (1 & syncdata[5]) + 48; // bit 0
lcinfo[34] = (1 & (syncdata[6] >> 1)) + 48; // bit 1
lcinfo[44] = (1 & syncdata[6]) + 48; // bit 0
lcinfo[54] = (1 & (syncdata[7] >> 1)) + 48; // bit 1
parity = (1 & syncdata[7]) + 48; // bit 0
mfid[1] = (1 & (syncdata[8] >> 1)) + 48; // bit 1
lcinfo[4] = (1 & syncdata[8]) + 48; // bit 0
lcinfo[15] = (1 & (syncdata[9] >> 1)) + 48; // bit 1
lcinfo[25] = (1 & syncdata[9]) + 48; // bit 0
lcinfo[35] = (1 & (syncdata[10] >> 1)) + 48; // bit 1
lcinfo[45] = (1 & syncdata[10]) + 48; // bit 0
lcinfo[55] = (1 & (syncdata[11] >> 1)) + 48; // bit 1
parity = (1 & syncdata[11]) + 48; // bit 0
mfid[2] = (1 & (syncdata[12] >> 1)) + 48; // bit 1
lcinfo[5] = (1 & syncdata[12]) + 48; // bit 0
}
else
{
mi[8] = (1 & (syncdata[4] >> 1)) + 48; // bit 1
mi[19] = (1 & syncdata[4]) + 48; // bit 0
mi[30] = (1 & (syncdata[5] >> 1)) + 48; // bit 1
mi[40] = (1 & syncdata[5]) + 48; // bit 0
mi[50] = (1 & (syncdata[6] >> 1)) + 48; // bit 1
mi[60] = (1 & syncdata[6]) + 48; // bit 0
mi[70] = (1 & (syncdata[7] >> 1)) + 48; // bit 1
parity = (1 & syncdata[7]) + 48; // bit 0
mi[9] = (1 & (syncdata[8] >> 1)) + 48; // bit 1
mi[20] = (1 & syncdata[8]) + 48; // bit 0
mi[31] = (1 & (syncdata[9] >> 1)) + 48; // bit 1
mi[41] = (1 & syncdata[9]) + 48; // bit 0
mi[51] = (1 & (syncdata[10] >> 1)) + 48; // bit 1
mi[61] = (1 & syncdata[10]) + 48; // bit 0
mi[71] = (1 & (syncdata[11] >> 1)) + 48; // bit 1
parity = (1 & syncdata[11]) + 48; // bit 0
mi[10] = (1 & (syncdata[12] >> 1)) + 48; // bit 1
mi[21] = (1 & syncdata[12]) + 48; // bit 0
}
}
// current slot frame 2 second half
for (i = 0; i < 18; i++)
{
dibit = getDibit (opts, state);
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
if (mutecurrentslot == 0)
{
if (state->firstframe == 1)
{ // we don't know if anything received before the first sync after no carrier is valid
state->firstframe = 0;
}
else
{
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
}
}
// current slot frame 3
w = aW;
x = aX;
y = aY;
z = aZ;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
if (mutecurrentslot == 0)
{
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
}
// CACH
for (i = 0; i < 12; i++)
{
dibit = getDibit (opts, state);
cachdata[i] = dibit;
}
cachdata[12] = 0;
#ifdef X2TDMA_DUMP
k = 0;
for (i = 0; i < 12; i++)
{
dibit = cachdata[i];
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
cachbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
cachbits[24] = 0;
printf ("%s ", cachbits);
#endif
// next slot
skipDibit (opts, state, 54);
// signaling data or sync
for (i = 0; i < 24; i++)
{
dibit = getDibit (opts, state);
syncdata[i] = dibit;
sync[i] = (dibit | 1) + 48;
}
sync[24] = 0;
syncdata[24] = 0;
if ((strcmp (sync, X2TDMA_BS_DATA_SYNC) == 0) || (msMode == 1))
{
if (state->currentslot == 0)
{
sprintf (state->slot1light, " slot1 ");
}
else
{
sprintf (state->slot0light, " slot0 ");
}
}
else if (strcmp (sync, X2TDMA_BS_VOICE_SYNC) == 0)
{
if (state->currentslot == 0)
{
sprintf (state->slot1light, " SLOT1 ");
}
else
{
sprintf (state->slot0light, " SLOT0 ");
}
}
#ifdef X2TDMA_DUMP
k = 0;
for (i = 0; i < 24; i++)
{
dibit = syncdata[i];
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
syncbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
syncbits[48] = 0;
printf ("%s ", syncbits);
#endif
if (j == 5)
{
// 2nd half next slot
skipDibit (opts, state, 54);
// CACH
skipDibit (opts, state, 12);
// first half current slot
skipDibit (opts, state, 54);
}
}
if (opts->errorbars == 1)
{
printf ("\n");
}
if (mutecurrentslot == 0)
{
if ((eeei == 0) && (aiei == 0))
{
processP25lcw (opts, state, lcformat, mfid, lcinfo);
}
if (opts->p25enc == 1)
{
algidhex = strtol (state->algid, NULL, 2);
kidhex = strtol (state->keyid, NULL, 2);
printf ("mi: %s algid: $%x kid: $%x\n", mi, algidhex, kidhex);
}
}
}