diff --git a/DSP_API/SmartSDR_Interface/sched_waveform.c b/DSP_API/SmartSDR_Interface/sched_waveform.c index 64d2c3a..c11c4c6 100644 --- a/DSP_API/SmartSDR_Interface/sched_waveform.c +++ b/DSP_API/SmartSDR_Interface/sched_waveform.c @@ -139,6 +139,8 @@ void sched_waveform_signal() #include "circular_buffer.h" #include "resampler.h" +#include "gmsk_modem.h" + #define PACKET_SAMPLES 128 #define DV_PACKET_SAMPLES 160 @@ -197,6 +199,9 @@ Circular_Float_Buffer TX4_cb = &tx4_cb; static int _dv_serial_fd = 0; +static GMSK_DEMOD _gmsk_demod = NULL; +static GMSK_MOD _gmsk_mod = NULL; + static void* _sched_waveform_thread(void* param) { int nin, nout; @@ -603,6 +608,44 @@ void sched_waveform_Init(void) struct sched_param fifo_param; fifo_param.sched_priority = 30; pthread_setschedparam(_waveform_thread, SCHED_FIFO, &fifo_param); + + _gmsk_demod = gmsk_createDemodulator(); + _gmsk_mod = gmsk_createModulator(); + + float test_buffer[160*2]; + unsigned char test_coded[8] = {0xAA,0xAA,0xFF,0x00,0xFF,0x00,0xFF,0x00}; + unsigned char output_bytes[8] = {0}; + uint32 i = 0; + +// +// BOOL bits[32] = {0}; +// gmsk_bytesToBits(test_coded, bits, 32); +// gmsk_byteToBits(0xF0, bits, 8); +// output("0xF0 = "); +// +// for ( i = 0 ; i < 8; i++ ){ +// output("%d ", bits[i]); +// } +// output("\n"); +// unsigned char test[4] = {0xAA, 0xAA, 0xAA, 0xAA}; +// gmsk_bytesToBits(test, bits, 32); +// +// for ( i = 0 ; i < 32/8 ; i++ ) { +// gmsk_bitsToByte(&bits[i*8], &output_bytes[i]); +// output("Byte = 0x%02X\n", output_bytes[i]); +// } +// + gmsk_encodeBuffer(_gmsk_mod, test_coded, 32*2, test_buffer, 160*2); +// FILE * dat = fopen("gmsk.dat", "w"); +// for ( i = 0 ; i < 160*2 ; i++ ) { +// fprintf(dat, "%d %.12f\n", i, test_buffer[i]); +// //output("%.12f,", test_buffer[i]); +// } +// fclose(dat); + + gmsk_decodeBuffer(_gmsk_demod, test_buffer, 160*2, output_bytes, 32*2); + + exit(0); } void sched_waveformThreadExit() diff --git a/DSP_API/ThumbDV/DStarDefines.h b/DSP_API/ThumbDV/DStarDefines.h index f00263d..fe82e99 100644 --- a/DSP_API/ThumbDV/DStarDefines.h +++ b/DSP_API/ThumbDV/DStarDefines.h @@ -88,7 +88,7 @@ const BOOL NULL_SLOW_DATA_BITS[] = {FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TR #define DSTAR_AUDIO_BLOCK_SIZE 160U #define DSTAR_AUDIO_BLOCK_BYTES (DSTAR_AUDIO_BLOCK_SIZE * 2U) -#define DSTAR_RADIO_SAMPLE_RATE 48000U +#define DSTAR_RADIO_SAMPLE_RATE 24000 #define DSTAR_RADIO_BLOCK_SIZE 960U #define LONG_CALLSIGN_LENGTH 8U diff --git a/DSP_API/ThumbDV/gmsk_modem.c b/DSP_API/ThumbDV/gmsk_modem.c index e3ce527..606d610 100644 --- a/DSP_API/ThumbDV/gmsk_modem.c +++ b/DSP_API/ThumbDV/gmsk_modem.c @@ -32,6 +32,110 @@ #include "gmsk_modem.h" #include "common.h" +/* Filters */ + +void gmsk_bitsToByte(BOOL * bits, unsigned char * byte) +{ + if ( bits == NULL || byte == NULL) { + output(ANSI_RED "NULL Pointer in bitsToByte\n" ANSI_WHITE); + return; + } + + unsigned char new_byte = 0x0; + uint32 i = 0; + for ( i = 0 ; i < 8; i++ ) { + new_byte <<= 1; + if ( bits[i] ) { + new_byte |= 0x01; + } + } + *byte = new_byte; +} + +void gmsk_byteToBits(unsigned char byte, BOOL * bits, uint32 num_bits) +{ + if ( bits == NULL ) { + output(ANSI_RED "NULL Pointer in byteToBits\n" ANSI_WHITE); + return; + } + + uint32 i = 0; + unsigned char mask = 0x80; + for ( i = 0; i < num_bits; i++ , mask >>= 1) { + bits[i] = (byte & mask) ? TRUE : FALSE; + } +} + +void gmsk_bytesToBits(unsigned char * bytes, BOOL * bits, uint32 num_bits) +{ + if ( bytes == NULL || bits == NULL ) { + output(ANSI_RED "NULL pointers in bytesToBits\n" ANSI_WHITE); + return; + } + + uint32 bits_left = num_bits; + uint32 byte_idx = 0; + while ( bits_left != 0 ) { + gmsk_byteToBits(bytes[byte_idx], &bits[byte_idx * 8], bits_left > 8 ? 8 : bits_left); + byte_idx++; + bits_left -= 8; + } + + uint32 i = 0; + output("Bytes: "); + for ( i = 0 ; i < num_bits / 8U ; i++ ) { + output(" 0x%02X", bytes[i]); + } + output("\nBits: "); + for ( i = 0 ; i < num_bits ; i++ ) { + output("%s ", bits[i] ? "1":"0"); + if ( (i+1) % 4 == 0 ) { + output(" "); + } + } + output("\n"); + +} + +float gmsk_FilterProcessSingle(FIR_FILTER filter, float val) +{ + if ( filter == NULL ) { + output(ANSI_RED "NULL FIlter object\n"ANSI_WHITE ) ; + return val; + } + float * ptr = filter->buffer + filter->pointer++; + + *ptr = val; + + float * a = ptr - filter->length; + float * b = filter->taps; + + float out = 0.0F; + uint32 i = 0; + for ( i = 0U; i < filter->length; i++) + out += (*a++) * (*b++); + + if (filter->pointer == filter->buf_len) { + memcpy(filter->buffer, filter->buffer + filter->buf_len - filter->length, filter->length * sizeof(float)); + filter->pointer = filter->length; + } + + return out; +} + +void gmsk_FilterProcessBuffer(FIR_FILTER filter, float * buffer, uint32 buffer_len) +{ + if ( filter == NULL ) { + output(ANSI_RED "NULL FIlter object\n"ANSI_WHITE ) ; + return; + } + + uint32 i = 0; + for ( i = 0 ; i < buffer_len; i++ ) { + buffer[i] = gmsk_FilterProcessSingle(filter, buffer[i]); + } +} + /* Demod Section */ const float DEMOD_COEFFS_TABLE[] = { @@ -66,7 +170,7 @@ const float DEMOD_COEFFS_TABLE[] = { #define DEMOD_COEFFS_LENGTH 103U #define PLLMAX 0x10000U -#define PLLINC ( PLLMAX / DSTAR_RADIO_BIT_LENGTH) +#define PLLINC ( PLLMAX / DSTAR_RADIO_BIT_LENGTH) // 2000 #define INC 32U @@ -75,15 +179,14 @@ enum DEMOD_STATE gmsk_decode(GMSK_DEMOD demod, float val) enum DEMOD_STATE state = DEMOD_UNKNOWN; /* FIlter process */ - float out = 0;//m_filter.process(val); + float out = val;//gmsk_FilterProcessSingle(demod->filter, val); BOOL bit = out > 0.0F; if (bit != demod->m_prev) { if (demod->m_pll < (PLLMAX / 2U) ) { demod->m_pll += PLLINC / INC; - } - else { + } else { demod->m_pll -= PLLINC / INC; } } @@ -110,6 +213,47 @@ void gmskDemod_reset(GMSK_DEMOD demod ) demod->m_prev = FALSE; } +void gmsk_decodeBuffer(GMSK_DEMOD demod, float * buffer,uint32 buf_len, unsigned char * bytes, uint32 num_bits) +{ + if ( num_bits * DSTAR_RADIO_BIT_LENGTH != buf_len ) { + output(ANSI_RED "Mismatched buf_len to number of encoded bits. buf_len = %d, required %d\n" ANSI_WHITE, buf_len, num_bits * DSTAR_RADIO_BIT_LENGTH); + return; + } + + BOOL bits[num_bits]; + uint32 i = 0; + uint32 bit = 0; + enum DEMOD_STATE state; + for ( i = 0; i < buf_len ; i++) { + state = gmsk_decode(demod, buffer[i]); + if ( state == DEMOD_TRUE ) { + bits[bit] = TRUE; + bit++; + } else if ( state == DEMOD_FALSE ) { + bits[bit] = FALSE; + bit++; + } else { + //output("UNKNOWN DEMOD STATE"); + //bits[bit] = 0x00; + } + } + + for ( i = 0; i < bit; i++ ) { + output("%d", bits[i] ? 1:0); + if ( (i+1) % 4 == 0 ) output(" "); + } output("\n"); + +// FILE * f = fopen("gmsk_demod.dat", "w"); +// for ( i = 0 ; i < num_bits ; i++ ) { +// fprintf(f,"%d %d\n", i, bits[i]); +// } +// fclose(f); + + for ( i = 0 ; i < num_bits / 8 ; i++ ) { + gmsk_bitsToByte(&bits[i*8], &bytes[i]); + } +} + /* Mod Section */ @@ -136,7 +280,7 @@ const float MOD_COEFFS_TABLE[] = { uint32 gmsk_encode(GMSK_MOD mod, BOOL bit, float * buffer, unsigned int length) { - if ( length == DSTAR_RADIO_BIT_LENGTH ) { + if ( length != DSTAR_RADIO_BIT_LENGTH ) { output(ANSI_RED "Length!= DSTAR_RADIO_BIT_LENGTH" ANSI_WHITE); } @@ -147,15 +291,39 @@ uint32 gmsk_encode(GMSK_MOD mod, BOOL bit, float * buffer, unsigned int length) for (i = 0; i < DSTAR_RADIO_BIT_LENGTH; i++) { if (bit) { - buffer[i] = 0;//m_filter.process(-0.5F); + //buffer[i] = -0.5f;//gmsk_FilterProcessSingle(mod->filter, -0.5f); + buffer[i] = gmsk_FilterProcessSingle(mod->filter, -0.5f); } else { - buffer[i] = 0;//m_filter.process(0.5F); + //buffer[i] = 0.5f;//gmsk_FilterProcessSingle(mod->filter, 0.5f); + buffer[i] = gmsk_FilterProcessSingle(mod->filter, 0.5f); } } return DSTAR_RADIO_BIT_LENGTH; } +BOOL gmsk_encodeBuffer(GMSK_MOD mod, unsigned char * bytes, uint32 num_bits, float * buffer, uint32 buf_len) +{ + if ( num_bits * DSTAR_RADIO_BIT_LENGTH != buf_len ) { + output(ANSI_RED "Mismatched buf_len to number of encoded bits. buf_len = %d, required %d\n" ANSI_WHITE, buf_len, num_bits * DSTAR_RADIO_BIT_LENGTH); + return FALSE; + } + + uint32 i = 0; + float * idx = &buffer[0]; + + BOOL bits[num_bits]; + + gmsk_bytesToBits(bytes, bits, num_bits); + + for ( i = 0 ; i < num_bits ; i++, idx += DSTAR_RADIO_BIT_LENGTH ) { + gmsk_encode(mod, bits[i], idx, DSTAR_RADIO_BIT_LENGTH); + } + + return TRUE; +} + + /* Init */ FIR_FILTER gmsk_createFilter(const float * taps, uint32 length) @@ -176,9 +344,9 @@ FIR_FILTER gmsk_createFilter(const float * taps, uint32 length) void gmsk_destroyFilter(FIR_FILTER filter) { if ( filter == NULL ) { - output(ANSI_RED "NULL FIlter object\n"ANSI_WHITE ) ; - return; - } + output(ANSI_RED "NULL FIlter object\n"ANSI_WHITE ) ; + return; + } safe_free(filter->taps); safe_free(filter->buffer); diff --git a/DSP_API/ThumbDV/gmsk_modem.h b/DSP_API/ThumbDV/gmsk_modem.h index 96d4484..9158577 100644 --- a/DSP_API/ThumbDV/gmsk_modem.h +++ b/DSP_API/ThumbDV/gmsk_modem.h @@ -58,6 +58,12 @@ typedef struct _gmsk_mod FIR_FILTER filter; } gmsk_mod, * GMSK_MOD; +void gmsk_bitsToByte(BOOL * bits, unsigned char * byte); +void gmsk_byteToBits(unsigned char byte, BOOL * bits, uint32 num_bits); +void gmsk_bytesToBits(unsigned char * bytes, BOOL * bits, uint32 num_bits); + +BOOL gmsk_encodeBuffer(GMSK_MOD mod, unsigned char * bytes, uint32 num_bits, float * buffer, uint32 buf_len); +void gmsk_decodeBuffer(GMSK_DEMOD demod, float * buffer,uint32 buf_len, unsigned char * bytes, uint32 num_bits); uint32 gmsk_encode(GMSK_MOD mod, BOOL bit, float * buffer, unsigned int length); diff --git a/DSP_API/ThumbDV/thumbDV.c b/DSP_API/ThumbDV/thumbDV.c index 2d885b0..272f1b8 100644 --- a/DSP_API/ThumbDV/thumbDV.c +++ b/DSP_API/ThumbDV/thumbDV.c @@ -326,7 +326,7 @@ int thumbDV_openSerial(const char * tty_name) return -1; } - output("opened %s - fd = %d\n", tty_name, fd); + //output("opened %s - fd = %d\n", tty_name, fd); return fd; } @@ -378,7 +378,7 @@ int thumbDV_processSerial(int serial_fd) packet_type = buffer[3]; //dump("Serial data", buffer, respLen); if ( packet_type == AMBE3000_CTRL_PKT_TYPE ) { - dump("Serial data", buffer, respLen); + // dump("Serial data", buffer, respLen); } else if ( packet_type == AMBE3000_CHAN_PKT_TYPE ) { desc = hal_BufferRequest(respLen, sizeof(unsigned char) ); memcpy(desc->buf_ptr, buffer, respLen);