From b88567eed63273a2cd58301eaf0583ad2ddbd40e Mon Sep 17 00:00:00 2001 From: drowe67 Date: Sun, 29 Apr 2018 05:27:43 +0000 Subject: [PATCH] freedv tx side working with test frames with interleaving git-svn-id: https://svn.code.sf.net/p/freetel/code@3534 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/src/freedv_api.c | 131 +++++++++++++++++++-------- codec2-dev/src/freedv_api.h | 7 ++ codec2-dev/src/freedv_api_internal.h | 3 + codec2-dev/src/freedv_tx.c | 41 ++++++--- codec2-dev/src/interldpc.c | 2 +- codec2-dev/src/ofdm_demod.c | 4 +- codec2-dev/src/ofdm_mod.c | 10 +- 7 files changed, 140 insertions(+), 58 deletions(-) diff --git a/codec2-dev/src/freedv_api.c b/codec2-dev/src/freedv_api.c index f87860c5..68f6afc1 100644 --- a/codec2-dev/src/freedv_api.c +++ b/codec2-dev/src/freedv_api.c @@ -90,6 +90,10 @@ extern int payload_data_bits[]; \*---------------------------------------------------------------------------*/ struct freedv *freedv_open(int mode) { + return freedv_open_advanced(mode, NULL); +} + +struct freedv *freedv_open_advanced(int mode, struct freedv_advanced *adv) { struct freedv *f; int Nc, codec2_mode, nbit, nbyte,i; @@ -188,7 +192,14 @@ struct freedv *freedv_open(int mode) { set_up_hra_112_112(f->ldpc); int coded_syms_per_frame = f->ldpc->coded_syms_per_frame; - f->interleave_frames = 1; + if (adv == NULL) { + f->interleave_frames = 1; + } else { + assert((adv->interleave_frames >= 0) && (adv->interleave_frames < 32)); + f->interleave_frames = adv->interleave_frames; + } + f->modem_frame_count_tx = 0; + f->codeword_symbols = (COMP*)malloc(sizeof(COMP)*f->interleave_frames*coded_syms_per_frame); if (f->codeword_symbols == NULL) {return NULL;} f->codeword_amps = (float*)malloc(sizeof(float)*f->interleave_frames*coded_syms_per_frame); @@ -206,10 +217,15 @@ struct freedv *freedv_open(int mode) { f->modem_sample_rate = OFDM_FS; f->clip = 0; nbit = OFDM_BITSPERFRAME; - f->tx_bits = (int*)malloc(nbit*sizeof(int)); - if (f->tx_bits == NULL) - return NULL; + f->tx_bits = NULL; /* not used for 700D */ f->sz_error_pattern = OFDM_BITSPERFRAME; /* uncoded errors */ + + f->mod_out = (COMP*)malloc(sizeof(COMP)*f->interleave_frames*f->n_nat_modem_samples); + if (f->mod_out == NULL) { return NULL; } + for (i=0; iinterleave_frames*f->n_nat_modem_samples; i++) { + f->mod_out[i].real = 0.0; + f->mod_out[i].imag = 0.0; + } } #endif @@ -347,23 +363,25 @@ struct freedv *freedv_open(int mode) { assert((f->ldpc->data_bits_per_frame % codec2_bits_per_frame(f->codec2)) == 0); - int Ncodec2frames = f->ldpc->data_bits_per_frame*f->interleave_frames/codec2_bits_per_frame(f->codec2); + int Ncodec2frames = f->ldpc->data_bits_per_frame/codec2_bits_per_frame(f->codec2); f->n_speech_samples = Ncodec2frames*codec2_samples_per_frame(f->codec2); - f->n_codec_bits = Ncodec2frames*codec2_bits_per_frame(f->codec2); - nbit = f->n_codec_bits; + f->n_codec_bits = f->interleave_frames*Ncodec2frames*codec2_bits_per_frame(f->codec2); + nbit = codec2_bits_per_frame(f->codec2); nbyte = (nbit + 7) / 8; - //fprintf(stderr, "Ncodec2frames: %d nbit: %d nbyte: %d A\n", Ncodec2frames, nbit, nbyte); + nbyte = nbyte*Ncodec2frames*f->interleave_frames; + fprintf(stderr, "Ncodec2frames: %d n_speech_samples: %d n_codec_bits: %d nbit: %d nbyte: %d\n", + Ncodec2frames, f->n_speech_samples, f->n_codec_bits, nbit, nbyte); } f->packed_codec_bits = (unsigned char*)malloc(nbyte*sizeof(char)); if (mode == FREEDV_MODE_1600) f->codec_bits = (int*)malloc(nbit*sizeof(int)); - if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B) || (mode == FREEDV_MODE_700C) || (mode == FREEDV_MODE_700D)) + if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B) || (mode == FREEDV_MODE_700C)) f->codec_bits = (int*)malloc(COHPSK_BITS_PER_FRAME*sizeof(int)); /* Note: VHF Framer/deframer goes directly from packed codec/vc/proto bits to filled frame */ - if ((f->packed_codec_bits == NULL) || (f->codec_bits == NULL)) + if (f->packed_codec_bits == NULL) return NULL; /* Sample rate conversion for modes using COHPSK */ @@ -415,6 +433,7 @@ void freedv_close(struct freedv *freedv) { if ((freedv->mode == FREEDV_MODE_700) || (freedv->mode == FREEDV_MODE_700B) || (freedv->mode == FREEDV_MODE_700C)) cohpsk_destroy(freedv->cohpsk); if (freedv->mode == FREEDV_MODE_700D) { + free(freedv->mod_out); free(freedv->codeword_symbols); free(freedv->codeword_amps); free(freedv->ldpc); @@ -848,26 +867,40 @@ static void freedv_comptx_700(struct freedv *f, COMP mod_out[]) { } /* - TODO: Configure to input/output one modem frame for each call, even - when interleaved. This means we'll need to buffer coded bits, - then buffer tx modem signal. Start with single frame, get that - working first. + Ok so when interleaved, we take the interleaver length of input samples, + and output that many modem samples, e.g. for interleaver of length 4: + + record input speech 1234 + freedv tx | + play modem sig 1234 + record modem sig 1234 + freedv_rx | + play output speech 1234 + time axis --------->123456789012----> + + So a sample of input speech at time 1 is ouput at time 9. We assume + the freedv_tx and freedv_rx and propogation time over channel (from + when a modem signal is played at the HF tx to when it is recorded at + the HF rx) is zero. + + The freedv tx interface ouputs n_nom_modem_samples, which a single + OFDM modem frame, 112 payload bits or 4 speech codec frames. So + this function must always have 1280 speech samples as input, and + 1280 modem samples as output, regradless of interleaver_frames. For + interleaver_frames > 1, we need to buffer samples. */ static void freedv_comptx_700d(struct freedv *f, COMP mod_out[]) { int bit, byte, i, j, k; - int bits_per_codec_frame, bits_per_modem_frame; int nspare; int data_bits_per_frame = f->ldpc->data_bits_per_frame; - - bits_per_modem_frame = f->interleave_frames*data_bits_per_frame; - uint8_t tx_bits[bits_per_modem_frame]; - - bits_per_codec_frame = codec2_bits_per_frame(f->codec2); + int bits_per_interleaved_frame = f->interleave_frames*data_bits_per_frame; + uint8_t tx_bits[bits_per_interleaved_frame]; + int bits_per_codec_frame = codec2_bits_per_frame(f->codec2); byte = 0; - for (j=0; jinterleave_frames*ofdm_get_samples_per_frame()]; + complex float tx_sams[f->interleave_frames*f->n_nat_modem_samples]; COMP asam; ofdm_ldpc_interleave_tx(f->ofdm, f->ldpc, tx_sams, tx_bits, txt_bits, f->interleave_frames); - assert(f->n_nat_modem_samples == f->interleave_frames*ofdm_get_samples_per_frame()); - - for(i=0; in_nat_modem_samples; i++) { + for(i=0; iinterleave_frames*f->n_nat_modem_samples; i++) { asam.real = crealf(tx_sams[i]); asam.imag = cimagf(tx_sams[i]); mod_out[i] = fcmult(OFDM_AMP_SCALE*NORM_PWR_OFDM, asam); @@ -940,10 +971,6 @@ static void freedv_comptx_700d(struct freedv *f, COMP mod_out[]) { void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]) { assert(f != NULL); -#ifndef CORTEX_M4 - int j; - int bits_per_codec_frame; -#endif assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C) || @@ -957,24 +984,54 @@ void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]) { #ifndef CORTEX_M4 + int bits_per_codec_frame = codec2_bits_per_frame(f->codec2); + int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; + int i,j; + /* all these modes need to pack a bunch of codec frames into one modem frame */ - if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C) - || (f->mode == FREEDV_MODE_700D)) { - bits_per_codec_frame = codec2_bits_per_frame(f->codec2); - int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; + if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) { int codec_frames = f->n_codec_bits / bits_per_codec_frame; for (j=0; jcodec2, f->packed_codec_bits + j * bytes_per_codec_frame, speech_in); speech_in += codec2_samples_per_frame(f->codec2); } - if (f->mode == FREEDV_MODE_700D) { - freedv_comptx_700d(f, mod_out); - } else { - freedv_comptx_700(f, mod_out); + freedv_comptx_700(f, mod_out); + } + + /* special treatment due to interleaver */ + + if (f->mode == FREEDV_MODE_700D) { + int data_bits_per_frame = f->ldpc->data_bits_per_frame; + int codec_frames = data_bits_per_frame / bits_per_codec_frame; + + fprintf(stderr, "modem_frame_count_tx: %d dec_frames: %d bytes offset: %d\n", + f->modem_frame_count_tx, codec_frames, (f->modem_frame_count_tx*codec_frames)*bytes_per_codec_frame); + + /* buffer up bits until we get enough encoded bits for interleaver */ + + for (j=0; jcodec2, f->packed_codec_bits + (f->modem_frame_count_tx*codec_frames+j)*bytes_per_codec_frame, speech_in); + speech_in += codec2_samples_per_frame(f->codec2); + } + + /* call modulate function when we have enough frames to run interleaver */ + + assert((f->modem_frame_count_tx >= 0) && (f->modem_frame_count_tx < f->interleave_frames)); + f->modem_frame_count_tx++; + if (f->modem_frame_count_tx == f->interleave_frames) { + freedv_comptx_700d(f, f->mod_out); + fprintf(stderr, " calling freedv_comptx_700d()\n"); + f->modem_frame_count_tx = 0; + } + + /* output n_nom_modem_samples at a time from modulated buffer */ + for(i=0; in_nat_modem_samples; i++) { + mod_out[i] = f->mod_out[f->modem_frame_count_tx*f->n_nat_modem_samples+i]; } } + #endif /* 2400 A and B are handled by the real-mode TX */ if((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B)){ diff --git a/codec2-dev/src/freedv_api.h b/codec2-dev/src/freedv_api.h index ed4ef702..e08f88cf 100644 --- a/codec2-dev/src/freedv_api.h +++ b/codec2-dev/src/freedv_api.h @@ -49,6 +49,12 @@ struct freedv; +/* advanced freedv open options rqd by some modes */ + +struct freedv_advanced { + int interleave_frames; +}; + /* Called when text message char is decoded */ typedef void (*freedv_callback_rx)(void *, char); /* Called when new text message char is needed */ @@ -78,6 +84,7 @@ typedef void (*freedv_callback_datatx)(void *, unsigned char *packet, size_t *si // open, close ---------------------------------------------------------------- struct freedv *freedv_open(int mode); +struct freedv *freedv_open_advanced(int mode, struct freedv_advanced *adv); void freedv_close (struct freedv *freedv); // Transmit ------------------------------------------------------------------- diff --git a/codec2-dev/src/freedv_api_internal.h b/codec2-dev/src/freedv_api_internal.h index 76bfbea6..cd8d5f84 100644 --- a/codec2-dev/src/freedv_api_internal.h +++ b/codec2-dev/src/freedv_api_internal.h @@ -78,6 +78,7 @@ struct freedv { struct quisk_cfFilter * ptFilter8000to7500; int n_speech_samples; // number of speech samples we need for each freedv_tx() call + // num of speech samples output by freedv_rx() call int n_nom_modem_samples; // size of tx and most rx modem sample buffers int n_max_modem_samples; // make your rx modem sample buffers this big int n_nat_modem_samples; // tx modem sample block length as used by the modem before interpolation to output @@ -135,6 +136,8 @@ struct freedv { int interleave_frames; // number of OFDM modem frames in interleaver, e.g. 1,2,4,8,16 COMP *codeword_symbols; float *codeword_amps; + int modem_frame_count_tx; // counter for tx side + COMP *mod_out; // output buffer of intereaved frames /* user defined function ptrs to produce and consume ASCII characters using aux txt channel */ diff --git a/codec2-dev/src/freedv_tx.c b/codec2-dev/src/freedv_tx.c index 89dbf69a..ee731d21 100644 --- a/codec2-dev/src/freedv_tx.c +++ b/codec2-dev/src/freedv_tx.c @@ -92,13 +92,13 @@ int main(int argc, char *argv[]) { int mode; int n_speech_samples; int n_nom_modem_samples; - int use_codectx; - int use_datatx; + int use_codectx, use_datatx, use_testframes, interleave_frames; struct CODEC2 *c2; int i; if (argc < 4) { - printf("usage: %s 1600|700|700B|700C|700D|2400A|2400B|800XA InputRawSpeechFile OutputModemRawFile [--testframes] [--codectx] [--datatx]\n", argv[0]); + printf("usage: %s 1600|700|700B|700C|700D|2400A|2400B|800XA InputRawSpeechFile OutputModemRawFile\n" + " [--testframes] [--interleave depth] [--codectx] [--datatx]\n", argv[0]); printf("e.g %s 1600 hts1a.raw hts1a_fdmdv.raw\n", argv[0]); exit(1); } @@ -135,16 +135,12 @@ int main(int argc, char *argv[]) { exit(1); } - freedv = freedv_open(mode); - assert(freedv != NULL); - - use_codectx = 0; - use_datatx = 0; - + use_codectx = 0; use_datatx = 0; use_testframes = 0; interleave_frames = 1; + if (argc > 4) { for (i = 4; i < argc; i++) { if (strcmp(argv[i], "--testframes") == 0) { - freedv_set_test_frames(freedv, 1); + use_testframes = 1; } if (strcmp(argv[i], "--codectx") == 0) { int c2_mode; @@ -161,12 +157,30 @@ int main(int argc, char *argv[]) { assert(c2 != NULL); } if (strcmp(argv[i], "--datatx") == 0) { - unsigned char header[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc }; - freedv_set_data_header(freedv, header); use_datatx = 1; } + if (strcmp(argv[i], "--interleave") == 0) { + interleave_frames = atoi(argv[i+1]); + } } } + + if (mode == FREEDV_MODE_700D) { + struct freedv_advanced adv; + adv.interleave_frames = interleave_frames; + freedv = freedv_open_advanced(mode, &adv); + } + else { + freedv = freedv_open(mode); + } + assert(freedv != NULL); + + if (use_datatx) { + unsigned char header[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc }; + freedv_set_data_header(freedv, header); + } + freedv_set_test_frames(freedv, use_testframes); + freedv_set_snr_squelch_thresh(freedv, -100.0); freedv_set_squelch_en(freedv, 1); @@ -176,7 +190,8 @@ int main(int argc, char *argv[]) { assert(speech_in != NULL); mod_out = (short*)malloc(sizeof(short)*n_nom_modem_samples); assert(mod_out != NULL); - + fprintf(stderr, "n_speech_samples: %d n_nom_modem_samples: %d\n", n_speech_samples, n_nom_modem_samples); + /* set up callback for txt msg chars */ sprintf(my_cb_state.tx_str, "cq cq cq hello world\r"); diff --git a/codec2-dev/src/interldpc.c b/codec2-dev/src/interldpc.c index 09bd15e4..eb1c9d1c 100644 --- a/codec2-dev/src/interldpc.c +++ b/codec2-dev/src/interldpc.c @@ -218,7 +218,7 @@ void ofdm_ldpc_interleave_tx(struct OFDM *ofdm, struct LDPC *ldpc, complex float gp_interleave_comp(coded_symbols_inter, coded_symbols, interleave_frames*coded_syms_per_frame); for (j=0; j