diff --git a/libs/spandsp/src/dtmf.c b/libs/spandsp/src/dtmf.c index 35dc6c9dd1..ac1656360e 100644 --- a/libs/spandsp/src/dtmf.c +++ b/libs/spandsp/src/dtmf.c @@ -258,45 +258,42 @@ SPAN_DECLARE(int) dtmf_rx(dtmf_rx_state_t *s, const int16_t amp[], int samples) Note this is only relevant to VoIP using A-law, u-law or similar. Low bit rate codecs scramble DTMF too much for it to be recognised, and often slip in units larger than a sample. */ - if (hit != s->in_digit) + if (hit != s->in_digit && s->last_hit != s->in_digit) { - if (s->last_hit != s->in_digit) + /* We have two successive indications that something has changed. */ + /* To declare digit on, the hits must agree. Otherwise we declare tone off. */ + hit = (hit && hit == s->last_hit) ? hit : 0; + if (s->realtime_callback) { - /* We have two successive indications that something has changed. */ - /* To declare digit on, the hits must agree. Otherwise we declare tone off. */ - hit = (hit && hit == s->last_hit) ? hit : 0; - if (s->realtime_callback) + /* Avoid reporting multiple no digit conditions on flaky hits */ + if (s->in_digit || hit) { - /* Avoid reporting multiple no digit conditions on flaky hits */ - if (s->in_digit || hit) - { - i = (s->in_digit && !hit) ? -99 : lfastrintf(log10f(s->energy)*10.0f - DTMF_POWER_OFFSET + DBM0_MAX_POWER); - s->realtime_callback(s->realtime_callback_data, hit, i, s->duration); - s->duration = 0; - } + i = (s->in_digit && !hit) ? -99 : lfastrintf(log10f(s->energy)*10.0f - DTMF_POWER_OFFSET + DBM0_MAX_POWER); + s->realtime_callback(s->realtime_callback_data, hit, i, s->duration); + s->duration = 0; } - else - { - if (hit) - { - if (s->current_digits < MAX_DTMF_DIGITS) - { - s->digits[s->current_digits++] = (char) hit; - s->digits[s->current_digits] = '\0'; - if (s->digits_callback) - { - s->digits_callback(s->digits_callback_data, s->digits, s->current_digits); - s->current_digits = 0; - } - } - else - { - s->lost_digits++; - } - } - } - s->in_digit = hit; } + else + { + if (hit) + { + if (s->current_digits < MAX_DTMF_DIGITS) + { + s->digits[s->current_digits++] = (char) hit; + s->digits[s->current_digits] = '\0'; + if (s->digits_callback) + { + s->digits_callback(s->digits_callback_data, s->digits, s->current_digits); + s->current_digits = 0; + } + } + else + { + s->lost_digits++; + } + } + } + s->in_digit = hit; } s->last_hit = hit; #if defined(SPANDSP_USE_FIXED_POINT) @@ -333,7 +330,7 @@ SPAN_DECLARE(int) dtmf_rx_fillin(dtmf_rx_state_t *s, int samples) #endif s->current_sample = 0; /* Don't update the hit detection. Pretend it never happened. */ - /* TODO: Surely we can be a cleverer than this. */ + /* TODO: Surely we can be cleverer than this. */ return 0; } /*- End of function --------------------------------------------------------*/ @@ -359,7 +356,7 @@ SPAN_DECLARE(size_t) dtmf_rx_get(dtmf_rx_state_t *s, char *buf, int max) s->current_digits -= max; } buf[max] = '\0'; - return max; + return max; } /*- End of function --------------------------------------------------------*/ @@ -417,7 +414,7 @@ SPAN_DECLARE(dtmf_rx_state_t *) dtmf_rx_init(dtmf_rx_state_t *s, if (s == NULL) { if ((s = (dtmf_rx_state_t *) malloc(sizeof (*s))) == NULL) - return NULL; + return NULL; } memset(s, 0, sizeof(*s)); span_log_init(&s->logging, SPAN_LOG_NONE, NULL); @@ -570,7 +567,7 @@ SPAN_DECLARE(dtmf_tx_state_t *) dtmf_tx_init(dtmf_tx_state_t *s) if (s == NULL) { if ((s = (dtmf_tx_state_t *) malloc(sizeof (*s))) == NULL) - return NULL; + return NULL; } memset(s, 0, sizeof(*s)); if (!dtmf_tx_inited) diff --git a/libs/spandsp/src/hdlc.c b/libs/spandsp/src/hdlc.c index fc401fb5d1..d08ab1a05e 100644 --- a/libs/spandsp/src/hdlc.c +++ b/libs/spandsp/src/hdlc.c @@ -154,7 +154,8 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s) s->rx_frames++; s->rx_bytes += s->len - s->crc_bytes; s->len -= s->crc_bytes; - s->frame_handler(s->frame_user_data, s->buffer, s->len, TRUE); + if (s->frame_handler) + s->frame_handler(s->frame_user_data, s->buffer, s->len, TRUE); } else { @@ -162,7 +163,8 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s) if (s->report_bad_frames) { s->len -= s->crc_bytes; - s->frame_handler(s->frame_user_data, s->buffer, s->len, FALSE); + if (s->frame_handler) + s->frame_handler(s->frame_user_data, s->buffer, s->len, FALSE); } } } @@ -177,7 +179,8 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s) s->len -= s->crc_bytes; else s->len = 0; - s->frame_handler(s->frame_user_data, s->buffer, s->len, FALSE); + if (s->frame_handler) + s->frame_handler(s->frame_user_data, s->buffer, s->len, FALSE); } s->rx_length_errors++; } diff --git a/libs/spandsp/src/make_modem_filter.c b/libs/spandsp/src/make_modem_filter.c index aa58ac301b..9bf49eb0aa 100644 --- a/libs/spandsp/src/make_modem_filter.c +++ b/libs/spandsp/src/make_modem_filter.c @@ -450,6 +450,151 @@ int main(int argc, char **argv) rx_tag = ""; tx_tag = ""; } + else if (strcmp(modem, "V.34_2400") == 0) + { + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 10; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + carrier = 1600.0; + baud_rate = 2400.0; + rx_tag = "_2400_low_carrier"; + tx_tag = "_2400"; + } + else if (strcmp(modem, "V.34_2400_high") == 0) + { + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 10; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + carrier = 1800.0; + baud_rate = 2400.0; + rx_tag = "_2400_high_carrier"; + tx_tag = "_2400"; + } + else if (strcmp(modem, "V.34_2743") == 0) + { + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 35; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + carrier = 1646.0; + baud_rate = 2400.0*8.0/7.0; + rx_tag = "_2743_low_carrier"; + tx_tag = "_2743"; + } + else if (strcmp(modem, "V.34_2743_high") == 0) + { + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 35; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + carrier = 1829.0; + baud_rate = 2400.0*8.0/7.0; + rx_tag = "_2743_high_carrier"; + tx_tag = "_2743"; + } + else if (strcmp(modem, "V.34_2800") == 0) + { + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 20; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + carrier = 1680.0; + baud_rate = 2400.0*7.0/6.0; + rx_tag = "_2800_low_carrier"; + tx_tag = "_2800"; + } + else if (strcmp(modem, "V.34_2800_high") == 0) + { + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 20; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + carrier = 1867.0; + baud_rate = 2400.0*7.0/6.0; + rx_tag = "_2800_high_carrier"; + tx_tag = "_2800"; + } + else if (strcmp(modem, "V.34_3000") == 0) + { + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 8; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + carrier = 1800.0; + baud_rate = 2400.0*5.0/4.0; + rx_tag = "_3000_low_carrier"; + tx_tag = "_3000"; + } + else if (strcmp(modem, "V.34_3000_high") == 0) + { + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 8; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + carrier = 2000.0; + baud_rate = 2400.0*5.0/4.0; + rx_tag = "_3000_high_carrier"; + tx_tag = "_3000"; + } + else if (strcmp(modem, "V.34_3200") == 0) + { + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 5; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + carrier = 1829.0; + baud_rate = 2400.0*4.0/3.0; + rx_tag = "_3200_low_carrier"; + tx_tag = "_3200"; + } + else if (strcmp(modem, "V.34_3200_high") == 0) + { + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 5; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + carrier = 1920.0; + baud_rate = 2400.0*4.0/3.0; + rx_tag = "_3200_high_carrier"; + tx_tag = "_3200"; + } + else if (strcmp(modem, "V.34_3429") == 0) + { + /* There is only one carrier frequency defined for this baud rate */ + rx_coeff_sets = 192; + rx_coeffs_per_filter = 27; + rx_excess_bandwidth = 0.25; + tx_coeff_sets = 7; + tx_coeffs_per_filter = 9; + tx_excess_bandwidth = 0.12; + //carrier = 1959.0; + carrier = 1959.0; + baud_rate = 2400.0*10.0/7.0; + rx_tag = "_3429"; + tx_tag = "_3429"; + } else { usage(); diff --git a/libs/spandsp/src/modem_connect_tones.c b/libs/spandsp/src/modem_connect_tones.c index 25e96b04d2..4162286db8 100644 --- a/libs/spandsp/src/modem_connect_tones.c +++ b/libs/spandsp/src/modem_connect_tones.c @@ -29,9 +29,11 @@ /* CNG is 0.5s+-15% of 1100+-38Hz, 3s+-15% off, repeating. CED is 0.2s silence, 3.3+-0.7s of 2100+-15Hz, and 75+-20ms of silence. - + + Calling tone is 0.5s-0.7s of 1300Hz+-15Hz, 1.5s-2.0s off, repeating. + ANS is 3.3+-0.7s of 2100+-15Hz. - + ANS/ is 3.3+-0.7s of 2100+-15Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms. ANSam/ is 2100+-1Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms, and AM with a sinewave of 15+-0.1Hz. @@ -92,6 +94,8 @@ SPAN_DECLARE(const char *) modem_connect_tone_to_str(int tone) return "FAX preamble"; case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: return "FAX CED or preamble"; + case MODEM_CONNECT_TONES_CALLING_TONE: + return "Calling tone"; } return "???"; } @@ -202,6 +206,29 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t * } s->duration_timer -= len; break; + case MODEM_CONNECT_TONES_CALLING_TONE: + for ( ; i < len; i++) + { + if (s->duration_timer > ms_to_samples(2000)) + { + if ((xlen = i + s->duration_timer - ms_to_samples(2000)) > len) + xlen = len; + s->duration_timer -= (xlen - i); + for ( ; i < xlen; i++) + amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); + } + if (s->duration_timer > 0) + { + if ((xlen = i + s->duration_timer) > len) + xlen = len; + s->duration_timer -= (xlen - i); + memset(amp + i, 0, sizeof(int16_t)*(xlen - i)); + i = xlen; + } + if (s->duration_timer == 0) + s->duration_timer = ms_to_samples(600 + 2000); + } + break; } return len; } @@ -274,6 +301,17 @@ SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem s->mod_phase = 0; s->hop_timer = ms_to_samples(450); break; + case MODEM_CONNECT_TONES_CALLING_TONE: + /* 0.6s of 1300Hz+-15Hz + 2.0s of silence repeating. */ + s->tone_phase_rate = dds_phase_rate(1300.0); + s->level = dds_scaling_dbm0(-11); + s->duration_timer = ms_to_samples(600 + 2000); + s->mod_phase_rate = 0; + s->tone_phase = 0; + s->mod_phase = 0; + s->mod_level = 0; + s->hop_timer = 0; + break; default: if (alloced) free(s); @@ -402,6 +440,8 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * famp = amp[i]; /* A Cauer notch at 1100Hz, spread just wide enough to meet our detection bandwidth criteria. */ + /* Poles 0.736618498*exp(+-1047/4000 * PI * j) + Zeroes exp(+-1099.5 * PI * j) */ v1 = 0.792928f*famp + 1.0018744927985f*s->znotch_1 - 0.54196833412465f*s->znotch_2; famp = v1 - 1.2994747954630f*s->znotch_1 + s->znotch_2; s->znotch_2 = s->znotch_1; @@ -446,6 +486,8 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * { famp = amp[i]; /* A Cauer bandpass at 15Hz, with which we demodulate the AM signal. */ + /* Poles 0.9983989*exp(+-15/4000 * PI * j) + Zeroes exp(0 * PI * j) */ v1 = fabs(famp) + 1.996667f*s->z15hz_1 - 0.9968004f*s->z15hz_2; filtered = 0.001599787f*(v1 - s->z15hz_2); s->z15hz_2 = s->z15hz_1; @@ -454,8 +496,8 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * //printf("%9.1f %10.4f %9d %9d\n", famp, filtered, s->am_level, s->channel_level); /* A Cauer notch at 2100Hz, spread just wide enough to meet our detection bandwidth criteria. */ - /* This is actually centred at 2095Hz, but gets the balance we want, due - to the asymmetric walls of the notch */ + /* Poles 0.7144255*exp(+-2105.612/4000 * PI * j) + Zeroes exp(+-2099.9 * PI * j) */ v1 = 0.76000f*famp - 0.1183852f*s->znotch_1 - 0.5104039f*s->znotch_2; famp = v1 + 0.1567596f*s->znotch_1 + s->znotch_2; s->znotch_2 = s->znotch_1; @@ -543,6 +585,44 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * } } break; + case MODEM_CONNECT_TONES_CALLING_TONE: + for (i = 0; i < len; i++) + { + famp = amp[i]; + /* A Cauer notch at 1300Hz, spread just wide enough to meet our detection bandwidth + criteria. */ + /* Poles 0.736618498*exp(+-1247/4000 * PI * j) + Zeroes exp(+-1299.5 * PI * j) */ + v1 = 0.755582f*famp + 0.820887174515f*s->znotch_1 - 0.541968324778f*s->znotch_2; + famp = v1 - 1.0456667108f*s->znotch_1 + s->znotch_2; + s->znotch_2 = s->znotch_1; + s->znotch_1 = v1; + notched = (int16_t) lfastrintf(famp); + + /* Estimate the overall energy in the channel, and the energy in + the notch (i.e. overall channel energy - tone energy => noise). + Use abs instead of multiply for speed (is it really faster?). */ + s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); + s->notch_level += ((abs(notched) - s->notch_level) >> 5); + if (s->channel_level > 70 && s->notch_level*6 < s->channel_level) + { + /* There is adequate energy in the channel, and it is mostly at 1300Hz. */ + if (s->tone_present != MODEM_CONNECT_TONES_CALLING_TONE) + { + if (++s->tone_cycle_duration >= ms_to_samples(415)) + report_tone_state(s, MODEM_CONNECT_TONES_CALLING_TONE, lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); + } + } + else + { + /* If the signal looks wrong, even for a moment, we consider this the + end of the tone. */ + if (s->tone_present == MODEM_CONNECT_TONES_CALLING_TONE) + report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); + s->tone_cycle_duration = 0; + } + } + break; } return 0; } diff --git a/libs/spandsp/src/spandsp/modem_connect_tones.h b/libs/spandsp/src/spandsp/modem_connect_tones.h index db3831bf28..f0c0aaeb2e 100644 --- a/libs/spandsp/src/spandsp/modem_connect_tones.h +++ b/libs/spandsp/src/spandsp/modem_connect_tones.h @@ -75,7 +75,10 @@ enum /*! \brief CED tone is the same as ANS tone. FAX preamble in a string of V.21 HDLC flag octets. This is only valid as a tone type to receive. It is never reported as a detected tone type. The report will either be for FAX preamble or CED/ANS tone. */ - MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE = 7 + MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE = 7, + /*! \brief Calling tone is a pure 1300Hz tone, in 0.6s bursts, with 2s silences in between. The + bursts repeat for as long as is required. */ + MODEM_CONNECT_TONES_CALLING_TONE = 8 }; /*! \brief FAX CED tone is the same as ANS tone. */ diff --git a/libs/spandsp/src/spandsp/private/super_tone_rx.h b/libs/spandsp/src/spandsp/private/super_tone_rx.h index 1f0fd98564..e62d455d47 100644 --- a/libs/spandsp/src/spandsp/private/super_tone_rx.h +++ b/libs/spandsp/src/spandsp/private/super_tone_rx.h @@ -26,7 +26,7 @@ #if !defined(_SPANDSP_PRIVATE_SUPER_TONE_RX_H_) #define _SPANDSP_PRIVATE_SUPER_TONE_RX_H_ -#define BINS 128 +#define SUPER_TONE_BINS 128 struct super_tone_rx_segment_s { @@ -41,7 +41,7 @@ struct super_tone_rx_descriptor_s { int used_frequencies; int monitored_frequencies; - int pitches[BINS/2][2]; + int pitches[SUPER_TONE_BINS/2][2]; int tones; super_tone_rx_segment_t **tone_list; int *tone_segs; @@ -55,7 +55,7 @@ struct super_tone_rx_state_s int detected_tone; int rotation; tone_report_func_t tone_callback; - void (*segment_callback)(void *data, int f1, int f2, int duration); + tone_segment_func_t segment_callback; void *callback_data; super_tone_rx_segment_t segments[11]; goertzel_state_t state[]; diff --git a/libs/spandsp/src/spandsp/private/v22bis.h b/libs/spandsp/src/spandsp/private/v22bis.h index d5016430e9..dca574df77 100644 --- a/libs/spandsp/src/spandsp/private/v22bis.h +++ b/libs/spandsp/src/spandsp/private/v22bis.h @@ -209,7 +209,7 @@ struct v22bis_state_s uint32_t guard_phase; /*! \brief The update rate for the phase of the guard tone (i.e. the DDS increment). */ int32_t guard_phase_rate; - float guard_level; + float guard_tone_gain; /*! \brief The current fractional phase of the baud timing. */ int baud_phase; /*! \brief The code number for the current position in the constellation. */ diff --git a/libs/spandsp/src/spandsp/v8.h b/libs/spandsp/src/spandsp/v8.h index 152c478fad..fa9df4a0c5 100644 --- a/libs/spandsp/src/spandsp/v8.h +++ b/libs/spandsp/src/spandsp/v8.h @@ -118,6 +118,8 @@ struct v8_parms_s { int status; int modem_connect_tone; + int send_ci; + int v92; int call_function; unsigned int modulations; int protocol; diff --git a/libs/spandsp/src/super_tone_rx.c b/libs/spandsp/src/super_tone_rx.c index 87934669ab..97b9655ea7 100644 --- a/libs/spandsp/src/super_tone_rx.c +++ b/libs/spandsp/src/super_tone_rx.c @@ -56,11 +56,11 @@ #include "spandsp/private/super_tone_rx.h" #if defined(SPANDSP_USE_FIXED_POINT) -#define DETECTION_THRESHOLD 16439 /* -42dBm0 [((BINS*BINS*32768.0/(1.4142*128.0))*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */ +#define DETECTION_THRESHOLD 16439 /* -42dBm0 [((SUPER_TONE_BINS*SUPER_TONE_BINS*32768.0/(1.4142*128.0))*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */ #define TONE_TWIST 4 /* 6dB */ #define TONE_TO_TOTAL_ENERGY 64 /* -3dB */ #else -#define DETECTION_THRESHOLD 2104205.6f /* -42dBm0 [((BINS*BINS*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */ +#define DETECTION_THRESHOLD 2104205.6f /* -42dBm0 [((SUPER_TONE_BINS*SUPER_TONE_BINS*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */ #define TONE_TWIST 3.981f /* 6dB */ #define TONE_TO_TOTAL_ENERGY 1.995f /* 3dB */ #endif @@ -86,7 +86,7 @@ static int add_super_tone_freq(super_tone_rx_descriptor_t *desc, int freq) /* Merge these two */ desc->pitches[desc->used_frequencies][0] = freq; desc->pitches[desc->used_frequencies][1] = i; - make_goertzel_descriptor(&desc->desc[desc->pitches[i][1]], (float) (freq + desc->pitches[i][0])/2, BINS); + make_goertzel_descriptor(&desc->desc[desc->pitches[i][1]], (float) (freq + desc->pitches[i][0])/2, SUPER_TONE_BINS); desc->used_frequencies++; return desc->pitches[i][1]; } @@ -97,7 +97,7 @@ static int add_super_tone_freq(super_tone_rx_descriptor_t *desc, int freq) { desc->desc = (goertzel_descriptor_t *) realloc(desc->desc, (desc->monitored_frequencies + 5)*sizeof(goertzel_descriptor_t)); } - make_goertzel_descriptor(&desc->desc[desc->monitored_frequencies++], (float) freq, BINS); + make_goertzel_descriptor(&desc->desc[desc->monitored_frequencies++], (float) freq, SUPER_TONE_BINS); desc->used_frequencies++; return desc->pitches[i][1]; } @@ -162,9 +162,9 @@ static int test_cadence(super_tone_rx_segment_t *pattern, j = (rotation + steps - 2)%steps; if (pattern[j].f1 != test[8].f1 || pattern[j].f2 != test[8].f2) return 0; - if (pattern[j].min_duration > test[8].min_duration*BINS + if (pattern[j].min_duration > test[8].min_duration*SUPER_TONE_BINS || - pattern[j].max_duration < test[8].min_duration*BINS) + pattern[j].max_duration < test[8].min_duration*SUPER_TONE_BINS) { return 0; } @@ -172,7 +172,7 @@ static int test_cadence(super_tone_rx_segment_t *pattern, j = (rotation + steps - 1)%steps; if (pattern[j].f1 != test[9].f1 || pattern[j].f2 != test[9].f2) return 0; - if (pattern[j].max_duration < test[9].min_duration*BINS) + if (pattern[j].max_duration < test[9].min_duration*SUPER_TONE_BINS) return 0; } else @@ -183,9 +183,9 @@ static int test_cadence(super_tone_rx_segment_t *pattern, j = i + 10 - steps; if (pattern[i].f1 != test[j].f1 || pattern[i].f2 != test[j].f2) return 0; - if (pattern[i].min_duration > test[j].min_duration*BINS + if (pattern[i].min_duration > test[j].min_duration*SUPER_TONE_BINS || - pattern[i].max_duration < test[j].min_duration*BINS) + pattern[i].max_duration < test[j].min_duration*SUPER_TONE_BINS) { return 0; } @@ -313,9 +313,9 @@ static void super_tone_chunk(super_tone_rx_state_t *s) int k1; int k2; #if defined(SPANDSP_USE_FIXED_POINT) - int32_t res[BINS/2]; + int32_t res[SUPER_TONE_BINS/2]; #else - float res[BINS/2]; + float res[SUPER_TONE_BINS/2]; #endif for (i = 0; i < s->desc->monitored_frequencies; i++) @@ -397,7 +397,7 @@ static void super_tone_chunk(super_tone_rx_state_t *s) s->segment_callback(s->callback_data, s->segments[9].f1, s->segments[9].f2, - s->segments[9].min_duration*BINS/8); + s->segments[9].min_duration*SUPER_TONE_BINS/8); } memcpy (&s->segments[0], &s->segments[1], 9*sizeof(s->segments[0])); s->segments[9].f1 = k1; @@ -467,7 +467,7 @@ SPAN_DECLARE(int) super_tone_rx(super_tone_rx_state_t *s, const int16_t amp[], i s->energy += xamp*xamp; #endif } - if (s->state[0].current_sample >= BINS) + if (s->state[0].current_sample >= SUPER_TONE_BINS) { /* We have finished a Goertzel block. */ super_tone_chunk(s); diff --git a/libs/spandsp/src/t38_gateway.c b/libs/spandsp/src/t38_gateway.c index 4c0c5a59da..1cf859b997 100644 --- a/libs/spandsp/src/t38_gateway.c +++ b/libs/spandsp/src/t38_gateway.c @@ -440,9 +440,9 @@ static int set_next_tx_type(t38_gateway_state_t *s) /* There is a handler queued, so that is the next one. */ set_tx_handler(s, t->next_tx_handler, t->next_tx_user_data); set_next_tx_handler(s, NULL, NULL); - if (t->tx_handler == (span_tx_handler_t) &(silence_gen) + if (t->tx_handler == (span_tx_handler_t) &silence_gen || - t->tx_handler == (span_tx_handler_t) &(tone_gen)) + t->tx_handler == (span_tx_handler_t) &tone_gen) { set_rx_active(s, TRUE); } diff --git a/libs/spandsp/src/v18.c b/libs/spandsp/src/v18.c index b35d5fa4e9..ee939b5cfd 100644 --- a/libs/spandsp/src/v18.c +++ b/libs/spandsp/src/v18.c @@ -111,7 +111,7 @@ static const struct dtmf_to_ascii_s dtmf_to_ascii[] = {"##8", 'W'}, {"##9", 'Z'}, {"##0", ' '}, -#if defined(WIN32) || ( defined(__SVR4) && defined (__sun)) +#if defined(WIN32) || (defined(__SVR4) && defined (__sun)) {"#*1", 'X'}, // (Note 1) 111 1011 {"#*2", 'X'}, // (Note 1) 111 1100 {"#*3", 'X'}, // (Note 1) 111 1101 diff --git a/libs/spandsp/src/v22bis_rx.c b/libs/spandsp/src/v22bis_rx.c index 55c540d53e..85c0b9e10c 100644 --- a/libs/spandsp/src/v22bis_rx.c +++ b/libs/spandsp/src/v22bis_rx.c @@ -52,6 +52,9 @@ #include "spandsp/telephony.h" #include "spandsp/logging.h" +#include "spandsp/fast_convert.h" +#include "spandsp/math_fixed.h" +#include "spandsp/saturated.h" #include "spandsp/complex.h" #include "spandsp/vector_float.h" #include "spandsp/complex_vector_float.h" @@ -77,12 +80,12 @@ #include "v22bis_rx_2400_floating_rrc.h" #endif -#define ms_to_symbols(t) (((t)*600)/1000) +#define ms_to_symbols(t) (((t)*600)/1000) /*! The adaption rate coefficient for the equalizer */ -#define EQUALIZER_DELTA 0.25f +#define EQUALIZER_DELTA 0.25f /*! The number of phase shifted coefficient set for the pulse shaping/bandpass filter */ -#define PULSESHAPER_COEFF_SETS 12 +#define PULSESHAPER_COEFF_SETS 12 /* The basic method used by the V.22bis receiver is: diff --git a/libs/spandsp/src/v22bis_tx.c b/libs/spandsp/src/v22bis_tx.c index 39ad4dd240..41c7ed2f38 100644 --- a/libs/spandsp/src/v22bis_tx.c +++ b/libs/spandsp/src/v22bis_tx.c @@ -310,8 +310,8 @@ static __inline__ int get_scrambled_bit(v22bis_state_t *s) static complexf_t training_get(v22bis_state_t *s) { - complexf_t z; int bits; + static const complexf_t zero = {0.0f, 0.0f}; /* V.22bis training sequence */ switch (s->tx.training) @@ -329,20 +329,17 @@ static complexf_t training_get(v22bis_state_t *s) case V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE: /* Silence */ s->tx.constellation_state = 0; - z = complex_setf(0.0f, 0.0f); - break; + return zero; case V22BIS_TX_TRAINING_STAGE_U11: /* Send continuous unscrambled ones at 1200bps (i.e. 270 degree phase steps). */ /* Only the answering modem sends unscrambled ones. It is the first thing exchanged between the modems. */ s->tx.constellation_state = (s->tx.constellation_state + phase_steps[3]) & 3; - z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; - break; + return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; case V22BIS_TX_TRAINING_STAGE_U0011: /* Continuous unscrambled double dibit 00 11 at 1200bps. This is termed the S1 segment in the V.22bis spec. It is only sent to request or accept 2400bps mode, and lasts 100+-3ms. After this timed burst, we unconditionally change to sending scrambled ones at 1200bps. */ s->tx.constellation_state = (s->tx.constellation_state + phase_steps[3*(s->tx.training_count & 1)]) & 3; - z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; if (++s->tx.training_count >= ms_to_symbols(100)) { span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 after U0011\n"); @@ -357,7 +354,7 @@ static complexf_t training_get(v22bis_state_t *s) s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11; } } - break; + return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; case V22BIS_TX_TRAINING_STAGE_TIMED_S11: /* A timed period of scrambled ones at 1200bps. */ if (++s->tx.training_count >= ms_to_symbols(756)) @@ -383,8 +380,7 @@ static complexf_t training_get(v22bis_state_t *s) bits = scramble(s, 1); bits = (bits << 1) | scramble(s, 1); s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3; - z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; - break; + return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; case V22BIS_TX_TRAINING_STAGE_S1111: /* Scrambled ones at 2400bps. We send a timed 200ms burst, and switch to normal operation at 2400bps */ bits = scramble(s, 1); @@ -392,7 +388,6 @@ static complexf_t training_get(v22bis_state_t *s) s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3; bits = scramble(s, 1); bits = (bits << 1) | scramble(s, 1); - z = v22bis_constellation[(s->tx.constellation_state << 2) | bits]; if (++s->tx.training_count >= ms_to_symbols(200)) { /* We have completed training. Now handle some real work. */ @@ -402,13 +397,9 @@ static complexf_t training_get(v22bis_state_t *s) v22bis_report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED); s->tx.current_get_bit = s->get_bit; } - break; - case V22BIS_TX_TRAINING_STAGE_PARKED: - default: - z = complex_setf(0.0f, 0.0f); - break; + return v22bis_constellation[(s->tx.constellation_state << 2) | bits]; } - return z; + return zero; } /*- End of function --------------------------------------------------------*/ @@ -476,12 +467,12 @@ SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len) x.im += tx_pulseshaper[39 - s->tx.baud_phase][i]*s->tx.rrc_filter[i + s->tx.rrc_filter_step].im; } /* Now create and modulate the carrier */ - z = dds_complexf(&(s->tx.carrier_phase), s->tx.carrier_phase_rate); + z = dds_complexf(&s->tx.carrier_phase, s->tx.carrier_phase_rate); famp = (x.re*z.re - x.im*z.im)*s->tx.gain; if (s->tx.guard_phase_rate && (s->tx.rrc_filter[s->tx.rrc_filter_step].re != 0.0f || s->tx.rrc_filter[s->tx.rrc_filter_step].im != 0.0f)) { /* Add the guard tone */ - famp += dds_modf(&(s->tx.guard_phase), s->tx.guard_phase_rate, s->tx.guard_level, 0); + famp += dds_modf(&s->tx.guard_phase, s->tx.guard_phase_rate, s->tx.guard_tone_gain, 0); } /* Don't bother saturating. We should never clip. */ amp[sample] = (int16_t) lfastrintf(famp); @@ -499,20 +490,20 @@ SPAN_DECLARE(void) v22bis_tx_power(v22bis_state_t *s, float power) l = 1.6f*powf(10.0f, (power - 1.0f - DBM0_MAX_POWER)/20.0f); s->tx.gain = l*32768.0f/(TX_PULSESHAPER_GAIN*3.0f); l = powf(10.0f, (power - 1.0f - 3.0f - DBM0_MAX_POWER)/20.0f); - s->tx.guard_level = l*32768.0f; + s->tx.guard_tone_gain = l*32768.0f; } else if(s->tx.guard_phase_rate == dds_phase_ratef(1800.0f)) { l = 1.6f*powf(10.0f, (power - 1.0f - 1.0f - DBM0_MAX_POWER)/20.0f); s->tx.gain = l*32768.0f/(TX_PULSESHAPER_GAIN*3.0f); l = powf(10.0f, (power - 1.0f - 6.0f - DBM0_MAX_POWER)/20.0f); - s->tx.guard_level = l*32768.0f; + s->tx.guard_tone_gain = l*32768.0f; } else { l = 1.6f*powf(10.0f, (power - DBM0_MAX_POWER)/20.0f); s->tx.gain = l*32768.0f/(TX_PULSESHAPER_GAIN*3.0f); - s->tx.guard_level = 0; + s->tx.guard_tone_gain = 0; } } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v8.c b/libs/spandsp/src/v8.c index 8ac13d3dd8..37ef368a44 100644 --- a/libs/spandsp/src/v8.c +++ b/libs/spandsp/src/v8.c @@ -63,7 +63,8 @@ enum { - V8_WAIT_1S, + V8_WAIT_1S, /* Start point when sending CI */ + V8_AWAIT_ANSAM, /* Start point when sending initial silence */ V8_CI_ON, V8_CI_OFF, V8_HEARD_ANSAM, @@ -100,7 +101,8 @@ enum enum { V8_CI_SYNC_OCTET = 0x00, - V8_CM_JM_SYNC_OCTET = 0xE0 + V8_CM_JM_SYNC_OCTET = 0xE0, + V8_V92_SYNC_OCTET = 0x55 }; SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function) @@ -755,7 +757,24 @@ SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len) } /*- End of function --------------------------------------------------------*/ -static void v8_send_ci(v8_state_t *s) +static void send_v92(v8_state_t *s) +{ + int i; + + if (s->result.v92 >= 0) + { + /* Send 2 V.92 packets */ + for (i = 0; i < 2; i++) + { + v8_put_preamble(s); + v8_put_byte(s, V8_V92_SYNC_OCTET); + v8_put_byte(s, s->result.v92); + } + } +} +/*- End of function --------------------------------------------------------*/ + +static void send_ci(v8_state_t *s) { int i; @@ -810,7 +829,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) if ((s->negotiation_timer -= len) > 0) break; fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); - v8_send_ci(s); + send_ci(s); s->state = V8_CI_ON; s->fsk_tx_on = TRUE; break; @@ -851,12 +870,18 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) { /* Try again */ fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); - v8_send_ci(s); + send_ci(s); s->state = V8_CI_ON; s->fsk_tx_on = TRUE; } } break; + case V8_AWAIT_ANSAM: + residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); + /* Check if an ANSam or ANSam/ tone has been detected */ + if ((tone = modem_connect_tones_rx_get(&s->ansam_rx)) != MODEM_CONNECT_TONES_NONE) + handle_modem_connect_tone(s, tone); + break; case V8_HEARD_ANSAM: /* We have heard the ANSam or ANSam/ signal, but we still need to wait for the end of the Te timeout period to comply with the spec. */ @@ -865,6 +890,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) v8_decode_init(s); s->negotiation_timer = ms_to_samples(5000); fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); + send_v92(s); send_cm_jm(s); s->state = V8_CM_ON; s->fsk_tx_on = TRUE; @@ -1015,9 +1041,16 @@ SPAN_DECLARE(int) v8_restart(v8_state_t *s, int calling_party, v8_parms_t *parms s->calling_party = calling_party; if (s->calling_party) { - s->state = V8_WAIT_1S; - s->negotiation_timer = ms_to_samples(1000); - s->ci_count = 0; + if (s->result.send_ci) + { + s->state = V8_WAIT_1S; + s->negotiation_timer = ms_to_samples(1000); + s->ci_count = 0; + } + else + { + s->state = V8_AWAIT_ANSAM; + } modem_connect_tones_rx_init(&s->ansam_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH1], get_bit, s); } diff --git a/libs/spandsp/src/vector_float.c b/libs/spandsp/src/vector_float.c index 7b5a7efa69..dd09e449e1 100644 --- a/libs/spandsp/src/vector_float.c +++ b/libs/spandsp/src/vector_float.c @@ -107,8 +107,8 @@ SPAN_DECLARE(void) vec_copyl(long double z[], const long double x[], int n) SPAN_DECLARE(void) vec_negatef(float z[], const float x[], int n) { int i; - static const uint32_t mask = 0x80000000; - static const float *fmask = (float *) &mask; + static const uint32_t mask = 0x80000000; + static const float *fmask = (float *) &mask; __m128 n1; __m128 n2; @@ -118,7 +118,7 @@ SPAN_DECLARE(void) vec_negatef(float z[], const float x[], int n) for (i -= 4; i >= 0; i -= 4) { n1 = _mm_loadu_ps(x + i); - n1 = _mm_xor_ps(n1, n2); + n1 = _mm_xor_ps(n1, n2); _mm_storeu_ps(z + i, n1); } } diff --git a/libs/spandsp/tests/fax_tester.h b/libs/spandsp/tests/fax_tester.h index 9735e0f2a5..3d64e2e6b7 100644 --- a/libs/spandsp/tests/fax_tester.h +++ b/libs/spandsp/tests/fax_tester.h @@ -37,7 +37,7 @@ typedef struct faxtester_state_s faxtester_state_t; -typedef void (faxtester_flush_handler_t)(faxtester_state_t *s, void *user_data, int which); +typedef void (*faxtester_flush_handler_t)(faxtester_state_t *s, void *user_data, int which); /*! FAX tester real time frame handler. @@ -48,13 +48,13 @@ typedef void (faxtester_flush_handler_t)(faxtester_state_t *s, void *user_data, \param msg The HDLC message. \param len The length of the message. */ -typedef void (faxtester_real_time_frame_handler_t)(faxtester_state_t *s, - void *user_data, - int direction, - const uint8_t *msg, - int len); +typedef void (*faxtester_real_time_frame_handler_t)(faxtester_state_t *s, + void *user_data, + int direction, + const uint8_t *msg, + int len); -typedef void (faxtester_front_end_step_complete_handler_t)(faxtester_state_t *s, void *user_data); +typedef void (*faxtester_front_end_step_complete_handler_t)(faxtester_state_t *s, void *user_data); /*! FAX tester descriptor. @@ -64,19 +64,19 @@ struct faxtester_state_s /*! \brief Pointer to our current step in the test. */ xmlNodePtr cur; - faxtester_flush_handler_t *flush_handler; + faxtester_flush_handler_t flush_handler; void *flush_user_data; /*! \brief A pointer to a callback routine to be called when frames are exchanged. */ - faxtester_real_time_frame_handler_t *real_time_frame_handler; + faxtester_real_time_frame_handler_t real_time_frame_handler; /*! \brief An opaque pointer supplied in real time frame callbacks. */ void *real_time_frame_user_data; - faxtester_front_end_step_complete_handler_t *front_end_step_complete_handler; + faxtester_front_end_step_complete_handler_t front_end_step_complete_handler; void *front_end_step_complete_user_data; - faxtester_front_end_step_complete_handler_t *front_end_step_timeout_handler; + faxtester_front_end_step_complete_handler_t front_end_step_timeout_handler; void *front_end_step_timeout_user_data; const uint8_t *image_buffer; @@ -149,7 +149,7 @@ void faxtester_send_hdlc_flags(faxtester_state_t *s, int flags); void faxtester_send_hdlc_msg(faxtester_state_t *s, const uint8_t *msg, int len, int crc_ok); -void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t *handler, void *user_data); +void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t handler, void *user_data); /*! Select whether silent audio will be sent when FAX transmit is idle. \brief Select whether silent audio will be sent when FAX transmit is idle. @@ -167,11 +167,11 @@ void faxtester_set_transmit_on_idle(faxtester_state_t *s, int transmit_on_idle); */ void faxtester_set_tep_mode(faxtester_state_t *s, int use_tep); -void faxtester_set_real_time_frame_handler(faxtester_state_t *s, faxtester_real_time_frame_handler_t *handler, void *user_data); +void faxtester_set_real_time_frame_handler(faxtester_state_t *s, faxtester_real_time_frame_handler_t handler, void *user_data); -void faxtester_set_front_end_step_complete_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t *handler, void *user_data); +void faxtester_set_front_end_step_complete_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data); -void faxtester_set_front_end_step_timeout_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t *handler, void *user_data); +void faxtester_set_front_end_step_timeout_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data); void faxtester_set_timeout(faxtester_state_t *s, int timeout); diff --git a/libs/spandsp/tests/udptl.h b/libs/spandsp/tests/udptl.h index 23563ad484..ae555cd500 100644 --- a/libs/spandsp/tests/udptl.h +++ b/libs/spandsp/tests/udptl.h @@ -31,7 +31,7 @@ #define UDPTL_BUF_MASK 15 -typedef int (udptl_rx_packet_handler_t) (void *user_data, const uint8_t msg[], int len, int seq_no); +typedef int (*udptl_rx_packet_handler_t) (void *user_data, const uint8_t msg[], int len, int seq_no); typedef struct { @@ -51,7 +51,7 @@ typedef struct struct udptl_state_s { - udptl_rx_packet_handler_t *rx_packet_handler; + udptl_rx_packet_handler_t rx_packet_handler; void *user_data; /*! This option indicates the error correction scheme used in transmitted UDPTL