]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
A little more modem polishing
authorSteve Underwood <steveu@coppice.org>
Thu, 21 Mar 2013 14:16:51 +0000 (22:16 +0800)
committerSteve Underwood <steveu@coppice.org>
Thu, 21 Mar 2013 14:16:51 +0000 (22:16 +0800)
libs/spandsp/src/spandsp/private/t4_rx.h
libs/spandsp/src/v27ter_rx.c
libs/spandsp/src/v29rx.c

index 3004d348b74f435b692e479dbb32272fbcaffd5c..58b30e86e97f08d07d38f9b17d5a49a55ab7058f 100644 (file)
@@ -105,6 +105,8 @@ struct t4_rx_state_s
 
     /*! \brief The width of the current page, in pixels. */
     uint32_t image_width;
+    /*! \brief The length of the current page, in pixels. */
+    uint32_t image_length;
 
     union
     {
index 7e1fb9929bbe25cefa947469054933e6f7e523fe..459163a997592fa778d5ea5fc3f905e9e34ca88c 100644 (file)
 #include "spandsp/private/v27ter_rx.h"
 
 #if defined(SPANDSP_USE_FIXED_POINT)
-#define FP_SCALE                        FP_Q_6_10
+#define FP_SCALE(x)                     FP_Q_6_10(x)
 #define FP_FACTOR                       4096
 #define FP_SHIFT_FACTOR                 12
 #else
 #define FP_SCALE(x)                     (x)
 #endif
 
+#define FP_CONSTELLATION_SCALE(x)       FP_SCALE(x)
+
 #include "v27ter_rx_4800_rrc.h"
 #include "v27ter_rx_2400_rrc.h"
 
@@ -115,14 +117,14 @@ static const complexi16_t v27ter_constellation[8] =
 static const complexf_t v27ter_constellation[8] =
 #endif
 {
-    {FP_SCALE( 1.414f), FP_SCALE( 0.0f)},           /*   0deg */
-    {FP_SCALE( 1.0f),   FP_SCALE( 1.0f)},           /*  45deg */
-    {FP_SCALE( 0.0f),   FP_SCALE( 1.414f)},         /*  90deg */
-    {FP_SCALE(-1.0f),   FP_SCALE( 1.0f)},           /* 135deg */
-    {FP_SCALE(-1.414f), FP_SCALE( 0.0f)},           /* 180deg */
-    {FP_SCALE(-1.0f),   FP_SCALE(-1.0f)},           /* 225deg */
-    {FP_SCALE( 0.0f),   FP_SCALE(-1.414f)},         /* 270deg */
-    {FP_SCALE( 1.0f),   FP_SCALE(-1.0f)}            /* 315deg */
+    {FP_CONSTELLATION_SCALE( 1.414f), FP_CONSTELLATION_SCALE( 0.0f)},       /*   0deg */
+    {FP_CONSTELLATION_SCALE( 1.0f),   FP_CONSTELLATION_SCALE( 1.0f)},       /*  45deg */
+    {FP_CONSTELLATION_SCALE( 0.0f),   FP_CONSTELLATION_SCALE( 1.414f)},     /*  90deg */
+    {FP_CONSTELLATION_SCALE(-1.0f),   FP_CONSTELLATION_SCALE( 1.0f)},       /* 135deg */
+    {FP_CONSTELLATION_SCALE(-1.414f), FP_CONSTELLATION_SCALE( 0.0f)},       /* 180deg */
+    {FP_CONSTELLATION_SCALE(-1.0f),   FP_CONSTELLATION_SCALE(-1.0f)},       /* 225deg */
+    {FP_CONSTELLATION_SCALE( 0.0f),   FP_CONSTELLATION_SCALE(-1.414f)},     /* 270deg */
+    {FP_CONSTELLATION_SCALE( 1.0f),   FP_CONSTELLATION_SCALE(-1.0f)}        /* 315deg */
 };
 
 SPAN_DECLARE(float) v27ter_rx_carrier_frequency(v27ter_rx_state_t *s)
@@ -205,14 +207,14 @@ static void equalizer_reset(v27ter_rx_state_t *s)
 {
     /* Start with an equalizer based on everything being perfect. */
 #if defined(SPANDSP_USE_FIXED_POINT)
-    static const complexi16_t x = {FP_SCALE(1.414f), FP_SCALE(0.0f)};
+    static const complexi16_t x = {FP_CONSTELLATION_SCALE(1.414f), FP_CONSTELLATION_SCALE(0.0f)};
 
     cvec_zeroi16(s->eq_coeff, V27TER_EQUALIZER_LEN);
     s->eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1] = x;
     cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_LEN);
     s->eq_delta = 32768.0f*EQUALIZER_DELTA/V27TER_EQUALIZER_LEN;
 #else
-    static const complexf_t x = {1.414f, 0.0f};
+    static const complexf_t x = {FP_CONSTELLATION_SCALE(1.414f), FP_CONSTELLATION_SCALE(0.0f)};
 
     cvec_zerof(s->eq_coeff, V27TER_EQUALIZER_LEN);
     s->eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1] = x;
@@ -336,21 +338,15 @@ static __inline__ int find_octant(complexf_t *z)
 #if defined(SPANDSP_USE_FIXED_POINT)
     abs_re = abs(z->re);
     abs_im = abs(z->im);
-    if (abs_im*1000 > abs_re*414  &&  abs_im*1000 < abs_re*2414)
 #else
     abs_re = fabsf(z->re);
     abs_im = fabsf(z->im);
-    if (abs_im > abs_re*0.4142136f  &&  abs_im < abs_re*2.4142136f)
 #endif
+    if (abs_im*FP_SCALE(1.0f) > abs_re*FP_SCALE(0.4142136f)  &&  abs_im*FP_SCALE(1.0f) < abs_re*FP_SCALE(2.4142136f))
     {
         /* Split the space along the two axes. */
-#if defined(SPANDSP_USE_FIXED_POINT)
-        b1 = (z->re < 0);
-        b2 = (z->im < 0);
-#else
-        b1 = (z->re < 0.0f);
-        b2 = (z->im < 0.0f);
-#endif
+        b1 = (z->re < FP_SCALE(0.0f));
+        b2 = (z->im < FP_SCALE(0.0f));
         bits = (b2 << 2) | ((b1 ^ b2) << 1) | 1;
     }
     else
@@ -402,10 +398,7 @@ static __inline__ void put_bit(v27ter_rx_state_t *s, int bit)
 {
     int out_bit;
 
-    bit &= 1;
-
     out_bit = descramble(s, bit);
-
     /* We need to strip the last part of the training before we let data
        go to the application. */
     if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION)
@@ -519,13 +512,13 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
     complexi16_t z;
     complexi16_t z16;
     const complexi16_t *target;
-    static const complexi16_t zero = {0, 0};
+    static const complexi16_t zero = {FP_SCALE(0.0f), FP_SCALE(0.0f)};
 #else
     float p;
     complexf_t z;
     complexf_t zz;
     const complexf_t *target;
-    static const complexf_t zero = {0.0f, 0.0f};
+    static const complexf_t zero = {FP_SCALE(0.0f), FP_SCALE(0.0f)};
 #endif
     int i;
     int j;
@@ -697,17 +690,13 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
         {
             /* At 4800bps the symbols are 1.08238 (Euclidian) apart.
                At 2400bps the symbols are 2.0 (Euclidian) apart. */
-#if defined(SPANDSP_USE_FIXED_POINT)
-            if ((s->bit_rate == 4800  &&  s->training_error < V27TER_TRAINING_SEG_6_LEN*FP_FACTOR*FP_FACTOR/4)
+            if ((s->bit_rate == 4800  &&  s->training_error < FP_CONSTELLATION_SCALE(V27TER_TRAINING_SEG_6_LEN)*FP_CONSTELLATION_SCALE(0.25f))
                 ||
-                (s->bit_rate == 2400  &&  s->training_error < V27TER_TRAINING_SEG_6_LEN*FP_FACTOR*FP_FACTOR/2))
+                (s->bit_rate == 2400  &&  s->training_error < FP_CONSTELLATION_SCALE(V27TER_TRAINING_SEG_6_LEN)*FP_CONSTELLATION_SCALE(0.5f)))
             {
+#if defined(SPANDSP_USE_FIXED_POINT)
                 span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %d)\n", s->bit_rate, s->training_error);
 #else
-            if ((s->bit_rate == 4800  &&  s->training_error < V27TER_TRAINING_SEG_6_LEN*0.25f)
-                ||
-                (s->bit_rate == 2400  &&  s->training_error < V27TER_TRAINING_SEG_6_LEN*0.5f))
-            {
                 span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %f)\n", s->bit_rate, s->training_error);
 #endif
                 /* We are up and running */
@@ -858,9 +847,9 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
                 {
                     /* Only AGC during the initial training */
 #if defined(SPANDSP_USE_FIXED_POINT)
-                    s->agc_scaling = saturate16(((int32_t) (1024.0f*FP_FACTOR*1.414f))/fixed_sqrt32(power));
+                    s->agc_scaling = saturate16(((int32_t) (FP_SCALE(1.414f)*1024.0f))/fixed_sqrt32(power));
 #else
-                    s->agc_scaling = (1.0f/RX_PULSESHAPER_4800_GAIN)*1.414f/sqrtf(power);
+                    s->agc_scaling = (FP_SCALE(1.414f)/RX_PULSESHAPER_4800_GAIN)/fixed_sqrt32(power);
 #endif
                 }
                 /* Pulse shape while still at the carrier frequency, using a quadrature
@@ -870,7 +859,6 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
                 step = -s->eq_put_step;
                 if (step > RX_PULSESHAPER_4800_COEFF_SETS - 1)
                     step = RX_PULSESHAPER_4800_COEFF_SETS - 1;
-                s->eq_put_step += RX_PULSESHAPER_4800_COEFF_SETS*5/2;
 #if defined(SPANDSP_USE_FIXED_POINT)
                 v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_4800_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
                 sample.re = (v*s->agc_scaling) >> 10;
@@ -888,6 +876,7 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
                 zz.re = sample.re*z.re - sample.im*z.im;
                 zz.im = -sample.re*z.im - sample.im*z.re;
 #endif
+                s->eq_put_step += RX_PULSESHAPER_4800_COEFF_SETS*5/2;
                 process_half_baud(s, &zz);
             }
 #if defined(SPANDSP_USE_FIXED_POINT)
@@ -920,9 +909,9 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
                 {
                     /* Only AGC during the initial training */
 #if defined(SPANDSP_USE_FIXED_POINT)
-                    s->agc_scaling = saturate16(((int32_t) (1024.0f*FP_FACTOR*1.414f))/fixed_sqrt32(power));
+                    s->agc_scaling = saturate16(((int32_t) (FP_SCALE(1.414f)*1024.0f))/fixed_sqrt32(power));
 #else
-                    s->agc_scaling = (1.0f/RX_PULSESHAPER_2400_GAIN)*1.414f/sqrtf(power);
+                    s->agc_scaling = (FP_SCALE(1.414f)/RX_PULSESHAPER_2400_GAIN)/fixed_sqrt32(power);
 #endif
                 }
                 /* Pulse shape while still at the carrier frequency, using a quadrature
@@ -932,7 +921,6 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
                 step = -s->eq_put_step;
                 if (step > RX_PULSESHAPER_2400_COEFF_SETS - 1)
                     step = RX_PULSESHAPER_2400_COEFF_SETS - 1;
-                s->eq_put_step += RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
 #if defined(SPANDSP_USE_FIXED_POINT)
                 v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_2400_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
                 sample.re = (v*s->agc_scaling) >> 10;
@@ -950,6 +938,7 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
                 zz.re = sample.re*z.re - sample.im*z.im;
                 zz.im = -sample.re*z.im - sample.im*z.re;
 #endif
+                s->eq_put_step += RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
                 process_half_baud(s, &zz);
             }
 #if defined(SPANDSP_USE_FIXED_POINT)
@@ -1027,11 +1016,10 @@ SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_
 
 #if defined(SPANDSP_USE_FIXED_POINT)
     vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
-    s->training_error = 0;
 #else
     vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
-    s->training_error = 0.0f;
 #endif
+    s->training_error = FP_CONSTELLATION_SCALE(0.0f);
     s->rrc_filter_step = 0;
 
     s->scramble_reg = 0x3C;
@@ -1068,9 +1056,9 @@ SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_
     {
         s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ);
 #if defined(SPANDSP_USE_FIXED_POINT)
-        s->agc_scaling = (float) (1024.0f*FP_FACTOR)*1.414f/283.0f;
+        s->agc_scaling = (float) FP_SCALE(1.414f)*1024.0f/283.0f;
 #else
-        s->agc_scaling = (1.0f/RX_PULSESHAPER_4800_GAIN)*1.414f/283.0f;
+        s->agc_scaling = (FP_SCALE(1.414f)/RX_PULSESHAPER_4800_GAIN)/283.0f;
 #endif
         equalizer_reset(s);
     }
index 525532a392e2fc062ddbfc94d267975071dd97d1..6e845a9360e45bd907a0ad359f9230769e28d1e9 100644 (file)
 #include "spandsp/private/v29rx.h"
 
 #if defined(SPANDSP_USE_FIXED_POINT)
-#define FP_SCALE                        FP_Q_4_12
+#define FP_SCALE(x)                     FP_Q_4_12(x)
 #define FP_FACTOR                       4096
 #define FP_SHIFT_FACTOR                 12
 #else
 #define FP_SCALE(x)                     (x)
 #endif
 
-#include "v29rx_rrc.h"
+#if defined(SPANDSP_USE_FIXED_POINT)
+#define FP_SYNC_SCALE(x)                FP_Q_6_10(x)
+#define FP_SYNC_SCALE_32(x)             FP_Q_6_10_32(x)
+#define FP_SYNC_SHIFT_FACTOR            10
+#else
+#define FP_SYNC_SCALE(x)                (x)
+#define FP_SYNC_SCALE_32(x)             (x)
+#endif
 
 #define FP_CONSTELLATION_SCALE(x)       FP_SCALE(x)
 
+#include "v29rx_rrc.h"
 #include "v29tx_constellation_maps.h"
 
 /*! The nominal frequency of the carrier, in Hertz */
 /*! The length of training segment 4, in symbols */
 #define V29_TRAINING_SEG_4_LEN          48
 
+/* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
+/* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */
+/* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */
+#define SIN_LOW_BAND_EDGE               0.382683432f
+#define COS_LOW_BAND_EDGE               0.923879533f
+#define SIN_HIGH_BAND_EDGE              0.760405966f
+#define COS_HIGH_BAND_EDGE             -0.649448048f
+#define ALPHA                           0.99f
+
+#define SYNC_LOW_BAND_EDGE_COEFF_0      FP_SYNC_SCALE(2.0f*ALPHA*COS_LOW_BAND_EDGE)
+#define SYNC_LOW_BAND_EDGE_COEFF_1      FP_SYNC_SCALE(-ALPHA*ALPHA)
+#define SYNC_LOW_BAND_EDGE_COEFF_2      FP_SYNC_SCALE(-ALPHA*SIN_LOW_BAND_EDGE)
+#define SYNC_HIGH_BAND_EDGE_COEFF_0     FP_SYNC_SCALE(2.0f*ALPHA*COS_HIGH_BAND_EDGE)
+#define SYNC_HIGH_BAND_EDGE_COEFF_1     FP_SYNC_SCALE(-ALPHA*ALPHA)
+#define SYNC_HIGH_BAND_EDGE_COEFF_2     FP_SYNC_SCALE(-ALPHA*SIN_HIGH_BAND_EDGE)
+#define SYNC_MIXED_EDGES_COEFF_3        FP_SYNC_SCALE(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
+
 enum
 {
     TRAINING_STAGE_NORMAL_OPERATION = 0,
@@ -130,33 +155,6 @@ static const uint8_t space_map_9600[20][20] =
     /*                               Middle ^ Middle */
 };
 
-/* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
-/* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */
-/* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */
-#define SIN_LOW_BAND_EDGE               0.382683432f
-#define COS_LOW_BAND_EDGE               0.923879533f
-#define SIN_HIGH_BAND_EDGE              0.760405966f
-#define COS_HIGH_BAND_EDGE             -0.649448048f
-#define ALPHA                           0.99f
-
-#if defined(SPANDSP_USE_FIXED_POINT)
-#define SYNC_LOW_BAND_EDGE_COEFF_0      FP_Q_6_10(2.0f*ALPHA*COS_LOW_BAND_EDGE)
-#define SYNC_LOW_BAND_EDGE_COEFF_1      FP_Q_6_10(-ALPHA*ALPHA)
-#define SYNC_LOW_BAND_EDGE_COEFF_2      FP_Q_6_10(-ALPHA*SIN_LOW_BAND_EDGE)
-#define SYNC_HIGH_BAND_EDGE_COEFF_0     FP_Q_6_10(2.0f*ALPHA*COS_HIGH_BAND_EDGE)
-#define SYNC_HIGH_BAND_EDGE_COEFF_1     FP_Q_6_10(-ALPHA*ALPHA)
-#define SYNC_HIGH_BAND_EDGE_COEFF_2     FP_Q_6_10(-ALPHA*SIN_HIGH_BAND_EDGE)
-#define SYNC_MIXED_EDGES_COEFF_3        FP_Q_6_10(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
-#else
-#define SYNC_LOW_BAND_EDGE_COEFF_0      (2.0f*ALPHA*COS_LOW_BAND_EDGE)
-#define SYNC_LOW_BAND_EDGE_COEFF_1      (-ALPHA*ALPHA)
-#define SYNC_LOW_BAND_EDGE_COEFF_2      (-ALPHA*SIN_LOW_BAND_EDGE)
-#define SYNC_HIGH_BAND_EDGE_COEFF_0     (2.0f*ALPHA*COS_HIGH_BAND_EDGE)
-#define SYNC_HIGH_BAND_EDGE_COEFF_1     (-ALPHA*ALPHA)
-#define SYNC_HIGH_BAND_EDGE_COEFF_2     (-ALPHA*SIN_HIGH_BAND_EDGE)
-#define SYNC_MIXED_EDGES_COEFF_3        (-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
-#endif
-
 SPAN_DECLARE(float) v29_rx_carrier_frequency(v29_rx_state_t *s)
 {
     return dds_frequencyf(s->carrier_phase_rate);
@@ -234,14 +232,14 @@ static void equalizer_reset(v29_rx_state_t *s)
 {
     /* Start with an equalizer based on everything being perfect */
 #if defined(SPANDSP_USE_FIXED_POINT)
-    static const complexi16_t x = {FP_SCALE(3.0f), FP_SCALE(0.0f)};
+    static const complexi16_t x = {FP_CONSTELLATION_SCALE(3.0f), FP_CONSTELLATION_SCALE(0.0f)};
 
     cvec_zeroi16(s->eq_coeff, V29_EQUALIZER_LEN);
     s->eq_coeff[V29_EQUALIZER_PRE_LEN] = x;
     cvec_zeroi16(s->eq_buf, V29_EQUALIZER_LEN);
     s->eq_delta = 32768.0f*EQUALIZER_DELTA/V29_EQUALIZER_LEN;
 #else
-    static const complexf_t x = {3.0f, 0.0f};
+    static const complexf_t x = {FP_CONSTELLATION_SCALE(3.0f), FP_CONSTELLATION_SCALE(0.0f)};
 
     cvec_zerof(s->eq_coeff, V29_EQUALIZER_LEN);
     s->eq_coeff[V29_EQUALIZER_PRE_LEN] = x;
@@ -262,8 +260,8 @@ static __inline__ complexi16_t equalizer_get(v29_rx_state_t *s)
 
     /* Get the next equalized value. */
     zz = cvec_circular_dot_prodi16(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step);
-    z.re = zz.re >> FP_SHIFT_FACTOR;
-    z.im = zz.im >> FP_SHIFT_FACTOR;
+    z.re = zz.re >> FP_CONSTELLATION_SHIFT_FACTOR;
+    z.im = zz.im >> FP_CONSTELLATION_SHIFT_FACTOR;
     return z;
 }
 #else
@@ -300,36 +298,6 @@ static void tune_equalizer(v29_rx_state_t *s, const complexf_t *z, const complex
 #endif
 /*- End of function --------------------------------------------------------*/
 
-static int scrambled_training_bit(v29_rx_state_t *s)
-{
-    int bit;
-
-    /* Segment 3 of the training sequence - the scrambled CDCD part. */
-    /* Apply the 1 + x^-6 + x^-7 scrambler */
-    bit = s->training_scramble_reg & 1;
-    s->training_scramble_reg >>= 1;
-    if (bit ^ (s->training_scramble_reg & 1))
-        s->training_scramble_reg |= 0x40;
-    return bit;
-}
-/*- End of function --------------------------------------------------------*/
-
-#if defined(SPANDSP_USE_FIXED_POINT)
-static __inline__ int find_quadrant(const complexi16_t *z)
-#else
-static __inline__ int find_quadrant(const complexf_t *z)
-#endif
-{
-    int b1;
-    int b2;
-
-    /* Split the space along the two diagonals. */
-    b1 = (z->im > z->re);
-    b2 = (z->im < -z->re);
-    return (b2 << 1) | (b1 ^ b2);
-}
-/*- End of function --------------------------------------------------------*/
-
 #if defined(SPANDSP_USE_FIXED_POINT)
 static __inline__ void track_carrier(v29_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
 #else
@@ -355,37 +323,71 @@ static __inline__ void track_carrier(v29_rx_state_t *s, const complexf_t *z, con
        different amplitudes of the various target positions scale things. This isn't all bad,
        as the angular error for the larger amplitude constellation points is probably
        a more reliable indicator, and we are weighting it as such. */
-#if defined(SPANDSP_USE_FIXED_POINT)
-    error = (((int32_t) z->im*target->re) >> FP_SHIFT_FACTOR) - (((int32_t) z->re*target->im) >> FP_SHIFT_FACTOR);
-#else
-    error = z->im*target->re - z->re*target->im;
-#endif
     /* Use a proportional-integral approach to tracking the carrier. The PI
        parameters are coarser at first, until we get precisely on target. Then,
        the filter will be damped more to keep us on target. */
 #if defined(SPANDSP_USE_FIXED_POINT)
+    error = (((int32_t) z->im*target->re) >> FP_SHIFT_FACTOR) - (((int32_t) z->re*target->im) >> FP_SHIFT_FACTOR);
     s->carrier_phase_rate += ((s->carrier_track_i*error) >> FP_SHIFT_FACTOR);
     s->carrier_phase += ((s->carrier_track_p*error) >> FP_SHIFT_FACTOR);
 #else
+    error = z->im*target->re - z->re*target->im;
     s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error);
     s->carrier_phase += (int32_t) (s->carrier_track_p*error);
-    //span_log(&s->logging, SPAN_LOG_FLOW, "Im = %15.5f   f = %15.5f\n", error, dds_frequencyf(s->carrier_phase_rate));
 #endif
 }
 /*- End of function --------------------------------------------------------*/
 
-static __inline__ void put_bit(v29_rx_state_t *s, int bit)
+#if defined(SPANDSP_USE_FIXED_POINT)
+static __inline__ int find_quadrant(const complexi16_t *z)
+#else
+static __inline__ int find_quadrant(const complexf_t *z)
+#endif
 {
-    int out_bit;
+    int b1;
+    int b2;
 
-    bit &= 1;
+    /* Split the space along the two diagonals. */
+    b1 = (z->im > z->re);
+    b2 = (z->im < -z->re);
+    return (b2 << 1) | (b1 ^ b2);
+}
+/*- End of function --------------------------------------------------------*/
+
+static int scrambled_training_bit(v29_rx_state_t *s)
+{
+    int bit;
+
+    /* Segment 3 of the training sequence - the scrambled CDCD part. */
+    /* Apply the 1 + x^-6 + x^-7 scrambler */
+    bit = s->training_scramble_reg & 1;
+    s->training_scramble_reg >>= 1;
+    if (bit ^ (s->training_scramble_reg & 1))
+        s->training_scramble_reg |= 0x40;
+    return bit;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int descramble(v29_rx_state_t *s, int in_bit)
+{
+    int out_bit;
 
     /* Descramble the bit */
-    out_bit = (bit ^ (s->scramble_reg >> (18 - 1)) ^ (s->scramble_reg >> (23 - 1))) & 1;
-    s->scramble_reg = (s->scramble_reg << 1) | bit;
+    in_bit &= 1;
+    out_bit = (in_bit ^ (s->scramble_reg >> (18 - 1)) ^ (s->scramble_reg >> (23 - 1))) & 1;
+    s->scramble_reg = (s->scramble_reg << 1) | in_bit;
+
+    return out_bit;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void put_bit(v29_rx_state_t *s, int bit)
+{
+    int out_bit;
 
     /* We need to strip the last part of the training - the test period of all 1s -
        before we let data go to the application. */
+    out_bit = descramble(s, bit);
     if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION)
     {
         s->put_bit(s->put_bit_user_data, out_bit);
@@ -431,11 +433,11 @@ static void decode_baud(v29_rx_state_t *s, complexf_t *z)
     {
         /* 9600 and 7200 are quite similar. */
 #if defined(SPANDSP_USE_FIXED_POINT)
-        re = (z->re + 5*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1);
-        im = (z->im + 5*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1);
+        re = (z->re + FP_CONSTELLATION_SCALE(5.0f)) >> (FP_CONSTELLATION_SHIFT_FACTOR - 1);
+        im = (z->im + FP_CONSTELLATION_SCALE(5.0f)) >> (FP_CONSTELLATION_SHIFT_FACTOR - 1);
 #else
-        re = (int) ((z->re + 5.0f)*2.0f);
-        im = (int) ((z->im + 5.0f)*2.0f);
+        re = (int) ((z->re + FP_CONSTELLATION_SCALE(5.0f))*2.0f);
+        im = (int) ((z->im + FP_CONSTELLATION_SCALE(5.0f))*2.0f);
 #endif
         if (re > 19)
             re = 19;
@@ -499,9 +501,9 @@ static __inline__ void symbol_sync(v29_rx_state_t *s)
 #if defined(SPANDSP_USE_FIXED_POINT)
     /* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */
     /* Cross correlate */
-    v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_LOW_BAND_EDGE_COEFF_2
-      - (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_HIGH_BAND_EDGE_COEFF_2
-      + (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_MIXED_EDGES_COEFF_3;
+    v = (((s->symbol_sync_low[1] >> (FP_SYNC_SHIFT_FACTOR/2))*(s->symbol_sync_high[0] >> (FP_SYNC_SHIFT_FACTOR/2))) >> 14)*SYNC_LOW_BAND_EDGE_COEFF_2
+      - (((s->symbol_sync_low[0] >> (FP_SYNC_SHIFT_FACTOR/2))*(s->symbol_sync_high[1] >> (FP_SYNC_SHIFT_FACTOR/2))) >> 14)*SYNC_HIGH_BAND_EDGE_COEFF_2
+      + (((s->symbol_sync_low[1] >> (FP_SYNC_SHIFT_FACTOR/2))*(s->symbol_sync_high[1] >> (FP_SYNC_SHIFT_FACTOR/2))) >> 14)*SYNC_MIXED_EDGES_COEFF_3;
     /* Filter away any DC component */
     p = v - s->symbol_sync_dc_filter[1];
     s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
@@ -509,15 +511,6 @@ static __inline__ void symbol_sync(v29_rx_state_t *s)
     /* A little integration will now filter away much of the HF noise */
     s->baud_phase -= p;
     v = labs(s->baud_phase);
-    if (v > 30*FP_FACTOR)
-    {
-        i = (v > 1000*FP_FACTOR)  ?  5  :  1;
-        if (s->baud_phase < 0)
-            i = -i;
-        //printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
-        s->eq_put_step += i;
-        s->total_baud_timing_correction += i;
-    }
 #else
     /* Cross correlate */
     v = s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_LOW_BAND_EDGE_COEFF_2
@@ -530,16 +523,16 @@ static __inline__ void symbol_sync(v29_rx_state_t *s)
     /* A little integration will now filter away much of the HF noise */
     s->baud_phase -= p;
     v = fabsf(s->baud_phase);
-    if (v > 30.0f)
+#endif
+    if (v > FP_SYNC_SCALE_32(30.0f))
     {
-        i = (v > 1000.0f)  ?  5  :  1;
-        if (s->baud_phase < 0.0f)
+        i = (v > FP_SYNC_SCALE_32(1000.0f))  ?  5  :  1;
+        if (s->baud_phase < FP_SYNC_SCALE_32(0.0f))
             i = -i;
         //printf("v = %10.5f %5d - %f %f %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
         s->eq_put_step += i;
         s->total_baud_timing_correction += i;
     }
-#endif
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -560,13 +553,13 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
     complexi16_t z;
     complexi16_t z16;
     const complexi16_t *target;
-    static const complexi16_t zero = {0, 0};
+    static const complexi16_t zero = {FP_CONSTELLATION_SCALE(0.0f), FP_CONSTELLATION_SCALE(0.0f)};
 #else
     float p;
     complexf_t z;
     complexf_t zz;
     const complexf_t *target;
-    static const complexf_t zero = {0.0f, 0.0f};
+    static const complexf_t zero = {FP_CONSTELLATION_SCALE(0.0f), FP_CONSTELLATION_SCALE(0.0f)};
 #endif
     int bit;
     int i;
@@ -606,13 +599,15 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
             s->training_stage = TRAINING_STAGE_LOG_PHASE;
             vec_zeroi32(s->diff_angles, 16);
             s->last_angles[0] = arctan2(z.im, z.re);
+            if (s->agc_scaling_save == FP_SCALE(0.0f))
+            {
 #if defined(SPANDSP_USE_FIXED_POINT)
-            if (s->agc_scaling_save == 0)
-                s->agc_scaling_save = s->agc_scaling;
+                span_log(&s->logging, SPAN_LOG_FLOW, "Locking AGC at %d\n", s->agc_scaling);
 #else
-            if (s->agc_scaling_save == 0.0f)
-                s->agc_scaling_save = s->agc_scaling;
+                span_log(&s->logging, SPAN_LOG_FLOW, "Locking AGC at %f\n", s->agc_scaling);
 #endif
+                s->agc_scaling_save = s->agc_scaling;
+            }
         }
         break;
     case TRAINING_STAGE_LOG_PHASE:
@@ -655,11 +650,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
             {
                 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
                 /* Park this modem */
-#if defined(SPANDSP_USE_FIXED_POINT)
-                s->agc_scaling_save = 0;
-#else
-                s->agc_scaling_save = 0.0f;
-#endif
+                s->agc_scaling_save = FP_SCALE(0.0f);
                 s->training_stage = TRAINING_STAGE_PARKED;
                 report_status_change(s, SIG_STATUS_TRAINING_FAILED);
                 break;
@@ -695,11 +686,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
                of a real training sequence. */
             span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
             /* Park this modem */
-#if defined(SPANDSP_USE_FIXED_POINT)
-            s->agc_scaling_save = 0;
-#else
-            s->agc_scaling_save = 0.0f;
-#endif
+            s->agc_scaling_save = FP_SCALE(0.0f);
             s->training_stage = TRAINING_STAGE_PARKED;
             report_status_change(s, SIG_STATUS_TRAINING_FAILED);
         }
@@ -715,12 +702,11 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
         if (++s->training_count >= V29_TRAINING_SEG_3_LEN - 48)
         {
             s->training_stage = TRAINING_STAGE_TRAIN_ON_CDCD_AND_TEST;
+            s->training_error = FP_CONSTELLATION_SCALE(0.0f);
 #if defined(SPANDSP_USE_FIXED_POINT)
-            s->training_error = 0;
             s->carrier_track_i = 200;
             s->carrier_track_p = 1000000;
 #else
-            s->training_error = 0.0f;
             s->carrier_track_i = 200.0f;
             s->carrier_track_p = 1000000.0f;
 #endif
@@ -746,15 +732,12 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
         {
 #if defined(SPANDSP_USE_FIXED_POINT)
             span_log(&s->logging, SPAN_LOG_FLOW, "Constellation mismatch %d\n", s->training_error);
-            if (s->training_error < 48*2*FP_FACTOR*FP_FACTOR)
-            {
-                s->training_error = 0;
 #else
             span_log(&s->logging, SPAN_LOG_FLOW, "Constellation mismatch %f\n", s->training_error);
-            if (s->training_error < 48.0f*2.0f)
-            {
-                s->training_error = 0.0f;
 #endif
+            if (s->training_error < FP_CONSTELLATION_SCALE(48.0f)*FP_CONSTELLATION_SCALE(2.0f))
+            {
+                s->training_error = FP_CONSTELLATION_SCALE(0.0f);
                 s->training_count = 0;
                 s->constellation_state = 0;
                 s->training_stage = TRAINING_STAGE_TEST_ONES;
@@ -763,11 +746,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
             {
                 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (convergence failed)\n");
                 /* Park this modem */
-#if defined(SPANDSP_USE_FIXED_POINT)
-                s->agc_scaling_save = 0;
-#else
-                s->agc_scaling_save = 0.0f;
-#endif
+                s->agc_scaling_save = FP_SCALE(0.0f);
                 s->training_stage = TRAINING_STAGE_PARKED;
                 report_status_change(s, SIG_STATUS_TRAINING_FAILED);
             }
@@ -789,11 +768,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
 #endif
         if (++s->training_count >= V29_TRAINING_SEG_4_LEN)
         {
-#if defined(SPANDSP_USE_FIXED_POINT)
-            if (s->training_error < 48*FP_FACTOR*FP_FACTOR)
-#else
-            if (s->training_error < 48.0f)
-#endif
+            if (s->training_error < FP_CONSTELLATION_SCALE(48.0f)*FP_CONSTELLATION_SCALE(1.0f))
             {
                 /* We are up and running */
 #if defined(SPANDSP_USE_FIXED_POINT)
@@ -815,11 +790,10 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
                 /* Training has failed. Park this modem */
 #if defined(SPANDSP_USE_FIXED_POINT)
                 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %d)\n", s->training_error);
-                s->agc_scaling_save = 0;
 #else
                 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error);
-                s->agc_scaling_save = 0.0f;
 #endif
+                s->agc_scaling_save = FP_SCALE(0.0f);
                 s->training_stage = TRAINING_STAGE_PARKED;
                 report_status_change(s, SIG_STATUS_TRAINING_FAILED);
             }
@@ -888,8 +862,8 @@ static __inline__ int signal_detect(v29_rx_state_t *s, int16_t amp)
                 return 0;
             }
 #if defined(IAXMODEM_STUFF)
-            /* Carrier has dropped, but the put_bit is
-               pending the signal_present delay. */
+            /* Carrier has dropped, but the put_bit is pending the
+               signal_present delay. */
             s->carrier_drop_pending = TRUE;
 #endif
         }
@@ -949,27 +923,33 @@ SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
 #if defined(SPANDSP_USE_FIXED_POINT)
         v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
         sample.re = (v*s->agc_scaling) >> 10;
-#else
-        v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
-        sample.re = v*s->agc_scaling;
-#endif
         /* Symbol timing synchronisation band edge filters */
-#if defined(SPANDSP_USE_FIXED_POINT)
         /* Low Nyquist band edge filter */
-        v = ((s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0) >> 10) + ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> 10) + sample.re;
+        v = ((s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0) >> FP_SYNC_SHIFT_FACTOR)
+          + ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> FP_SYNC_SHIFT_FACTOR)
+          + sample.re;
         s->symbol_sync_low[1] = s->symbol_sync_low[0];
         s->symbol_sync_low[0] = v;
         /* High Nyquist band edge filter */
-        v = ((s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0) >> 10) + ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> 10) + sample.re;
+        v = ((s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0) >> FP_SYNC_SHIFT_FACTOR)
+          + ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> FP_SYNC_SHIFT_FACTOR)
+          + sample.re;
         s->symbol_sync_high[1] = s->symbol_sync_high[0];
         s->symbol_sync_high[0] = v;
 #else
+        v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
+        sample.re = v*s->agc_scaling;
+        /* Symbol timing synchronisation band edge filters */
         /* Low Nyquist band edge filter */
-        v = s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0 + s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1 + sample.re;
+        v = s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0
+          + s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1
+          + sample.re;
         s->symbol_sync_low[1] = s->symbol_sync_low[0];
         s->symbol_sync_low[0] = v;
         /* High Nyquist band edge filter */
-        v = s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0 + s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1 + sample.re;
+        v = s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0
+          + s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1
+          + sample.re;
         s->symbol_sync_high[1] = s->symbol_sync_high[0];
         s->symbol_sync_high[0] = v;
 #endif
@@ -978,18 +958,18 @@ SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
         if (s->eq_put_step <= 0)
         {
             /* Only AGC until we have locked down the setting. */
+            if (s->agc_scaling_save == FP_SCALE(0.0f))
+            {
 #if defined(SPANDSP_USE_FIXED_POINT)
-            if (s->agc_scaling_save == 0)
-                s->agc_scaling = saturate16(((int32_t) (1024.0f*FP_FACTOR*1.25f))/fixed_sqrt32(power));
+                s->agc_scaling = saturate16(((int32_t) (FP_SCALE(1.25f)*1024.0f))/fixed_sqrt32(power));
 #else
-            if (s->agc_scaling_save == 0.0f)
-                s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*1.25f/sqrtf(power);
+                s->agc_scaling = (FP_SCALE(1.25f)/RX_PULSESHAPER_GAIN)/fixed_sqrt32(power);
 #endif
+            }
             /* Pulse shape while still at the carrier frequency, using a quadrature
                pair of filters. This results in a properly bandpass filtered complex
                signal, which can be brought directly to baseband by complex mixing.
                No further filtering, to remove mixer harmonics, is needed. */
-            s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
 #if defined(SPANDSP_USE_FIXED_POINT)
             v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_im[step], V29_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
             sample.im = (v*s->agc_scaling) >> 10;
@@ -1003,6 +983,7 @@ SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
             zz.re = sample.re*z.re - sample.im*z.im;
             zz.im = -sample.re*z.im - sample.im*z.re;
 #endif
+            s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
             process_half_baud(s, &zz);
         }
 #if defined(SPANDSP_USE_FIXED_POINT)
@@ -1118,12 +1099,11 @@ SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train)
     {
         s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ);
         equalizer_reset(s);
+        s->agc_scaling_save = FP_SCALE(0.0f);
 #if defined(SPANDSP_USE_FIXED_POINT)
-        s->agc_scaling_save = 0;
-        s->agc_scaling = (float) (1024.0f*FP_FACTOR)*1.25f/735.0f;
+        s->agc_scaling = (float) (FP_SCALE(1.25f)*1024.0f)/735.0f;
 #else
-        s->agc_scaling_save = 0.0f;
-        s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*1.25f/735.0f;
+        s->agc_scaling = (FP_SCALE(1.25f)/RX_PULSESHAPER_GAIN)/735.0f;
 #endif
     }
 #if defined(SPANDSP_USE_FIXED_POINT)
@@ -1137,23 +1117,13 @@ SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train)
     s->eq_skip = 0;
 
     /* Initialise the working data for symbol timing synchronisation */
-#if defined(SPANDSP_USE_FIXED_POINT)
     for (i = 0;  i < 2;  i++)
     {
-        s->symbol_sync_low[i] = 0;
-        s->symbol_sync_high[i] = 0;
-        s->symbol_sync_dc_filter[i] = 0;
+        s->symbol_sync_low[i] = FP_SCALE(0.0f);
+        s->symbol_sync_high[i] = FP_SCALE(0.0f);
+        s->symbol_sync_dc_filter[i] = FP_SCALE(0.0f);
     }
-    s->baud_phase = 0;
-#else
-    for (i = 0;  i < 2;  i++)
-    {
-        s->symbol_sync_low[i] = 0.0f;
-        s->symbol_sync_high[i] = 0.0f;
-        s->symbol_sync_dc_filter[i] = 0.0f;
-    }
-    s->baud_phase = 0.0f;
-#endif
+    s->baud_phase = FP_SCALE(0.0f);
     s->baud_half = 0;
 
     s->total_baud_timing_correction = 0;