mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-14 17:57:28 -05:00
Some much needed organization
This commit is contained in:
83
src/Hamming.cpp
Normal file
83
src/Hamming.cpp
Normal 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
240
src/dmr_data.c
Normal 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
382
src/dmr_voice.c
Normal 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
620
src/dsd_audio.c
Normal 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) ? ¶meters : NULL,
|
||||
(input == 0) ? ¶meters : 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
437
src/dsd_dibit.c
Normal 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
370
src/dsd_file.c
Normal 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
116
src/dsd_filters.c
Normal 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
571
src/dsd_frame.c
Normal 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
830
src/dsd_frame_sync.c
Normal 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
872
src/dsd_main.c
Normal 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
152
src/dsd_mbe.c
Normal 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
90
src/dsd_serial.c
Normal 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
308
src/dsd_symbol.c
Normal 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
68
src/dsd_upsample.c
Normal 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
163
src/dstar.c
Normal 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
76
src/dstar_header.c
Normal 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
2
src/git_ver.c.in
Normal file
@@ -0,0 +1,2 @@
|
||||
#define _GIT_TAG "@GIT_TAG@"
|
||||
const char GIT_TAG[] = _GIT_TAG;
|
||||
124
src/nxdn96.c
Normal file
124
src/nxdn96.c
Normal 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
36
src/nxdn_data.c
Normal 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
59
src/nxdn_voice.c
Normal 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
160
src/p25_lcw.c
Normal 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
142
src/p25p1_check_hdu.cpp
Normal 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
125
src/p25p1_check_ldu.cpp
Normal 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
93
src/p25p1_check_nid.cpp
Normal 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
511
src/p25p1_hdu.c
Normal 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
386
src/p25p1_heuristics.c
Normal 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
269
src/p25p1_ldu.c
Normal 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
334
src/p25p1_ldu1.c
Normal 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
370
src/p25p1_ldu2.c
Normal 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
34
src/p25p1_tdu.c
Normal 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
391
src/p25p1_tdulc.c
Normal 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
104
src/pa_devs.c
Normal 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
519
src/provoice.c
Normal 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
241
src/x2tdma_data.c
Normal 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
642
src/x2tdma_voice.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user