Commiting back changes made during flexradio update
authorbaobrien <baobrien@01035d8c-6547-0410-b346-abe4f91aad63>
Sat, 2 Dec 2017 06:33:09 +0000 (06:33 +0000)
committerbaobrien <baobrien@01035d8c-6547-0410-b346-abe4f91aad63>
Sat, 2 Dec 2017 06:33:09 +0000 (06:33 +0000)
-made freedv_comptx actually produce complex samples for 2400A
-added support for 24k sample rate changing to freedv api for 2400A
-added optional 'simple' freq. est. mode to cohpsk
-made some things in cohpsk faster

git-svn-id: https://svn.code.sf.net/p/freetel/code@3383 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/src/codec2_cohpsk.h
codec2-dev/src/cohpsk.c
codec2-dev/src/cohpsk_internal.h
codec2-dev/src/freedv_api.c
codec2-dev/src/fsk.c

index a0ad488cd15972a4baf24e8564b31d5124b78d7d..a7c9b4f01adf0f678077e1b3285b8caa1aac68ea 100644 (file)
@@ -59,6 +59,8 @@ void cohpsk_set_frame(struct COHPSK *coh, int frame);
 void fdmdv_freq_shift_coh(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, float Fs,
                           COMP *foff_phase_rect, int nin);
 
+void cohpsk_set_freq_est_mode(struct COHPSK *coh, int used_simple_mode);
+
 /* used for accessing upper and lower bits before diversity combination */
 
 float *cohpsk_get_rx_bits_lower(struct COHPSK *coh);
index 303db04545db371eb08966edb430f6b3ba01064d..8269157dc047773b8a7acf5d9c4cfd60b18aaecc 100644 (file)
@@ -57,7 +57,7 @@ static COMP qpsk_mod[] = {
 
 static int sampling_points[] = {0, 1, 6, 7};
 
-void corr_with_pilots(float *corr_out, float *mag_out, struct COHPSK *coh, int t, float f_fine);
+void corr_with_pilots_comp(float *corr_out, float *mag_out, struct COHPSK *coh, int t, COMP f_fine);
 void update_ct_symb_buf(COMP ct_symb_buf[][COHPSK_NC*ND], COMP ch_symb[][COHPSK_NC*ND]);
 
 /*---------------------------------------------------------------------------*\
@@ -188,6 +188,9 @@ struct COHPSK *cohpsk_create(void)
     coh->ptest_bits_coh_tx = coh->ptest_bits_coh_rx[0] = coh->ptest_bits_coh_rx[1] = (int*)test_bits_coh;
     coh->ptest_bits_coh_end = (int*)test_bits_coh + sizeof(test_bits_coh)/sizeof(int);
 
+    /* Disable 'reduce' frequency estimation mode */
+    coh->freq_est_mode_reduced = 0;
+
     return coh;
 }
 
@@ -422,7 +425,7 @@ void qpsk_symbols_to_bits(struct COHPSK *coh, float rx_bits[], COMP ct_symb_buf[
 
 \*---------------------------------------------------------------------------*/
 
-void tx_filter_and_upconvert_coh(COMP tx_fdm[], int Nc, COMP tx_symbols[],
+void tx_filter_and_upconvert_coh(COMP tx_fdm[], int Nc,const COMP tx_symbols[],
                                  COMP tx_filter_memory[COHPSK_NC*ND][COHPSK_NSYM],
                                  COMP phase_tx[], COMP freq[],
                                  COMP *fbb_phase, COMP fbb_rect)
@@ -439,12 +442,12 @@ void tx_filter_and_upconvert_coh(COMP tx_fdm[], int Nc, COMP tx_symbols[],
     gain.imag = 0.0;
 
     for(i=0; i<COHPSK_M; i++) {
-       tx_fdm[i].real = 0.0;
-       tx_fdm[i].imag = 0.0;
+               tx_fdm[i].real = 0.0;
+               tx_fdm[i].imag = 0.0;
     }
 
     for(c=0; c<Nc; c++)
-       tx_filter_memory[c][COHPSK_NSYM-1] = cmult(tx_symbols[c], gain);
+       tx_filter_memory[c][COHPSK_NSYM-1] = cmult(tx_symbols[c], gain);
 
     /*
        tx filter each symbol, generate M filtered output samples for
@@ -454,37 +457,30 @@ void tx_filter_and_upconvert_coh(COMP tx_fdm[], int Nc, COMP tx_symbols[],
     */
 
     for(c=0; c<Nc; c++) {
-        for(i=0; i<COHPSK_M; i++) {
-
-           /* filter real sample of symbol for carrier c */
-
-           acc = 0.0;
-           for(j=0,k=COHPSK_M-i-1; j<COHPSK_NSYM; j++,k+=COHPSK_M)
-               acc += COHPSK_M * tx_filter_memory[c][j].real * gt_alpha5_root_coh[k];
-           tx_baseband.real = acc;
 
-           /* filter imag sample of symbol for carrier c */
+               for(i=0; i<COHPSK_M; i++) {
 
-           acc = 0.0;
-           for(j=0,k=COHPSK_M-i-1; j<COHPSK_NSYM; j++,k+=COHPSK_M)
-               acc += COHPSK_M * tx_filter_memory[c][j].imag * gt_alpha5_root_coh[k];
-           tx_baseband.imag = acc;
-            //printf("%d %d %f %f\n", c, i, tx_baseband.real, tx_baseband.imag);
+                       const COMP * tx_filter_memory_cn = &tx_filter_memory[c];
+                       /* filter sample of symbol for carrier c */
+                       tx_baseband.real = 0;
+                       tx_baseband.imag = 0;
+                       for(j=0,k=COHPSK_M-i-1; j<COHPSK_NSYM; j++,k+=COHPSK_M){
+                               tx_baseband = cadd(tx_baseband,fcmult(COHPSK_M,fcmult(gt_alpha5_root_coh[k],tx_filter_memory_cn[j])));
+                       }
 
-            /* freq shift and sum */
+                               /* freq shift and sum */
 
-           phase_tx[c] = cmult(phase_tx[c], freq[c]);
-           tx_fdm[i] = cadd(tx_fdm[i], cmult(tx_baseband, phase_tx[c]));
-            //printf("%d %d %f %f\n", c, i, phase_tx[c].real, phase_tx[c].imag);
-       }
+                       phase_tx[c] = cmult(phase_tx[c], freq[c]);
+                       tx_fdm[i] = cadd(tx_fdm[i], cmult(tx_baseband, phase_tx[c]));
+               }
         //exit(0);
     }
 
     /* shift whole thing up to carrier freq */
 
-    for (i=0; i<COHPSK_M; i++) {
-       *fbb_phase = cmult(*fbb_phase, fbb_rect);
-       tx_fdm[i] = cmult(tx_fdm[i], *fbb_phase);
+       for (i=0; i<COHPSK_M; i++) {
+               *fbb_phase = cmult(*fbb_phase, fbb_rect);
+               tx_fdm[i] = cmult(tx_fdm[i], *fbb_phase);
     }
 
     /*
@@ -515,26 +511,46 @@ void tx_filter_and_upconvert_coh(COMP tx_fdm[], int Nc, COMP tx_symbols[],
        for(c=0; c<Nc; c++)
            tx_filter_memory[c][i] = tx_filter_memory[c][i+1];
 
-    for(c=0; c<Nc; c++) {
-       tx_filter_memory[c][COHPSK_NSYM-1].real = 0.0;
-       tx_filter_memory[c][COHPSK_NSYM-1].imag = 0.0;
+       for(c=0; c<Nc; c++) {
+               tx_filter_memory[c][COHPSK_NSYM-1].real = 0.0;
+               tx_filter_memory[c][COHPSK_NSYM-1].imag = 0.0;
     }
 }
 
-
-
-void corr_with_pilots(float *corr_out, float *mag_out, struct COHPSK *coh, int t, float f_fine)
+void corr_with_pilots_comp(float *corr_out, float *mag_out, struct COHPSK *coh, int t, COMP dp_f_fine)
 {
     COMP  acorr, f_fine_rect, f_corr;
     float mag, corr;
     int   c, p, pc;
 
+    //1,2,7,8
+    f_fine_rect.real = 1;
+    f_fine_rect.imag = 0;
+
+    COMP f_fine_rects[4];
+    //dp_f_fine = comp_exp_j(2*m_pi*f_fine/cohpsk_rs);
+
+    f_fine_rect = cmult(f_fine_rect,dp_f_fine);        //sampling_points[0]+1 = 1
+    f_fine_rects[0] = dp_f_fine;
+    f_fine_rect = cmult(dp_f_fine,dp_f_fine);  //sampling_points[1]+1 = 2
+    f_fine_rects[1] = f_fine_rect;
+    f_fine_rect = cmult(f_fine_rect,dp_f_fine);        //                                     = 2
+    f_fine_rect = cmult(f_fine_rect,dp_f_fine);        //                     = 3
+    f_fine_rect = cmult(f_fine_rect,dp_f_fine);        //                     = 4
+    f_fine_rect = cmult(f_fine_rect,dp_f_fine);        //                     = 5
+    f_fine_rect = cmult(f_fine_rect,dp_f_fine);        //                     = 6
+    f_fine_rect = cmult(f_fine_rect,dp_f_fine);        //sampling_points[2]+1 = 7
+    f_fine_rects[2] = f_fine_rect;
+    f_fine_rect = cmult(f_fine_rect,dp_f_fine);        //sampling_points[2]+1 = 8
+    f_fine_rects[3] = f_fine_rect;
+
     corr = 0.0; mag = 0.0;
     for (c=0; c<COHPSK_NC*ND; c++) {
         acorr.real = 0.0; acorr.imag = 0.0;
         for (p=0; p<NPILOTSFRAME+2; p++) {
-            f_fine_rect.real = cosf(f_fine*2.0*M_PI*(sampling_points[p]+1.0)/COHPSK_RS);
-            f_fine_rect.imag = sinf(f_fine*2.0*M_PI*(sampling_points[p]+1.0)/COHPSK_RS);
+            //f_fine_rect.real = cosf(f_fine*2.0*M_PI*(sampling_points[p]+1.0)/COHPSK_RS);
+            //f_fine_rect.imag = sinf(f_fine*2.0*M_PI*(sampling_points[p]+1.0)/COHPSK_RS);
+               f_fine_rect = f_fine_rects[p];
             f_corr = cmult(f_fine_rect, coh->ct_symb_buf[t+sampling_points[p]][c]);
             pc = c % COHPSK_NC;
             acorr = cadd(acorr, fcmult(coh->pilot2[p][pc], f_corr));
@@ -563,21 +579,37 @@ void corr_with_pilots(float *corr_out, float *mag_out, struct COHPSK *coh, int t
 void frame_sync_fine_freq_est(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC*ND], int sync, int *next_sync)
 {
     int   t;
-    float f_fine, mag, max_corr, max_mag, corr;
+    float f_fine, mag, max_corr, max_mag, corr, delta_f_fine, f_fine_range ;
+    COMP f_fine_d_ph;
+
+       if(coh->freq_est_mode_reduced){
+               delta_f_fine = 1.3;
+               f_fine_range = 10;
+    }else{
+               delta_f_fine = .25;
+               f_fine_range = 20;
+    }
 
-    update_ct_symb_buf(coh->ct_symb_buf, ch_symb);
+       /* Represent f_fine scan as delta2-phase */
+       const COMP f_fine_d2_ph = comp_exp_j(2*M_PI*delta_f_fine/COHPSK_RS);
 
+    f_fine = -f_fine_range;
+
+    update_ct_symb_buf(coh->ct_symb_buf, ch_symb);
     /* sample pilots at start of this frame and start of next frame */
 
     if (sync == 0) {
 
-        /* sample correlation over 2D grid of time and fine freq points */
+       /* Represent f_fine as complex delta-phase instead of frequency */
+       f_fine_d_ph = comp_exp_j(2*M_PI*f_fine/COHPSK_RS);
 
+
+        /* sample correlation over 2D grid of time and fine freq points */
         max_corr = max_mag = 0;
-        for (f_fine=-20; f_fine<=20; f_fine+=0.25) {
+        for (f_fine=-f_fine_range; f_fine<=f_fine_range; f_fine+=delta_f_fine) {
             for (t=0; t<NSYMROWPILOT; t++) {
-                corr_with_pilots(&corr, &mag, coh, t, f_fine);
-                //printf("  f: %f  t: %d corr: %f mag: %f\n", f_fine, t, corr, mag);
+                corr_with_pilots_comp(&corr,&mag,coh,t,f_fine_d_ph);
+
                 if (corr >= max_corr) {
                     max_corr = corr;
                     max_mag = mag;
@@ -585,6 +617,8 @@ void frame_sync_fine_freq_est(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC*ND],
                     coh->f_fine_est = f_fine;
                 }
             }
+            /* Advance f_fine */
+            f_fine_d_ph = cmult(f_fine_d_ph,f_fine_d2_ph);
         }
 
 
@@ -633,7 +667,7 @@ int sync_state_machine(struct COHPSK *coh, int sync, int next_sync)
 
         /* check that sync is still good, fall out of sync on consecutive bad frames */
 
-        corr_with_pilots(&corr, &mag, coh, coh->ct, coh->f_fine_est);
+        corr_with_pilots_comp(&corr, &mag, coh, coh->ct, comp_exp_j(2*M_PI*coh->f_fine_est/COHPSK_RS));
         coh->ratio = fabsf(corr)/mag;
 
         // printf("%f\n", cabsolute(corr)/mag);
@@ -744,17 +778,17 @@ void fdm_downconvert_coh(COMP rx_baseband[COHPSK_NC][COHPSK_M+COHPSK_M/P], int N
     /* downconvert */
 
     for (c=0; c<Nc; c++)
-       for (i=0; i<nin; i++) {
-           phase_rx[c] = cmult(phase_rx[c], freq[c]);
-           rx_baseband[c][i] = cmult(rx_fdm[i], cconj(phase_rx[c]));
-       }
+               for (i=0; i<nin; i++) {
+                       phase_rx[c] = cmult(phase_rx[c], freq[c]);
+                       rx_baseband[c][i] = cmult(rx_fdm[i], cconj(phase_rx[c]));
+               }
 
     /* normalise digital oscilators as the magnitude can drift over time */
 
     for (c=0; c<Nc; c++) {
         mag = cabsolute(phase_rx[c]);
-       phase_rx[c].real /= mag;
-       phase_rx[c].imag /= mag;
+               phase_rx[c].real /= mag;
+               phase_rx[c].imag /= mag;
     }
 }
 
@@ -771,10 +805,12 @@ void fdm_downconvert_coh(COMP rx_baseband[COHPSK_NC][COHPSK_M+COHPSK_M/P], int N
 
 \*---------------------------------------------------------------------------*/
 
+
 void rx_filter_coh(COMP rx_filt[COHPSK_NC+1][P+1], int Nc, COMP rx_baseband[COHPSK_NC+1][COHPSK_M+COHPSK_M/P], COMP rx_filter_memory[COHPSK_NC+1][+COHPSK_NFILTER], int nin)
 {
-    int c, i,j,k,l;
+    int c, i,j,k;
     int n=COHPSK_M/P;
+    COMP acc;
 
     /* rx filter each symbol, generate P filtered output samples for
        each symbol.  Note we keep filter memory at rate M, it's just
@@ -782,25 +818,29 @@ void rx_filter_coh(COMP rx_filt[COHPSK_NC+1][P+1], int Nc, COMP rx_baseband[COHP
 
     for(i=0, j=0; i<nin; i+=n,j++) {
 
-       /* latest input sample */
-
-       for(c=0; c<Nc; c++)
-           for(k=COHPSK_NFILTER-n,l=i; k<COHPSK_NFILTER; k++,l++)
-               rx_filter_memory[c][k] = rx_baseband[c][l];
-
-       /* convolution (filtering) */
-
-       for(c=0; c<Nc; c++) {
-           rx_filt[c][j].real = 0.0; rx_filt[c][j].imag = 0.0;
-           for(k=0; k<COHPSK_NFILTER; k++)
-               rx_filt[c][j] = cadd(rx_filt[c][j], fcmult(gt_alpha5_root_coh[k], rx_filter_memory[c][k]));
-       }
-
-       /* make room for next input sample */
-
-       for(c=0; c<Nc; c++)
-           for(k=0,l=n; k<COHPSK_NFILTER-n; k++,l++)
-               rx_filter_memory[c][k] = rx_filter_memory[c][l];
+               /* latest input sample */
+
+               for(c=0; c<Nc; c++){
+                       k=COHPSK_NFILTER-n;
+                       memcpy(&rx_filter_memory[c][k],&rx_baseband[c][i],n*sizeof(COMP));
+               }
+               /* convolution (filtering) */
+
+               for(c=0; c<Nc; c++) {
+                       /* Cast into const so the compiler doesn't expect aliasing */
+                       const COMP * rx_filt_lc = &rx_filter_memory[c][0];
+                       acc.real = 0.0f;
+                       acc.imag = 0.0f;
+                       for(k=0; k<COHPSK_NFILTER; k++){
+                               acc = cadd(acc, fcmult(gt_alpha5_root_coh[k], rx_filt_lc[k]));
+                       }
+                       rx_filt[c][j] = acc;
+               }
+
+               /* make room for next input sample */
+               for(c=0; c<Nc; c++){
+                       memcpy(&rx_filter_memory[c][0],&rx_filter_memory[c][n],(COHPSK_NFILTER-n)*sizeof(COMP));
+               }
     }
 
     assert(j <= (P+1)); /* check for any over runs */
@@ -948,6 +988,24 @@ void rate_Fs_rx_processing(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC*ND], COM
     coh->rx_timing = rx_timing;
 }
 
+/*---------------------------------------------------------------------------*\
+
+  FUNCTION....: cohpsk_set_freq_est_mode()
+  AUTHOR......: Brady O'Brien
+  DATE CREATED: 12 Dec 2017
+
+  Enables or disables a 'simple' frequency estimation mode. Simple frequency
+  estimation uses substantially less CPU when cohpsk modem is not sunk than
+  default mode, but may take many frames to sync.
+
+\*---------------------------------------------------------------------------*/
+void cohpsk_set_freq_est_mode(struct COHPSK *coh, int use_simple_mode){
+       if(use_simple_mode){
+               coh->freq_est_mode_reduced = 1;
+       }else{
+               coh->freq_est_mode_reduced = 0;
+       }
+}
 
 /*---------------------------------------------------------------------------*\
 
@@ -967,7 +1025,7 @@ void rate_Fs_rx_processing(struct COHPSK *coh, COMP ch_symb[][COHPSK_NC*ND], COM
 void cohpsk_demod(struct COHPSK *coh, float rx_bits[], int *sync_good, COMP rx_fdm[], int *nin_frame)
 {
     COMP  ch_symb[NSW*NSYMROWPILOT][COHPSK_NC*ND];
-    int   i, j, sync, anext_sync, next_sync, nin, r, c;
+    int   i, j, sync, anext_sync, next_sync, nin, r, c, ns_done;
     float max_ratio, f_est;
 
     assert(*nin_frame <= COHPSK_MAX_SAMPLES_PER_FRAME);
@@ -985,11 +1043,34 @@ void cohpsk_demod(struct COHPSK *coh, float rx_bits[], int *sync_good, COMP rx_f
 
     if (sync == 0) {
 
-        /* we can test +/- 20Hz, so we break this up into 3 tests to cover +/- 60Hz */
 
         max_ratio = 0.0;
         f_est = 0.0;
-        for (coh->f_est = FDMDV_FCENTRE-40.0; coh->f_est <= FDMDV_FCENTRE+40.0; coh->f_est += 40.0) {
+
+        coh->f_est -= 20;
+        if(coh->f_est < FDMDV_FCENTRE - 60.0){
+               coh->f_est = FDMDV_FCENTRE + 60;
+        }
+
+        if(!coh->freq_est_mode_reduced){
+               coh->f_est = FDMDV_FCENTRE-40.0;
+        }
+
+        ns_done = 0;
+        //for (coh->f_est = FDMDV_FCENTRE-40.0; coh->f_est <= FDMDV_FCENTRE+40.0; coh->f_est += 40.0)
+        while(!ns_done){
+
+               /* Use slower freq estimator; only do one chunk of freq range */
+               if(coh->freq_est_mode_reduced){
+                       coh->f_est -= 20;
+                               if(coh->f_est < FDMDV_FCENTRE - 60.0){
+                                       coh->f_est = FDMDV_FCENTRE + 60;
+                               }
+                               ns_done = 1;
+               }else{
+                /* we can test +/- 20Hz, so we break this up into 3 tests to cover +/- 60Hz */
+                       if(coh->f_est > FDMDV_FCENTRE+40.0) ns_done = 1;
+               }
 
             if (coh->verbose)
                 fprintf(stderr, "  [%d] acohpsk.f_est: %f +/- 20\n", coh->frame, coh->f_est);
@@ -1010,6 +1091,10 @@ void cohpsk_demod(struct COHPSK *coh, float rx_bits[], int *sync_good, COMP rx_f
                     next_sync   = anext_sync;
                 }
             }
+
+            if(!coh->freq_est_mode_reduced){
+                       coh->f_est += 40;
+            }
         }
 
         if (next_sync == 1) {
index 369fc969e04fcd5361efde7130aa3f1d8e4ca793..478bc4e098cf5d5c35ff126ecc01b3fdddaaa9e6 100644 (file)
@@ -106,11 +106,14 @@ struct COHPSK {
     /* tx amplitude weights for each carrier for test/instrumentation */
 
     float          carrier_ampl[COHPSK_NC*ND];
+
+    /* Flag enabling simple freq est mode */
+    int            freq_est_mode_reduced;
 };
 
 void bits_to_qpsk_symbols(COMP tx_symb[][COHPSK_NC*COHPSK_ND], int tx_bits[], int nbits);
 void qpsk_symbols_to_bits(struct COHPSK *coh, float rx_bits[], COMP ct_symb_buf[][COHPSK_NC*COHPSK_ND]);
-void tx_filter_and_upconvert_coh(COMP tx_fdm[], int Nc, COMP tx_symbols[],
+void tx_filter_and_upconvert_coh(COMP tx_fdm[], int Nc, const COMP tx_symbols[],
                                  COMP tx_filter_memory[COHPSK_NC][COHPSK_NSYM],
                                  COMP phase_tx[], COMP freq[],
                                  COMP *fbb_phase, COMP fbb_rect);
index f0aafcfad1f1365e28176a643cc3b154968cc8b9..f2ae1e99b787df09c38bd78ddade99f5ae2e0e70 100644 (file)
@@ -405,7 +405,7 @@ static void freedv_tx_fsk_voice(struct freedv *f, short mod_out[]) {
     float *tx_float; /* To hold on to modulated samps from fsk/fmfsk */
     uint8_t vc_bits[2]; /* Varicode bits for 2400 framing */
     uint8_t proto_bits[3]; /* Prococol bits for 2400 framing */
-        
+
     /* Frame for 2400A/B */
     if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_2400B){
         /* Get varicode bits for TX and possibly ask for a new char */
@@ -426,7 +426,7 @@ static void freedv_tx_fsk_voice(struct freedv *f, short mod_out[]) {
                 }
             }
         }
-            
+
         /* If the API user hasn't set up message callbacks, don't bother with varicode bits */
         if(f->freedv_get_next_proto != NULL){
             (*f->freedv_get_next_proto)(f->proto_callback_state,(char*)proto_bits);
@@ -440,10 +440,10 @@ static void freedv_tx_fsk_voice(struct freedv *f, short mod_out[]) {
     }else if(f->mode == FREEDV_MODE_800XA){
         fvhff_frame_bits(FREEDV_HF_FRAME_B,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL);
     }
-        
+
     /* Allocate floating point buffer for FSK mod */
     tx_float = alloca(sizeof(float)*f->n_nom_modem_samples);
-        
+
     /* do 4fsk mod */
     if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_800XA){
         fsk_mod(f->fsk,tx_float,(uint8_t*)(f->tx_bits));
@@ -461,6 +461,69 @@ static void freedv_tx_fsk_voice(struct freedv *f, short mod_out[]) {
     }
 }
 
+/* TX routines for 2400 FSK modes, after codec2 encoding */
+static void freedv_comptx_fsk_voice(struct freedv *f, COMP mod_out[]) {
+    int  i;
+    float *tx_float; /* To hold on to modulated samps from fsk/fmfsk */
+    uint8_t vc_bits[2]; /* Varicode bits for 2400 framing */
+    uint8_t proto_bits[3]; /* Prococol bits for 2400 framing */
+
+    /* Frame for 2400A/B */
+    if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_2400B){
+        /* Get varicode bits for TX and possibly ask for a new char */
+        /* 2 bits per 2400A/B frame, so this has to be done twice */
+        for(i=0;i<2;i++){
+            if (f->nvaricode_bits) {
+                vc_bits[i] = f->tx_varicode_bits[f->varicode_bit_index++];
+                f->nvaricode_bits--;
+            }
+
+            if (f->nvaricode_bits == 0) {
+                /* get new char and encode */
+                char s[2];
+                if (f->freedv_get_next_tx_char != NULL) {
+                    s[0] = (*f->freedv_get_next_tx_char)(f->callback_state);
+                    f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1);
+                    f->varicode_bit_index = 0;
+                }
+            }
+        }
+
+        /* If the API user hasn't set up message callbacks, don't bother with varicode bits */
+        if(f->freedv_get_next_proto != NULL){
+            (*f->freedv_get_next_proto)(f->proto_callback_state,(char*)proto_bits);
+            fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),proto_bits,vc_bits);
+        }else if(f->freedv_get_next_tx_char != NULL){
+            fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,vc_bits);
+        }else {
+            fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL);
+        }
+    /* Frame for 800XA */
+    }else if(f->mode == FREEDV_MODE_800XA){
+        fvhff_frame_bits(FREEDV_HF_FRAME_B,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL);
+    }
+
+    /* Allocate floating point buffer for FSK mod */
+    tx_float = alloca(sizeof(float)*f->n_nom_modem_samples);
+
+    /* do 4fsk mod */
+    if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_800XA){
+        fsk_mod_c(f->fsk,mod_out,(uint8_t*)(f->tx_bits));
+        /* Convert float samps to short */
+        for(i=0; i<f->n_nom_modem_samples; i++){
+               mod_out[i] = fcmult(NORM_PWR_FSK,mod_out[i]);
+        }
+    /* do me-fsk mod */
+    }else if(f->mode == FREEDV_MODE_2400B){
+        fmfsk_mod(f->fmfsk,tx_float,(uint8_t*)(f->tx_bits));
+        /* Convert float samps to short */
+        for(i=0; i<f->n_nom_modem_samples; i++){
+            mod_out[i].real = (tx_float[i]);
+        }
+    }
+}
+
+
 /* TX routines for 2400 FSK modes, data channel */
 static void freedv_tx_fsk_data(struct freedv *f, short mod_out[]) {
     int  i;
@@ -731,12 +794,8 @@ void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]) {
 #endif
     /* 2400 A and B are handled by the real-mode TX */
     if((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B)){
-        freedv_tx(f,tx_real,speech_in);
-        /* Convert to complex-mode */
-        for(i=0; i<f->n_nom_modem_samples; i++){
-            mod_out[i].real = (float) tx_real[i];
-            mod_out[i].imag = 0;
-        }
+       codec2_encode(f->codec2, f->packed_codec_bits, speech_in);
+        freedv_comptx_fsk_voice(f,mod_out);
     }
 }
 
@@ -1590,7 +1649,7 @@ void freedv_set_carrier_ampl(struct freedv *freedv, int c, float ampl) {
 
 int freedv_set_alt_modem_samp_rate(struct freedv *f, int samp_rate){
        if(f->mode == FREEDV_MODE_2400A){ 
-               if(samp_rate == 48000 || samp_rate == 96000){
+               if(samp_rate == 24000 || samp_rate == 48000 || samp_rate == 96000){
                        fsk_destroy(f->fsk);
                        f->fsk = fsk_create_hbr(samp_rate,1200,10,4,1200,1200);
         
index 62ad98bdc5b24067941fb53f5e56d1d5c165bad8..ad8f0f02b200ea2c2e43a96c221b15209e93e8cd 100644 (file)
@@ -1090,7 +1090,8 @@ void fsk_mod_c(struct FSK *fsk,COMP fsk_out[],uint8_t tx_bits[]){
     int M = fsk->mode;
     COMP dosc_f[M];                 /* phase shift per sample */
     COMP dph;                       /* phase shift of current bit */
-    size_t i,j,m,bit_i,sym;
+    size_t i,j,bit_i,sym;
+    int m;
     
     /* Init the per sample phase shift complex numbers */
     for( m=0; m<M; m++){