freedv tx side working with test frames with interleaving
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 29 Apr 2018 05:27:43 +0000 (05:27 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 29 Apr 2018 05:27:43 +0000 (05:27 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@3534 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/src/freedv_api.c
codec2-dev/src/freedv_api.h
codec2-dev/src/freedv_api_internal.h
codec2-dev/src/freedv_tx.c
codec2-dev/src/interldpc.c
codec2-dev/src/ofdm_demod.c
codec2-dev/src/ofdm_mod.c

index f87860c5d49df9e45981642098c019ac7da3673d..68f6afc1441af347374ab693c39293e101035bb8 100644 (file)
@@ -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; i<f->interleave_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; j<bits_per_modem_frame; j+=bits_per_codec_frame) {
+    for (j=0; j<bits_per_interleaved_frame; j+=bits_per_codec_frame) {
 
         /* unpack bits, MSB first */
 
@@ -919,14 +952,12 @@ static void freedv_comptx_700d(struct freedv *f, COMP mod_out[]) {
 
     /* OK now ready to LDPC encode, interleave, and OFDM modulate */
     
-    complex float tx_sams[f->interleave_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; i<f->n_nat_modem_samples; i++) {
+    for(i=0; i<f->interleave_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; j<codec_frames; j++) {
             codec2_encode(f->codec2, 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; j<codec_frames; j++) {
+            codec2_encode(f->codec2, 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; i<f->n_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)){
index ed4ef702c7f595690b3d053689b67455a4b4bb98..e08f88cf9ce9f66fb00b4f781b8a1cc40c8b315a 100644 (file)
 
 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 -------------------------------------------------------------------
index 76bfbea6b992df6242350d683dd840ab0e0ae917..cd8d5f84ff186165b4e958f2bfc83580650bd67b 100644 (file)
@@ -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 */
index 89dbf69a734b8e2aea26f556cae5b7f85ade3e60..ee731d21d1eed9aad4fff499447223cd7346e0cf 100644 (file)
@@ -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");
index 09bd15e494b57b1dfba4046130e14c08df550a46..eb1c9d1c9330e4ee126a1f7a707e56c6b82a7e4b 100644 (file)
@@ -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<interleave_frames; j++) {            
         for(i=0; i<coded_syms_per_frame; i++) {
-            /* todo: we don't need to build modulated UW every tinme, just txt bits */
+            /* todo: we don't need to build modulated UW every time, just txt bits */
             build_modulated_uw(ofdm, tx_symbols, &txt_bits[OFDM_NTXTBITS*j]);
             tx_symbols[(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS+i] = coded_symbols_inter[j*coded_syms_per_frame+i].real
                 + I * coded_symbols_inter[j*coded_syms_per_frame+i].imag;
index bcf0fcff01d29719ead32ff62014b4657c5edf49..c5e268897af0da680e548226ce8bbddf113a8841 100644 (file)
@@ -93,7 +93,7 @@ int main(int argc, char *argv[])
         fprintf(stderr, "\n");
         fprintf(stderr, "                Default output file format is one byte per bit hard decision\n");
         fprintf(stderr, "  --llr         LLR output, one double per bit, %d doubles/frame\n", coded_bits_per_frame);
-        fprintf(stderr, "  -t            Receive test frames and count errors\n");
+        fprintf(stderr, "  --testframes  Receive test frames and count errors\n");
         fprintf(stderr, "  --ldpc        Run (%d,%d) LDPC decoder.  This forces 112, one char/bit output values\n"
                         "                per frame.  In testframe mode (-t) raw and coded errors will be counted\n",
                                          coded_bits_per_frame, data_bits_per_frame);
@@ -136,7 +136,7 @@ int main(int argc, char *argv[])
     }
 
     testframes = 0;
-    if (opt_exists(argv, argc, "-t")) {
+    if (opt_exists(argv, argc, "--testframes")) {
         testframes = 1;
     }
 
index 582a406acd0bbc6a752733e6c33bbc4064a3f577..adc265e1ccdf0fec68f9d325610517c426065cf0 100644 (file)
@@ -70,11 +70,11 @@ int main(int argc, char *argv[])
     if (argc < 3) {
         fprintf(stderr, "\n");
        fprintf(stderr, "usage: %s InputOneCharPerBitFile OutputModemRawFile [--lpdc] [--interleaver depth]\n\n", argv[0]);
-        fprintf(stderr, "  -t Nsecs      Transmit test frames (adjusts test frames for raw and LDPC modes)\n");
-        fprintf(stderr, "  --ldpc        Run (%d,%d) LDPC decoder.  This forces 112, one char/bit output values\n"
-                        "                per frame.  In testframe mode (-t) raw and coded errors will be counted\n",
-                                         coded_bits_per_frame, data_bits_per_frame);
-        fprintf(stderr, "  --interleave  Interleave depth for LDPC frames, e.g. 1,2,4,8,16, default is 1\n");
+        fprintf(stderr, "  --testframe Nsecs   Transmit test frames (adjusts test frames for raw and LDPC modes)\n");
+        fprintf(stderr, "  --ldpc              Run (%d,%d) LDPC decoder.  This forces 112, one char/bit output values\n"
+                        "                      per frame.  In testframe mode (-t) raw and coded errors will be counted\n",
+                                               coded_bits_per_frame, data_bits_per_frame);
+        fprintf(stderr, "  --interleave depth  Interleave depth for LDPC frames, e.g. 1,2,4,8,16, default is 1\n");
         fprintf(stderr, "\n");
        exit(1);
     }