From 1eb4542a162483adadc7dfd215d3ac1c1f917983 Mon Sep 17 00:00:00 2001 From: drowe67 Date: Thu, 18 Jun 2015 23:37:49 +0000 Subject: [PATCH] testframes working in freedv API, and tested with freedv_tx and freedv_rx git-svn-id: https://svn.code.sf.net/p/freetel/code@2207 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/CMakeLists.txt | 2 +- codec2-dev/src/codec2_cohpsk.h | 5 + codec2-dev/src/cohpsk.c | 76 +++++++++ codec2-dev/src/cohpsk_get_test_bits.c | 10 +- codec2-dev/src/cohpsk_internal.h | 4 + codec2-dev/src/cohpsk_mod.c | 2 +- codec2-dev/src/cohpsk_put_test_bits.c | 58 ++----- codec2-dev/src/freedv_api.c | 214 ++++++++++++++------------ codec2-dev/src/freedv_api.h | 8 + codec2-dev/src/freedv_rx.c | 34 ++-- codec2-dev/src/freedv_tx.c | 6 +- 11 files changed, 254 insertions(+), 165 deletions(-) diff --git a/codec2-dev/CMakeLists.txt b/codec2-dev/CMakeLists.txt index b64f4fd0..f74643f2 100644 --- a/codec2-dev/CMakeLists.txt +++ b/codec2-dev/CMakeLists.txt @@ -48,7 +48,7 @@ message(STATUS "codec2 version: ${CODEC2_VERSION}") # Set default build type if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release") + set(CMAKE_BUILD_TYPE "Debug") endif() # Set default C++ flags. diff --git a/codec2-dev/src/codec2_cohpsk.h b/codec2-dev/src/codec2_cohpsk.h index cea97ab6..c8d6d250 100644 --- a/codec2-dev/src/codec2_cohpsk.h +++ b/codec2-dev/src/codec2_cohpsk.h @@ -42,6 +42,8 @@ struct COHPSK; +extern const int test_bits_coh[]; + struct COHPSK *cohpsk_create(void); void cohpsk_destroy(struct COHPSK *coh); void cohpsk_mod(struct COHPSK *cohpsk, COMP tx_fdm[], int tx_bits[]); @@ -49,5 +51,8 @@ void cohpsk_clip(COMP tx_fdm[]); void cohpsk_demod(struct COHPSK *cohpsk, float rx_bits[], int *sync, COMP rx_fdm[], int *nin_frame); void cohpsk_get_demod_stats(struct COHPSK *cohpsk, struct MODEM_STATS *stats); void cohpsk_set_verbose(struct COHPSK *coh, int verbose); +void cohpsk_get_test_bits(struct COHPSK *coh, int rx_bits[]); +void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[], + int *bit_errors, float rx_bits_sd[]); #endif diff --git a/codec2-dev/src/cohpsk.c b/codec2-dev/src/cohpsk.c index c8ed48df..cda8a727 100644 --- a/codec2-dev/src/cohpsk.c +++ b/codec2-dev/src/cohpsk.c @@ -46,6 +46,7 @@ #include "kiss_fft.h" #include "linreg.h" #include "rn_coh.h" +#include "test_bits_coh.h" static COMP qpsk_mod[] = { { 1.0, 0.0}, @@ -178,6 +179,11 @@ struct COHPSK *cohpsk_create(void) coh->rx_timing_log = NULL; coh->rx_timing_log_index = 0; + /* test frames */ + + coh->ptest_bits_coh_tx = coh->ptest_bits_coh_rx = (int*)test_bits_coh; + coh->ptest_bits_coh_end = (int*)test_bits_coh + sizeof(test_bits_coh)/sizeof(int); + return coh; } @@ -1136,3 +1142,73 @@ void cohpsk_set_verbose(struct COHPSK *coh, int verbose) } +/*---------------------------------------------------------------------------*\ + + FUNCTION....: cohpsk_get_test_bits() + AUTHOR......: David Rowe + DATE CREATED: June 2015 + + Returns a frame of known test bits. + +\*---------------------------------------------------------------------------*/ + +void cohpsk_get_test_bits(struct COHPSK *coh, int rx_bits[]) +{ + memcpy(rx_bits, coh->ptest_bits_coh_tx, sizeof(int)*COHPSK_BITS_PER_FRAME); + coh->ptest_bits_coh_tx += COHPSK_BITS_PER_FRAME; + if (coh->ptest_bits_coh_tx >=coh->ptest_bits_coh_end) { + coh->ptest_bits_coh_tx = (int*)test_bits_coh; + } +} + + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: cohpsk_put_test_bits() + AUTHOR......: David Rowe + DATE CREATED: June 2015 + + Accepts bits from demod and attempts to sync with the known + test_bits sequence. When synced measures bit errors. + +\*---------------------------------------------------------------------------*/ + +void cohpsk_put_test_bits(struct COHPSK *coh, int *state, short error_pattern[], + int *bit_errors, float rx_bits_sd[]) +{ + int i, next_state, anerror; + int rx_bits[COHPSK_BITS_PER_FRAME]; + + for(i=0; iptest_bits_coh_rx[i]; + *bit_errors += anerror; + error_pattern[i] = anerror; + } + + /* state logic */ + + next_state = *state; + + if (*state == 0) { + if (*bit_errors < 4) { + next_state = 1; + coh->ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME; + } + } + + if (*state == 1) { + coh->ptest_bits_coh_rx += COHPSK_BITS_PER_FRAME; + if (coh->ptest_bits_coh_rx >= coh->ptest_bits_coh_end) { + coh->ptest_bits_coh_rx = (int*)test_bits_coh; + } + } + + *state = next_state; +} + + diff --git a/codec2-dev/src/cohpsk_get_test_bits.c b/codec2-dev/src/cohpsk_get_test_bits.c index d54be81f..ed4f5473 100644 --- a/codec2-dev/src/cohpsk_get_test_bits.c +++ b/codec2-dev/src/cohpsk_get_test_bits.c @@ -40,11 +40,12 @@ int main(int argc, char *argv[]) { FILE *fout; int tx_bits[COHPSK_BITS_PER_FRAME]; + float sd_tx_bits[COHPSK_BITS_PER_FRAME]; int numBits, nFrames, n; - int *ptest_bits_coh, *ptest_bits_coh_end; + int *ptest_bits_coh, *ptest_bits_coh_end, i; if (argc < 2) { - printf("usage: %s OutputOneBitPerIntFile numBits\n", argv[0]); + printf("usage: %s OutputOneFloatPerBitFile numBits\n", argv[0]); exit(1); } @@ -68,7 +69,10 @@ int main(int argc, char *argv[]) ptest_bits_coh = (int*)test_bits_coh; } - fwrite(tx_bits, sizeof(int), COHPSK_BITS_PER_FRAME, fout); + for(i=0; i #include "codec2_cohpsk.h" -#include "test_bits_coh.h" #include "octave.h" #define LOG_FRAMES 100 @@ -44,17 +43,17 @@ int main(int argc, char *argv[]) { FILE *fin, *foct; float rx_bits_sd[COHPSK_BITS_PER_FRAME]; - int rx_bits[COHPSK_BITS_PER_FRAME]; - int *ptest_bits_coh, *ptest_bits_coh_end; - int state, next_state, i, nbits, errors, nerrors; + int state, i, nbits, bit_errors, nerrors; + short error_pattern[COHPSK_BITS_PER_FRAME]; int error_positions_hist[COHPSK_BITS_PER_FRAME], logframes; int nerr_log[LOG_FRAMES]; + struct COHPSK *coh; for(i=0; i= ptest_bits_coh_end) { - ptest_bits_coh = (int*)test_bits_coh; - } - if (logframes < LOG_FRAMES) - nerr_log[logframes++] = errors; } - state = next_state; - if (fin == stdin) fflush(stdin); } diff --git a/codec2-dev/src/freedv_api.c b/codec2-dev/src/freedv_api.c index 5d672beb..04726d87 100644 --- a/codec2-dev/src/freedv_api.c +++ b/codec2-dev/src/freedv_api.c @@ -58,7 +58,7 @@ struct freedv *freedv_open(int mode) { struct freedv *f; - int Nc, codec2_mode, nbit, nbyte, i; + int Nc, codec2_mode, nbit, nbyte; if ((mode != FREEDV_MODE_1600) && (mode != FREEDV_MODE_700)) return NULL; @@ -68,6 +68,7 @@ struct freedv *freedv_open(int mode) { return NULL; f->mode = mode; + f->test_frames = 0; if (mode == FREEDV_MODE_1600) { Nc = 16; @@ -107,6 +108,10 @@ struct freedv *freedv_open(int mode) { return NULL; } + f->test_frame_sync_state = 0; + f->total_bits = 0; + f->total_bit_errors = 0; + f->codec2 = codec2_create(codec2_mode); if (f->codec2 == NULL) return NULL; @@ -284,6 +289,14 @@ void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]) { } f->tx_bits[i] = 0; /* spare bit */ + /* optionally overwrite with test frames */ + + if (f->test_frames) { + fdmdv_get_test_bits(f->fdmdv, f->tx_bits); + fdmdv_get_test_bits(f->fdmdv, &f->tx_bits[bits_per_modem_frame]); + //fprintf(stderr, "test frames on tx\n"); + } + /* modulate even and odd frames */ fdmdv_mod(f->fdmdv, tx_fdm, f->tx_bits, &f->tx_sync_bit); @@ -344,6 +357,12 @@ void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]) { } + /* optionally ovwerwrite the codec bits with test frames */ + + if (f->test_frames) { + cohpsk_get_test_bits(f->cohpsk, f->codec_bits); + } + /* cohpsk modulator */ cohpsk_mod(f->cohpsk, tx_fdm, f->codec_bits); @@ -435,7 +454,7 @@ int freedv_floatrx(struct freedv *f, short speech_out[], float demod_in[]) { int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { assert(f != NULL); int bits_per_codec_frame, bytes_per_codec_frame, bits_per_fdmdv_frame; - int sync, i, j, bit, byte, nin_prev, nout, k; + int i, j, bit, byte, nin_prev, nout, k; int recd_codeword, codeword1, data_flag_index, n_ascii; short abit[1]; char ascii_out; @@ -467,7 +486,7 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { else { memcpy(&f->rx_bits[bits_per_fdmdv_frame], f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int)); - if (f->mode == FREEDV_MODE_1600) { + if (f->test_frames == 0) { recd_codeword = 0; for(i=0; i<8; i++) { recd_codeword <<= 1; @@ -496,41 +515,69 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { for(i=8,j=11; i<12; i++,j++) { f->codec_bits[j] = (codeword1 >> (22-i)) & 0x1; } - } + + // extract txt msg data bit ------------------------------------------------------------ - // extract txt msg data bit ------------------------------------------------------------ + data_flag_index = codec2_get_spare_bit_index(f->codec2); + abit[0] = f->codec_bits[data_flag_index]; - data_flag_index = codec2_get_spare_bit_index(f->codec2); - abit[0] = f->codec_bits[data_flag_index]; + n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, abit, 1, 1); + if (n_ascii && (f->freedv_put_next_rx_char != NULL)) { + (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out); + } - n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, abit, 1, 1); - if (n_ascii && (f->freedv_put_next_rx_char != NULL)) { - (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out); + // reconstruct missing bit we steal for data bit and decode speech + + codec2_rebuild_spare_bit(f->codec2, f->codec_bits); + + // pack bits, MSB received first + + bit = 7; + byte = 0; + memset(f->packed_codec_bits, 0, bytes_per_codec_frame); + for(i=0; ipacked_codec_bits[byte] |= (f->codec_bits[i] << bit); + bit--; + if(bit < 0) { + bit = 7; + byte++; + } + } + + codec2_decode(f->codec2, speech_out, f->packed_codec_bits); } + else { + int test_frame_sync, bit_errors, ntest_bits, k; + short error_pattern[fdmdv_error_pattern_size(f->fdmdv)]; - // reconstruct missing bit we steal for data bit and decode speech + for(k=0; k<2; k++) { + /* test frames, so lets sync up to the test frames and count any errors */ + fdmdv_put_test_bits(f->fdmdv, &test_frame_sync, error_pattern, &bit_errors, &ntest_bits, &f->rx_bits[k*bits_per_fdmdv_frame]); - codec2_rebuild_spare_bit(f->codec2, f->codec_bits); + if (test_frame_sync == 1) { + f->test_frame_sync_state = 1; + f->test_frame_count = 0; + } - // pack bits, MSB received first + if (f->test_frame_sync_state) { + if (f->test_frame_count == 0) { + f->total_bit_errors += bit_errors; + f->total_bits += ntest_bits; + } + f->test_frame_count++; + if (f->test_frame_count == 4) + f->test_frame_count = 0; + } - bit = 7; - byte = 0; - memset(f->packed_codec_bits, 0, bytes_per_codec_frame); - for(i=0; ipacked_codec_bits[byte] |= (f->codec_bits[i] << bit); - bit--; - if(bit < 0) { - bit = 7; - byte++; + //fprintf(stderr, "test_frame_sync: %d test_frame_sync_state: %d bit_errors: %d ntest_bits: %d\n", + // test_frame_sync, f->test_frame_sync_state, bit_errors, ntest_bits); } } - codec2_decode(f->codec2, speech_out, f->packed_codec_bits); - /* squelch if beneath SNR threshold */ + /* squelch if beneath SNR threshold or test frames enabled */ - if (f->stats.snr_est < f->snr_thresh) { + if ((f->stats.snr_est < f->snr_thresh) || f->test_frames) { for(i=0; in_speech_samples; i++) speech_out[i] = 0; } @@ -561,40 +608,58 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { if (sync) { - data_flag_index = codec2_get_spare_bit_index(f->codec2); + if (f->test_frames == 0) { + data_flag_index = codec2_get_spare_bit_index(f->codec2); - for (j=0; jvaricode_dec_states, &ascii_out, abit, 1, 1); - if (n_ascii && (f->freedv_put_next_rx_char != NULL)) { - (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out); + n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, abit, 1, 1); + if (n_ascii && (f->freedv_put_next_rx_char != NULL)) { + (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out); + } } - } - /* pack bits, MSB received first */ + /* pack bits, MSB received first */ - bit = 7; byte = 0; - memset(f->packed_codec_bits, 0, bytes_per_codec_frame); - for(i=0; ipacked_codec_bits[byte] |= ((rx_bits[j+i] < 0.0) << bit); - bit--; - if (bit < 0) { - bit = 7; - byte++; + bit = 7; byte = 0; + memset(f->packed_codec_bits, 0, bytes_per_codec_frame); + for(i=0; ipacked_codec_bits[byte] |= ((rx_bits[j+i] < 0.0) << bit); + bit--; + if (bit < 0) { + bit = 7; + byte++; + } } + + codec2_decode(f->codec2, speech_out, f->packed_codec_bits); + speech_out += codec2_samples_per_frame(f->codec2); } + nout = f->n_speech_samples; + } + else { + short error_pattern[COHPSK_BITS_PER_FRAME]; + int bit_errors; + + /* test data, lets see if we can sync to the test data sequence */ - codec2_decode(f->codec2, speech_out, f->packed_codec_bits); - speech_out += codec2_samples_per_frame(f->codec2); + cohpsk_put_test_bits(f->cohpsk, &f->test_frame_sync_state, error_pattern, &bit_errors, rx_bits); + if (f->test_frame_sync_state == 1) { + //for(i=0; itotal_bit_errors += bit_errors; + f->total_bits += COHPSK_BITS_PER_FRAME; + } } - nout = f->n_speech_samples; + } - else { + + if ((sync == 0) || f->test_frames) { float t,a,b,s; int t1,t2; @@ -612,59 +677,8 @@ int freedv_comprx(struct freedv *f, short speech_out[], COMP demod_in[]) { nout = f->n_speech_samples; //fprintf(stderr, "%d %d %d\n", f->n_speech_samples, speech_out[0], speech_out[nin_prev-1]); } - } - + } + return nout; } - -#ifdef TODO - if (g_testFrames) { - int bit_errors, ntest_bits, test_frame_sync; - - // test frame processing, g_test_frame_sync will be asserted when we detect a - // valid test frame. - - fdmdv_put_test_bits(g_pFDMDV, &test_frame_sync, g_error_pattern, &bit_errors, &ntest_bits, codec_bits); - - if (test_frame_sync == 1) { - g_test_frame_sync_state = 1; - g_test_frame_count = 0; - } - - if (g_test_frame_sync_state) { - if (g_test_frame_count == 0) { - //printf("bit_errors: %d ntest_bits: %d\n", bit_errors, ntest_bits); - g_total_bit_errors += bit_errors; - g_total_bits += ntest_bits; - fifo_write(g_errorFifo, g_error_pattern, g_sz_error_pattern); - } - g_test_frame_count++; - if (g_test_frame_count == 4) - g_test_frame_count = 0; - } - - fdmdv_put_test_bits(g_pFDMDV, &test_frame_sync, g_error_pattern, &bit_errors, &ntest_bits, &codec_bits[bits_per_fdmdv_frame]); - - if (test_frame_sync == 1) { - g_test_frame_sync_state = 1; - g_test_frame_count = 0; - } - - if (g_test_frame_sync_state) { - if (g_test_frame_count == 0) { - //printf("bit_errors: %d ntest_bits: %d\n", bit_errors, ntest_bits); - g_total_bit_errors += bit_errors; - g_total_bits += ntest_bits; - fifo_write(g_errorFifo, g_error_pattern, g_sz_error_pattern); - } - g_test_frame_count++; - if (g_test_frame_count == 4) - g_test_frame_count = 0; - } - - // silent audio - - for(i=0; i<2*N8; i++) - output_buf[i] = 0; -#endif diff --git a/codec2-dev/src/freedv_api.h b/codec2-dev/src/freedv_api.h index 70463ea5..d4aa1875 100644 --- a/codec2-dev/src/freedv_api.h +++ b/codec2-dev/src/freedv_api.h @@ -62,6 +62,14 @@ struct freedv { int *fdmdv_bits; int *rx_bits; int tx_sync_bit; + + int *ptest_bits_coh; + int *ptest_bits_coh_end; + + int test_frames; // set this baby for 1 to tx/rx test frames to look at bit error stats + int test_frame_sync_state; + int test_frame_count; + int total_bits; int total_bit_errors; int sync; diff --git a/codec2-dev/src/freedv_rx.c b/codec2-dev/src/freedv_rx.c index 285b619e..ffc499b6 100644 --- a/codec2-dev/src/freedv_rx.c +++ b/codec2-dev/src/freedv_rx.c @@ -42,7 +42,7 @@ struct my_callback_state { void my_put_next_rx_char(void *callback_state, char c) { struct my_callback_state* pstate = (struct my_callback_state*)callback_state; if (pstate->ftxt != NULL) { - fprintf(stderr, "%c", c); + fprintf(pstate->ftxt, "%c", c); } } @@ -51,12 +51,12 @@ int main(int argc, char *argv[]) { short *speech_out; short *demod_in; struct freedv *freedv; - int nin, nout, frame; + int nin, nout, frame = 0; struct my_callback_state my_cb_state; int mode; if (argc < 4) { - printf("usage: %s 1600|700 InputModemSpeechFile OutputSpeechawFile txtLogFile\n", argv[0]); + printf("usage: %s 1600|700 InputModemSpeechFile OutputSpeechRawFile [--test_frames]\n", argv[0]); printf("e.g %s 1600 hts1a_fdmdv.raw hts1a_out.raw txtLogFile\n", argv[0]); exit(1); } @@ -82,24 +82,21 @@ int main(int argc, char *argv[]) { exit(1); } - ftxt = NULL; - if ( (argc > 4) && (strcmp(argv[4],"|") != 0) ) { - if ((ftxt = fopen(argv[4],"wt")) == NULL ) { - fprintf(stderr, "Error opening txt Log File: %s: %s.\n", - argv[4], strerror(errno)); - exit(1); - } - } - freedv = freedv_open(mode); - cohpsk_set_verbose(freedv->cohpsk, 1); + if (mode == FREEDV_MODE_700) + cohpsk_set_verbose(freedv->cohpsk, 1); assert(freedv != NULL); + if ( (argc > 4) && (strcmp(argv[4], "--testframes") == 0) ) { + freedv->test_frames = 1; + } + speech_out = (short*)malloc(sizeof(short)*freedv->n_speech_samples); assert(speech_out != NULL); demod_in = (short*)malloc(sizeof(short)*freedv->n_max_modem_samples); assert(demod_in != NULL); + ftxt = stderr; my_cb_state.ftxt = ftxt; freedv->callback_state = (void*)&my_cb_state; freedv->freedv_put_next_rx_char = &my_put_next_rx_char; @@ -117,13 +114,20 @@ int main(int argc, char *argv[]) { fwrite(speech_out, sizeof(short), nout, fout); nin = freedv_nin(freedv); + if (freedv->mode == FREEDV_MODE_1600) + fdmdv_get_demod_stats(freedv->fdmdv, &freedv->stats); + if (freedv->mode == FREEDV_MODE_700) + cohpsk_get_demod_stats(freedv->cohpsk, &freedv->stats); + /* log some side info to the txt file */ frame++; + /* if (ftxt != NULL) { fprintf(ftxt, "frame: %d demod sync: %d demod snr: %3.2f dB bit errors: %d\n", frame, freedv->stats.sync, freedv->stats.snr_est, freedv->total_bit_errors); } + */ /* if this is in a pipeline, we probably don't want the usual buffering to occur */ @@ -132,6 +136,10 @@ int main(int argc, char *argv[]) { if (fin == stdin) fflush(stdin); } + if (freedv->test_frames) { + fprintf(stderr, "bits: %d errors: %d BER: %3.2f\n", freedv->total_bits, freedv->total_bit_errors, (float)freedv->total_bit_errors/freedv->total_bits); + } + free(speech_out); free(demod_in); freedv_close(freedv); diff --git a/codec2-dev/src/freedv_tx.c b/codec2-dev/src/freedv_tx.c index c13303c7..80e4c479 100644 --- a/codec2-dev/src/freedv_tx.c +++ b/codec2-dev/src/freedv_tx.c @@ -58,7 +58,7 @@ int main(int argc, char *argv[]) { int mode; if (argc < 4) { - printf("usage: %s 1600|700 InputRawSpeechFile OutputModemRawFile\n", argv[0]); + printf("usage: %s 1600|700 InputRawSpeechFile OutputModemRawFile [--testframes]\n", argv[0]); printf("e.g %s 1600 hts1a.raw hts1a_fdmdv.raw\n", argv[0]); exit(1); } @@ -87,6 +87,10 @@ int main(int argc, char *argv[]) { freedv = freedv_open(mode); assert(freedv != NULL); + if ((argc > 4) && (strcmp(argv[4], "--testframes") == 0)) { + freedv->test_frames = 1; + } + speech_in = (short*)malloc(sizeof(short)*freedv->n_speech_samples); assert(speech_in != NULL); mod_out = (short*)malloc(sizeof(short)*freedv->n_nom_modem_samples); -- 2.25.1