mirror of https://github.com/lwvmobile/dsd-fme.git
Initial working DSTAR voice support
This commit is contained in:
parent
27960ae4be
commit
040ea148b0
15
COPYRIGHT
15
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)
|
||||
|
||||
|
|
|
|||
115
Makefile
115
Makefile
|
|
@ -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
9
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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
4
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);
|
||||
|
|
|
|||
18
dsd_audio.c
18
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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
26
dsd_frame.c
26
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;
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
19
dsd_main.c
19
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 <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);
|
||||
|
|
|
|||
21
dsd_mbe.c
21
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);
|
||||
|
|
|
|||
|
|
@ -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
178
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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
362
dstar_const.h
362
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue