Initial working DSTAR voice support

This commit is contained in:
balr0g 2013-12-14 20:02:43 -05:00
parent 27960ae4be
commit 040ea148b0
17 changed files with 814 additions and 455 deletions

View File

@ -1,3 +1,18 @@
dstar_header.c/h, descramble.h, and fcs.h are under the following license:
dstar_header.c/h and fcs.h: Copyright (C) 2010 by Kristoff Bonne, ON1ARF
descramble.h: Copyright (C) 2011 by Jonathan Naylor, G4KLX
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.
All other code is under the following license:
Copyright (C) 2010 DSD Author
GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)

115
Makefile
View File

@ -1,115 +0,0 @@
# 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.
CC = gcc
CFLAGS = -O2 -Wall -g
INCLUDES = -I. -I/usr/local/include -I/usr/include -I../mbelib-master
LIBS = -L/usr/local/lib -L../mbelib-master -lm -lmbe
INSTALL=install
AR=ar
RANLIB=ranlib
DEST_BASE=/usr/local
DEST_INC=${DEST_BASE}/include
DEST_LIB=${DEST_BASE}/lib
DEST_BIN=${DEST_BASE}/bin
OBJS = dsd_main.o dsd_symbol.o dsd_dibit.o dsd_frame_sync.o dsd_file.o dsd_audio.o dsd_serial.o dsd_frame.o dsd_mbe.o dsd_upsample.o p25p1_hdu.o p25p1_ldu1.o p25p1_ldu2.o p25p1_tdulc.o p25_lcw.o x2tdma_voice.o x2tdma_data.o dstar.o nxdn_voice.o nxdn_data.o dmr_voice.o dmr_data.o provoice.o
all: dsd
build: all
dsd_main.o: dsd_main.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_main.c -o dsd_main.o
dsd_symbol.o: dsd_symbol.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_symbol.c -o dsd_symbol.o
dsd_dibit.o: dsd_dibit.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_dibit.c -o dsd_dibit.o
dsd_frame_sync.o: dsd_frame_sync.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_frame_sync.c -o dsd_frame_sync.o
dsd_file.o: dsd_file.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_file.c -o dsd_file.o
dsd_audio.o: dsd_audio.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_audio.c -o dsd_audio.o
dsd_serial.o: dsd_serial.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_serial.c -o dsd_serial.o
dsd_frame.o: dsd_frame.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_frame.c -o dsd_frame.o
dsd_mbe.o: dsd_mbe.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_mbe.c -o dsd_mbe.o
dsd_upsample.o: dsd_upsample.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_upsample.c -o dsd_upsample.o
p25p1_hdu.o: p25p1_hdu.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c p25p1_hdu.c -o p25p1_hdu.o
p25p1_ldu1.o: p25p1_ldu1.c p25p1_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c p25p1_ldu1.c -o p25p1_ldu1.o
p25p1_ldu2.o: p25p1_ldu2.c p25p1_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c p25p1_ldu2.c -o p25p1_ldu2.o
p25p1_tdulc.o: p25p1_tdulc.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c p25p1_tdulc.c -o p25p1_tdulc.o
p25_lcw.o: p25_lcw.c dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c p25_lcw.c -o p25_lcw.o
x2tdma_voice.o: x2tdma_voice.c x2tdma_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c x2tdma_voice.c -o x2tdma_voice.o
x2tdma_data.o: x2tdma_data.c x2tdma_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c x2tdma_data.c -o x2tdma_data.o
dstar.o: dstar.c dstar_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dstar.c -o dstar.o
nxdn48_voice.o: nxdn48_voice.c nxdn_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c nxdn48_voice.c -o nxdn48_voice.o
nxdn_voice.o: nxdn_voice.c nxdn_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c nxdn_voice.c -o nxdn_voice.o
nxdn_data.o: nxdn_data.c nxdn_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c nxdn_data.c -o nxdn_data.o
dmr_voice.o: dmr_voice.c dmr_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dmr_voice.c -o dmr_voice.o
dmr_data.o: dmr_data.c dmr_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c dmr_data.c -o dmr_data.o
provoice.o: provoice.c provoice_const.h dsd.h config.h
$(CC) $(CFLAGS) $(INCLUDES) -c provoice.c -o provoice.o
dsd: $(OBJS) dsd.h config.h
$(CC) $(CFLAGS) -o dsd $(OBJS) $(LIBS)
clean:
rm -f *.o
rm -f dsd
install: dsd
$(INSTALL) dsd $(DEST_BIN)
chgrp uucp $(DEST_BIN)/dsd
chmod g+s $(DEST_BIN)/dsd

9
README
View File

@ -60,12 +60,9 @@ PERFORMANCE OF THIS SOFTWARE.
D-STAR Amateur radio digital voice standard
Development support only. DSD recognized frames and can
extract the voice bits but speech is not yet decoded.
D-STAR likely uses a version of AMBE not yet supported by
mbelib. The voice bit interleave pattern also needs to be
determined.
Note: not enabled by default, use -fd to enable.
This is an earlier version of the AMBE codec than the one
used by most of the protocols. Support for this was added by
various developers.
Unsupported formats in version 1.4 considered for future development:

293
descramble.h Normal file
View File

@ -0,0 +1,293 @@
/* descramble.h */
// Functions for processing the radio-header:
// descramble
// deinterleave
// FECdecoder
// (C) 2011 Jonathan Naylor G4KLX
/*
* 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.
*/
// This code was originally written by JOnathan Naylor, G4KLX, as part
// of the "pcrepeatercontroller" project
// More info:
// http://groups.yahoo.com/group/pcrepeatercontroller
// Changes:
// Convert C++ to C
// Version 20111106: initial release
#include <stdio.h>
#include <string.h>
// function traceBack
int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_pathMemory2, int * m_pathMemory3) {
enum FEC_STATE { S0, S1, S2, S3 } state;
int loop;
int length=0;
state=S0;
for (loop=329; loop >= 0; loop--, length++) {
switch (state) {
case S0: // if state S0
if (m_pathMemory0[loop]) {
state = S2; // lower path
} else {
state = S0; // upper path
}; // end else - if
out[loop]=0;
break;
case S1: // if state S1
if (m_pathMemory1[loop]) {
state = S2; // lower path
} else {
state = S0; // upper path
}; // end else - if
out[loop]=1;
break;
case S2: // if state S2
if (m_pathMemory2[loop]) {
state = S3; // lower path
} else {
state = S1; // upper path
}; // end else - if
out[loop]=0;
break;
case S3: // if state S3
if (m_pathMemory3[loop]) {
state = S3; // lower path
} else {
state = S1; // upper path
}; // end else - if
out[loop]=1;
break;
}; // end switch
}; // end for
return(length);
}; // end function
// function viterbiDecode
void viterbiDecode (int n, int *data, int *m_pathMemory0, int *m_pathMemory1, int *m_pathMemory2, int *m_pathMemory3, int *m_pathMetric) {
int tempMetric[4];
int metric[8];
int loop;
int m1;
int m2;
metric[0]=(data[1]^0)+(data[0]^0);
metric[1]=(data[1]^1)+(data[0]^1);
metric[2]=(data[1]^1)+(data[0]^0);
metric[3]=(data[1]^0)+(data[0]^1);
metric[4]=(data[1]^1)+(data[0]^1);
metric[5]=(data[1]^0)+(data[0]^0);
metric[6]=(data[1]^0)+(data[0]^1);
metric[7]=(data[1]^1)+(data[0]^0);
// Pres. state = S0, Prev. state = S0 & S2
m1=metric[0]+m_pathMetric[0];
m2=metric[4]+m_pathMetric[2];
if (m1<m2) {
m_pathMemory0[n]=0;
tempMetric[0]=m1;
} else {
m_pathMemory0[n]=1;
tempMetric[0]=m2;
}; // end else - if
// Pres. state = S1, Prev. state = S0 & S2
m1=metric[1]+m_pathMetric[0];
m2=metric[5]+m_pathMetric[2];
if (m1<m2) {
m_pathMemory1[n]=0;
tempMetric[1]=m1;
} else {
m_pathMemory1[n]=1;
tempMetric[1]=m2;
}; // end else - if
// Pres. state = S2, Prev. state = S2 & S3
m1=metric[2]+m_pathMetric[1];
m2=metric[6]+m_pathMetric[3];
if (m1<m2) {
m_pathMemory2[n]=0;
tempMetric[2]=m1;
} else {
m_pathMemory2[n]=1;
tempMetric[2]=m2;
}
// Pres. state = S3, Prev. state = S1 & S3
m1=metric[3]+m_pathMetric[1];
m2=metric[7]+m_pathMetric[3];
if (m1 < m2) {
m_pathMemory3[n]=0;
tempMetric[3]=m1;
} else {
m_pathMemory3[n]=1;
tempMetric[3]=m2;
}; // end else - if
for (loop=0;loop<4;loop++) {
m_pathMetric[loop]=tempMetric[loop];
}; // end for
}; // end function ViterbiDecode
// function FECdecoder
// returns outlen
int FECdecoder (int * in, int * out) {
int outLen;
int m_pathMemory0[330]; memset(m_pathMemory0,0,330*sizeof(int));
int m_pathMemory1[330]; memset(m_pathMemory1,0,330*sizeof(int));
int m_pathMemory2[330]; memset(m_pathMemory2,0,330*sizeof(int));
int m_pathMemory3[330]; memset(m_pathMemory3,0,330*sizeof(int));
int m_pathMetric[4];
int loop,loop2;
int n=0;
for (loop=0;loop<4;loop++) {
m_pathMetric[loop]=0;
}; // end for
for (loop2=0;loop2<660;loop2+=2, n++) {
int data[2];
if (in[loop2]) {
data[1]=1;
} else {
data[1]=0;
}; // end else - if
if (in[loop2+1]) {
data[0]=1;
} else {
data[0]=0;
}; // end else - if
viterbiDecode(n, data, m_pathMemory0, m_pathMemory1, m_pathMemory2, m_pathMemory3, m_pathMetric);
}; // end for
outLen=traceBack(out, m_pathMemory0, m_pathMemory1, m_pathMemory2, m_pathMemory3);
// Swap endian-ness
// code removed (done converting bits into octets), done in main program
//for (loop=0;loop<330;loop+=8) {
// int temp;
// temp=out[loop];out[loop]=out[loop+7];out[loop+7]=temp;
// temp=out[loop+1];out[loop+1]=out[loop+6];out[loop+6]=temp;
// temp=out[loop+2];out[loop+2]=out[loop+5];out[loop+5]=temp;
// temp=out[loop+3];out[loop+3]=out[loop+4];out[loop+4]=temp;
//}
return(outLen);
}; // end function FECdecoder
// function deinterleave
void deinterleave (int * in, int * out) {
int k=0;
int loop=0;
// function starts here
// init vars
k=0;
for (loop=0;loop<660;loop++) {
out[k]=in[loop];
k += 24;
if (k >= 672) {
k -= 671;
} else if (k >= 660) {
k -= 647;
}; // end elsif - if
}; // end for
}; // end function deinterleave
/// function scramble
void scramble (int * in,int * out) {
static const int SCRAMBLER_TABLE_BITS[] = {
0,0,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,
0,0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,
1,1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,
1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,
0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,
1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,
1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,
0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,
1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,
0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,
1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,
0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,
0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,
1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,
1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,
1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,
0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1,
0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,1,
1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,
1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,
1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1,0,
1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0};
const int SCRAMBLER_TABLE_BITS_LENGTH=720;
int loop=0;
int m_count=0;
for (loop=0; loop < 660; loop++) {
out[loop] = in[loop] ^ SCRAMBLER_TABLE_BITS[m_count++];
if (m_count >= SCRAMBLER_TABLE_BITS_LENGTH) {
m_count = 0U;
}; // end if
}; // end for
}; // end function scramble

4
dsd.h
View File

@ -99,6 +99,7 @@ typedef struct
int msize;
int playfiles;
int delay;
int use_cosine_filter;
} dsd_opts;
typedef struct
@ -179,6 +180,8 @@ typedef struct
#define X2TDMA_MS_DATA_SYNC "313113333111111133333313"
#define X2TDMA_MS_VOICE_SYNC "131331111333333311111131"
#define DSTAR_HD "131313131333133113131111"
#define INV_DSTAR_HD "313131313111311331313333"
#define DSTAR_SYNC "313131313133131113313111"
#define INV_DSTAR_SYNC "131313131311313331131333"
@ -252,3 +255,4 @@ void processTDULC (dsd_opts * opts, dsd_state * state);
void processProVoice (dsd_opts * opts, dsd_state * state);
void processX2TDMAdata (dsd_opts * opts, dsd_state * state);
void processX2TDMAvoice (dsd_opts * opts, dsd_state * state);
void processDSTAR_HD (dsd_opts * opts, dsd_state * state);

View File

@ -90,14 +90,16 @@ processAudio (dsd_opts * opts, dsd_state * state)
gaindelta = (float) 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);
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 datat to output buffer and upsample if necessary
state->audio_out_temp_buf_p = state->audio_out_temp_buf;

View File

@ -183,7 +183,7 @@ getDibit (dsd_opts * opts, dsd_state * state)
}
// determine dibit state
if ((state->synctype == 6) || (state->synctype == 14))
if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18))
{
if (symbol > state->center)
{
@ -198,7 +198,7 @@ getDibit (dsd_opts * opts, dsd_state * state)
return (1);
}
}
else if ((state->synctype == 7) || (state->synctype == 15))
else if ((state->synctype == 7) || (state->synctype == 15)|| (state->synctype == 19))
{
if (symbol > state->center)
{

View File

@ -16,6 +16,9 @@
*/
#include "dsd.h"
#if !defined(NULL)
#define NULL 0
#endif
void
printFrameInfo (dsd_opts * opts, dsd_state * state)
@ -131,6 +134,29 @@ processFrame (dsd_opts * opts, dsd_state * state)
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;

View File

@ -61,6 +61,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
* 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;
@ -670,6 +672,35 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
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))

View File

@ -128,6 +128,7 @@ initOpts (dsd_opts * opts)
opts->msize = 15;
opts->playfiles = 0;
opts->delay = 0;
opts->use_cosine_filter = 1;
}
void
@ -244,7 +245,7 @@ usage ()
printf (" -i <device> Audio input device (default is /dev/audio)\n");
printf (" -o <device> Audio output device (default is /dev/audio)\n");
printf (" -d <dir> Create mbe data files, use this directory\n");
printf (" -g <num> Audio output gain (default = 0 = auto)\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 ("\n");
@ -256,12 +257,13 @@ usage ()
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* (no audio)\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 cosine filter (improves D-STAR performance)*\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");
@ -344,7 +346,7 @@ main (int argc, char **argv)
exitflag = 0;
signal (SIGINT, sigfun);
while ((c = getopt (argc, argv, "hep:qstv:z:i:o:d:g:nw:B:C:R:f:m:u:x:A:S:M:r")) != -1)
while ((c = getopt (argc, argv, "hep:qstv:z:i:o:d:g:nw:B:C:R:f:m:u:x:A:S:M:rl")) != -1)
{
opterr = 0;
switch (c)
@ -418,7 +420,11 @@ main (int argc, char **argv)
break;
case 'g':
sscanf (optarg, "%f", &opts.audio_gain);
if (opts.audio_gain <= (float) 0)
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");
@ -451,7 +457,7 @@ main (int argc, char **argv)
case 'f':
if (optarg[0] == 'a')
{
opts.frame_dstar = 0;
opts.frame_dstar = 1;
opts.frame_x2tdma = 1;
opts.frame_p25p1 = 1;
opts.frame_nxdn48 = 0;
@ -649,6 +655,9 @@ main (int argc, char **argv)
opts.datascope = 0;
state.optind = optind;
break;
case 'l':
opts.use_cosine_filter = 0;
break;
default:
usage ();
exit (0);

View File

@ -77,6 +77,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
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++)
{
@ -99,9 +102,27 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
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);

View File

@ -88,6 +88,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
}
}
// printf("res: %zd\n, offset: %lld", result, sf_seek(opts->audio_in_file, 0, SEEK_CUR));
if (opts->use_cosine_filter)
{
#define NZEROS 60
#define GAIN 7.423339364e+00

178
dstar.c
View File

@ -16,64 +16,148 @@
*/
/*
* Note: D-STAR support is very incomplete and does not work yet
* It is unknown if the ambe3600x2450 decoder is even compatible with D-STAR
* voice frames. If it is then the interleave pattern needs to be determined.
* 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
* rate. This was included mainly as an example of how other systmes might
* be supported.
*/
#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];
char dstar[300];
const int *w, *x;
if (opts->errorbars == 1)
{
printf ("e:");
}
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");
printf ("\n");
#endif
for (j = 0; j < 210; j++) // 210 is very long but used for debugging
{
// voice frame
w = dW;
x = dX;
for (i = 0; i < 72; i++)
{
dibit = getDibit (opts, state);
dstar[i] = dibit + 48;
ambe_fr[*w][*x] = (1 & dibit);
w++;
x++;
}
dstar[i] = 32;
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
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
}
// data frame
for (i = 73; i < 97; i++)
{
dstar[i] = getDibit (opts, state) + 48;
}
dstar[i] = 0;
while (sync_missed < 3) {
#ifdef DSTAR_DUMP
printf ("%s\n", dstar);
#endif
}
if (opts->errorbars == 1)
{
printf ("\n");
}
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);
}

View File

@ -25,287 +25,105 @@ extern const int dW[72];
extern const int dX[72];
#else
/*
* 4x18
*/
/*
const int dW[72] = {
0,0,1,2,
0,0,1,2,
0,0,1,2,
0,0,1,2,
0,0,1,3,
0,0,1,3,
0,1,1,3,
0,1,1,3,
0,1,1,3,
0,1,1,3,
0,1,1,3,
0,1,2,3,
0,1,2,3,
0,1,2,3,
0,1,2,3,
0,1,2,3,
0,1,2,3,
0,1,2,3
};
// 0-11
0, 0,
3, 2,
1, 1,
0, 0,
1, 1,
0, 0,
// 12-23
3, 2,
1, 1,
3, 2,
1, 1,
0, 0,
3, 2,
// 24-35
0, 0,
3, 2,
1, 1,
0, 0,
1, 1,
0, 0,
// 36-47
3, 2,
1, 1,
3, 2,
1, 1,
0, 0,
3, 2,
// 48-59
0, 0,
3, 2,
1, 1,
0, 0,
1, 1,
0, 0,
// 60-71
3, 2,
1, 1,
3, 3,
2, 1,
0, 0,
3, 3,
};
const int dX[72] = {
23,5,10,3,
22,4,9,2,
21,3,8,1,
20,2,7,0,
19,1,6,13,
18,0,5,12,
17,22,4,11,
16,21,3,10,
15,20,2,9,
14,19,1,8,
13,18,0,7,
12,17,10,6,
11,16,9,5,
10,15,8,4,
9,14,7,3,
8,13,6,2,
7,12,5,1,
6,11,4,0
};
*/
/*
* 3x24 alt
*/
const int dW[72] = {
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 3,
1, 0, 2,
1, 0, 2,
1, 0, 2,
1, 0, 2,
1, 0, 2,
1, 0, 2,
1, 0, 2,
1, 0, 2,
1, 0, 2,
1, 0, 2,
0, 3, 2,
};
// 0-11
10, 22,
11, 9,
10, 22,
11, 23,
8, 20,
9, 21,
const int dX[72] = {
22, 22, 12,
21, 21, 11,
20, 20, 10,
19, 19, 9,
18, 18, 8,
17, 17, 7,
16, 16, 6,
15, 15, 5,
14, 14, 4,
13, 13, 3,
12, 12, 2,
11, 11, 1,
10, 10, 0,
9, 9, 10,
8, 8, 9,
7, 7, 8,
6, 6, 7,
5, 5, 6,
4, 4, 5,
3, 3, 4,
2, 2, 3,
1, 1, 2,
0, 0, 1,
23, 13, 0
};
// 12-23
10, 8,
9, 21,
8, 6,
7, 19,
8, 20,
9, 7,
/*
* 3x24
*/
/*
const int dW[72] = {
0,1,2,
0,1,2,
0,1,2,
0,1,2,
0,1,2,
0,1,2,
0,1,2,
0,1,2,
0,1,2,
0,1,2,
0,1,3,
0,1,3,
0,1,3,
0,1,3,
0,1,3,
0,1,3,
0,1,3,
0,1,3,
0,1,3,
0,1,3,
0,1,3,
0,1,3,
0,1,3,
0,2,3,
};
// 24-35
6, 18,
7, 5,
6, 18,
7, 19,
4, 16,
5, 17,
const int dX[72] = {
23,22,9,
22,21,8,
21,20,7,
20,19,6,
19,18,5,
18,17,4,
17,16,3,
16,15,2,
15,14,1,
14,13,0,
13,12,13,
12,11,12,
11,10,11,
10,9,10,
9,8,9,
8,7,8,
7,6,7,
6,5,6,
5,4,5,
4,3,4,
3,2,3,
2,1,2,
1,0,1,
0,10,0
};
*/
// 36-47
6, 4,
5, 17,
4, 2,
3, 15,
4, 16,
5, 3,
// 48-59
2, 14,
3, 1,
2, 14,
3, 15,
0, 12,
1, 13,
/*
* 2x36
*/
/*
const int dW[72] = {
0,1,
0,1,
0,1,
0,1,
0,1,
0,1,
0,1,
0,1,
0,1,
0,1,
0,1,
0,2,
0,2,
0,2,
0,2,
0,2,
0,2,
0,2,
0,2,
0,2,
0,2,
0,2,
0,3,
0,3,
1,3,
1,3,
1,3,
1,3,
1,3,
1,3,
1,3,
1,3,
1,3,
1,3,
1,3,
1,3
// 60-71
2, 0,
1, 13,
0, 12,
10, 11,
0, 12,
1, 13,
};
const int dX[72] = {
23,10,
22,9,
21,8,
20,7,
19,6,
18,5,
17,4,
16,3,
15,2,
14,1,
13,0,
12,10,
11,9,
10,8,
9,7,
8,6,
7,5,
6,4,
5,3,
4,2,
3,1,
2,0,
1,13,
0,12,
22,11,
21,10,
20,9,
19,8,
18,7,
17,6,
16,5,
15,4,
14,3,
13,2,
12,1,
11,0
};
*/
/*
* non-interleaved
*/
/*
const int dW[72] = {
0,0,0,0,0,0,
0,0,0,0,0,0,
0,0,0,0,0,0,
0,0,0,0,0,0,
1,1,1,1,1,1,
1,1,1,1,1,1,
1,1,1,1,1,1,
1,1,1,1,1,2,
2,2,2,2,2,2,
2,2,2,2,3,3,
3,3,3,3,3,3,
3,3,3,3,3,3
};
const int dX[72] = {
23,22,21,20,19,18,
17,16,15,14,13,12,
11,10,9,8,7,6,
5,4,3,2,1,0,
22,21,20,19,18,17,
16,15,14,13,12,11,
10,9,8,7,6,5,
4,3,2,1,0,10,
9,8,7,6,5,4,
3,2,1,0,13,12,
11,10,9,8,7,6,
5,4,3,2,1,0
};
*/
#endif

76
dstar_header.c Normal file
View File

@ -0,0 +1,76 @@
/*
*
* This code is taken largely from on1arf's GMSK code. Original copyright below:
*
*
* Copyright (C) 2011 by Kristoff Bonne, ON1ARF
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "fcs.h"
#include "descramble.h"
#include "dstar_header.h"
void dstar_header_decode(int radioheaderbuffer[660]) {
int radioheaderbuffer2[660];
unsigned char radioheader[41];
int octetcount, bitcount, loop;
unsigned char bit2octet[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
unsigned int FCSinheader;
unsigned int FCScalculated;
int len;
scramble(radioheaderbuffer, radioheaderbuffer2);
deinterleave(radioheaderbuffer2, radioheaderbuffer);
len = FECdecoder(radioheaderbuffer, radioheaderbuffer2);
memset(radioheader, 0, 41);
// note we receive 330 bits, but we only use 328 of them (41 octets)
// bits 329 and 330 are unused
octetcount = 0;
bitcount = 0;
for (loop = 0; loop < 328; loop++) {
if (radioheaderbuffer2[loop]) {
radioheader[octetcount] |= bit2octet[bitcount];
};
bitcount++;
// increase octetcounter and reset bitcounter every 8 bits
if (bitcount >= 8) {
octetcount++;
bitcount = 0;
}
}
// print header
printf("\nDSTAR HEADER: ");
//printf("FLAG1: %02X - FLAG2: %02X - FLAG3: %02X\n", radioheader[0],
// radioheader[1], radioheader[2]);
printf("RPT 2: %c%c%c%c%c%c%c%c ", radioheader[3], radioheader[4],
radioheader[5], radioheader[6], radioheader[7], radioheader[8],
radioheader[9], radioheader[10]);
printf("RPT 1: %c%c%c%c%c%c%c%c ", radioheader[11], radioheader[12],
radioheader[13], radioheader[14], radioheader[15], radioheader[16],
radioheader[17], radioheader[18]);
printf("YOUR: %c%c%c%c%c%c%c%c ", radioheader[19], radioheader[20],
radioheader[21], radioheader[22], radioheader[23], radioheader[24],
radioheader[25], radioheader[26]);
printf("MY: %c%c%c%c%c%c%c%c/%c%c%c%c\n", radioheader[27],
radioheader[28], radioheader[29], radioheader[30], radioheader[31],
radioheader[32], radioheader[33], radioheader[34], radioheader[35],
radioheader[36], radioheader[37], radioheader[38]);
//FCSinheader = ((radioheader[39] << 8) | radioheader[40]) & 0xFFFF;
//FCScalculated = calc_fcs((unsigned char*) radioheader, 39);
//printf("Check sum = %04X ", FCSinheader);
//if (FCSinheader == FCScalculated) {
// printf("(OK)\n");
//} else {
// printf("(NOT OK- Calculated FCS = %04X)\n", FCScalculated);
//}; // end else - if
}

6
dstar_header.h Normal file
View File

@ -0,0 +1,6 @@
/* This is the header file for dstar_header.c, which is under the GPL. */
#ifndef _DSTAR_HEADER_H
#define _DSTAR_HEADER_H
void dstar_header_decode(int radioheaderbuffer[660]);
#endif /* _DSTAR_HEADER_H */

91
fcs.h Normal file
View File

@ -0,0 +1,91 @@
/* fcs.h */
// Viterbi decoder using Traceback method.
// Original Source was written by Sho Tamaoki and Tom Wada
// See http://www.lsi.ie.u-ryukyu.ac.jp/~sho/midterm/
// Modified by Satoshi Yasuda 7m3tjz/ad6gz
// Modified by Jonathan Nayor, G4KLX (C) 2009
// Converted from C++ to C by Kristoff Bonne, ON1ARF
/*
* Copyright (C) 2010 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 <stdint.h>
static const unsigned short ccittTab[] = {
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78};
uint16_t calc_fcs (unsigned char * dvstartframe, int size) {
// this function calculated the CRC-values of a DSTAR digital
// voice frame. It calculates this value on octets 0 up to 38 of the D-STAR
// radio header (fields flag1, flag2, flag3, destination, departure, companion,
// own1 and own2)
uint16_t m_crc;
m_crc=0xFFFF;
int loop;
unsigned short tmp;
for (loop=0; loop < size; loop++) {
tmp = (m_crc & 0x00ff) ^ dvstartframe[loop];
m_crc = (m_crc >> 8) ^ ccittTab[tmp];
}; // end for
// calculate and save crc-value in fields 54 and 55 of dvframe
m_crc = ~m_crc;
tmp = m_crc;
m_crc = (m_crc << 8) | (tmp >> 8 & 0xFF);
// done
return(m_crc);
}; // end function