From 040ea148b098860829da0802c3509059f35bcd39 Mon Sep 17 00:00:00 2001 From: balr0g Date: Sat, 14 Dec 2013 20:02:43 -0500 Subject: [PATCH] Initial working DSTAR voice support --- COPYRIGHT | 15 ++ Makefile | 115 --------------- README | 9 +- descramble.h | 293 ++++++++++++++++++++++++++++++++++++++ dsd.h | 4 + dsd_audio.c | 18 +-- dsd_dibit.c | 4 +- dsd_frame.c | 26 ++++ dsd_frame_sync.c | 31 ++++ dsd_main.c | 19 ++- dsd_mbe.c | 21 +++ dsd_symbol.c | 1 + dstar.c | 178 +++++++++++++++++------ dstar_const.h | 362 ++++++++++++----------------------------------- dstar_header.c | 76 ++++++++++ dstar_header.h | 6 + fcs.h | 91 ++++++++++++ 17 files changed, 814 insertions(+), 455 deletions(-) delete mode 100644 Makefile create mode 100644 descramble.h create mode 100644 dstar_header.c create mode 100644 dstar_header.h create mode 100644 fcs.h diff --git a/COPYRIGHT b/COPYRIGHT index d402478..1d3e29c 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -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) diff --git a/Makefile b/Makefile deleted file mode 100644 index fcf64a4..0000000 --- a/Makefile +++ /dev/null @@ -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 diff --git a/README b/README index bfa61e3..b335c60 100644 --- a/README +++ b/README @@ -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: diff --git a/descramble.h b/descramble.h new file mode 100644 index 0000000..c167f7b --- /dev/null +++ b/descramble.h @@ -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 +#include + +// 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= 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 + + + + diff --git a/dsd.h b/dsd.h index d187d6a..1285cc8 100644 --- a/dsd.h +++ b/dsd.h @@ -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); diff --git a/dsd_audio.c b/dsd_audio.c index 90150c9..6e48c9e 100644 --- a/dsd_audio.c +++ b/dsd_audio.c @@ -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; diff --git a/dsd_dibit.c b/dsd_dibit.c index ffa4540..3d05e4e 100644 --- a/dsd_dibit.c +++ b/dsd_dibit.c @@ -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) { diff --git a/dsd_frame.c b/dsd_frame.c index 4923dd1..8a7aef1 100644 --- a/dsd_frame.c +++ b/dsd_frame.c @@ -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; diff --git a/dsd_frame_sync.c b/dsd_frame_sync.c index b2aa950..91ed884 100644 --- a/dsd_frame_sync.c +++ b/dsd_frame_sync.c @@ -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)) diff --git a/dsd_main.c b/dsd_main.c index 866fda5..7cbe5f6 100644 --- a/dsd_main.c +++ b/dsd_main.c @@ -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 Audio input device (default is /dev/audio)\n"); printf (" -o Audio output device (default is /dev/audio)\n"); printf (" -d Create mbe data files, use this directory\n"); - printf (" -g Audio output gain (default = 0 = auto)\n"); + printf (" -g Audio output gain (default = 0 = auto, disable = -1)\n"); printf (" -n Do not send synthesized speech to audio output device\n"); printf (" -w 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); diff --git a/dsd_mbe.c b/dsd_mbe.c index 884a218..a7984c1 100644 --- a/dsd_mbe.c +++ b/dsd_mbe.c @@ -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); diff --git a/dsd_symbol.c b/dsd_symbol.c index e8d3849..c9d18e1 100644 --- a/dsd_symbol.c +++ b/dsd_symbol.c @@ -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 diff --git a/dstar.c b/dstar.c index 5905383..358baa1 100644 --- a/dstar.c +++ b/dstar.c @@ -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); + +} + diff --git a/dstar_const.h b/dstar_const.h index 35bf59e..23df459 100644 --- a/dstar_const.h +++ b/dstar_const.h @@ -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 diff --git a/dstar_header.c b/dstar_header.c new file mode 100644 index 0000000..9314b9e --- /dev/null +++ b/dstar_header.c @@ -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 +} diff --git a/dstar_header.h b/dstar_header.h new file mode 100644 index 0000000..9723fbf --- /dev/null +++ b/dstar_header.h @@ -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 */ \ No newline at end of file diff --git a/fcs.h b/fcs.h new file mode 100644 index 0000000..314ebac --- /dev/null +++ b/fcs.h @@ -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 + +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