diff --git a/libs/spandsp/src/async.c b/libs/spandsp/src/async.c index e24d84343b..518642111e 100644 --- a/libs/spandsp/src/async.c +++ b/libs/spandsp/src/async.c @@ -69,6 +69,12 @@ SPAN_DECLARE(const char *) signal_status_to_str(int status) return "Poor signal quality"; case SIG_STATUS_MODEM_RETRAIN_OCCURRED: return "Modem retrain occurred"; + case SIG_STATUS_LINK_CONNECTED: + return "Link connected"; + case SIG_STATUS_LINK_DISCONNECTED: + return "Link disconnected"; + case SIG_STATUS_LINK_ERROR: + return "Link error"; } return "???"; } diff --git a/libs/spandsp/src/dds_int.c b/libs/spandsp/src/dds_int.c index cf75ecc9c3..73eecb4077 100644 --- a/libs/spandsp/src/dds_int.c +++ b/libs/spandsp/src/dds_int.c @@ -56,7 +56,7 @@ /* This is a simple set of direct digital synthesis (DDS) functions to generate sine waves. This version uses a 128 entry sin/cos table to cover one quadrant. */ -static const int16_t sine_table[DDS_STEPS] = +static const int16_t sine_table[DDS_STEPS + 1] = { 201, 603, @@ -186,6 +186,7 @@ static const int16_t sine_table[DDS_STEPS] = 32753, 32762, 32767, + 32767 }; SPAN_DECLARE(int32_t) dds_phase_rate(float frequency) @@ -220,7 +221,7 @@ SPAN_DECLARE(int16_t) dds_lookup(uint32_t phase) phase >>= DDS_SHIFT; step = phase & (DDS_STEPS - 1); if ((phase & DDS_STEPS)) - step = (DDS_STEPS - 1) - step; + step = DDS_STEPS - step; amp = sine_table[step]; if ((phase & (2*DDS_STEPS))) amp = -amp; @@ -254,7 +255,7 @@ SPAN_DECLARE(int16_t) dds_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t s { int16_t amp; - amp = (int16_t) (((int32_t) dds_lookup(*phase_acc + phase)*(int32_t) scale) >> 15); + amp = (int16_t) (((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15); *phase_acc += phase_rate; return amp; } @@ -280,8 +281,8 @@ SPAN_DECLARE(complexi_t) dds_complexi_mod(uint32_t *phase_acc, int32_t phase_rat { complexi_t amp; - amp = complex_seti(((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*(int32_t) scale) >> 15, - ((int32_t) dds_lookup(*phase_acc + phase)*(int32_t) scale) >> 15); + amp = complex_seti(((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15, + ((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15); *phase_acc += phase_rate; return amp; } @@ -307,8 +308,8 @@ SPAN_DECLARE(complexi16_t) dds_complexi16_mod(uint32_t *phase_acc, int32_t phase { complexi16_t amp; - amp = complex_seti16((int16_t) (((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*(int32_t) scale) >> 15), - (int16_t) (((int32_t) dds_lookup(*phase_acc + phase)*(int32_t) scale) >> 15)); + amp = complex_seti16((int16_t) (((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15), + (int16_t) (((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15)); *phase_acc += phase_rate; return amp; } @@ -334,8 +335,8 @@ SPAN_DECLARE(complexi32_t) dds_complexi32_mod(uint32_t *phase_acc, int32_t phase { complexi32_t amp; - amp = complex_seti32(((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*(int32_t) scale) >> 15, - ((int32_t) dds_lookup(*phase_acc + phase)*(int32_t) scale) >> 15); + amp = complex_seti32(((int32_t) dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15, + ((int32_t) dds_lookup(*phase_acc + phase)*scale) >> 15); *phase_acc += phase_rate; return amp; } diff --git a/libs/spandsp/src/fsk.c b/libs/spandsp/src/fsk.c index 088c54bb88..19941637c0 100644 --- a/libs/spandsp/src/fsk.c +++ b/libs/spandsp/src/fsk.c @@ -220,7 +220,7 @@ SPAN_DECLARE(void) fsk_tx_set_get_bit(fsk_tx_state_t *s, get_bit_func_t get_bit, } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_tx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; @@ -248,7 +248,7 @@ SPAN_DECLARE(void) fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit, } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_tx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; diff --git a/libs/spandsp/src/gsm0610_preprocess.c b/libs/spandsp/src/gsm0610_preprocess.c index ea0edfd64e..d48d164f87 100644 --- a/libs/spandsp/src/gsm0610_preprocess.c +++ b/libs/spandsp/src/gsm0610_preprocess.c @@ -91,15 +91,16 @@ void gsm0610_preprocess(gsm0610_state_t *s, const int16_t amp[GSM0610_FRAME_LEN] /* 4.2.1 Downscaling of the input signal */ SO = (amp[k] >> 1) & ~3; - assert(SO >= -0x4000); // downscaled by - assert(SO <= 0x3FFC); // previous routine. + /* This is supposed to have been downscaled by previous routine. */ + assert(SO >= -0x4000); + assert(SO <= 0x3FFC); /* 4.2.2 Offset compensation */ /* This part implements a high-pass filter and requires extended arithmetic precision for the recursive part of this filter. The input of this procedure is the array so[0...159] and the - output the array sof[ 0...159 ]. + output the array sof[0...159]. */ /* Compute the non-recursive part */ s1 = SO - z1; diff --git a/libs/spandsp/src/hdlc.c b/libs/spandsp/src/hdlc.c index a07eb3e9fc..fc401fb5d1 100644 --- a/libs/spandsp/src/hdlc.c +++ b/libs/spandsp/src/hdlc.c @@ -332,7 +332,7 @@ SPAN_DECLARE(void) hdlc_rx_set_frame_handler(hdlc_rx_state_t *s, hdlc_frame_hand } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_rx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; diff --git a/libs/spandsp/src/image_translate.c b/libs/spandsp/src/image_translate.c index 9221a9afa7..1b14c2286c 100644 --- a/libs/spandsp/src/image_translate.c +++ b/libs/spandsp/src/image_translate.c @@ -146,12 +146,12 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t le int input_length; double c1; double c2; - double int_part; int x; #if defined(SPANDSP_USE_FIXED_POINT) int frac_row; int frac_col; #else + double int_part; double frac_row; double frac_col; #endif diff --git a/libs/spandsp/src/lpc10_decode.c b/libs/spandsp/src/lpc10_decode.c index bfb169edaa..3ccee7c18c 100644 --- a/libs/spandsp/src/lpc10_decode.c +++ b/libs/spandsp/src/lpc10_decode.c @@ -86,7 +86,7 @@ static __inline__ int32_t pow_ii(int32_t x, int32_t n) if (n == 0 || x == 1) return 1; if (x != -1) - return (x == 0) ? 1/x : 0; + return (x != 0) ? 1/x : 0; n = -n; } u = n; diff --git a/libs/spandsp/src/plc.c b/libs/spandsp/src/plc.c index 392a7b01a6..3d07417f68 100644 --- a/libs/spandsp/src/plc.c +++ b/libs/spandsp/src/plc.c @@ -165,10 +165,8 @@ SPAN_DECLARE(int) plc_fillin(plc_state_t *s, int16_t amp[], int len) float old_weight; float new_weight; float gain; - //int16_t *orig_amp; int orig_len; - //orig_amp = amp; orig_len = len; if (s->missing_samples == 0) { diff --git a/libs/spandsp/src/power_meter.c b/libs/spandsp/src/power_meter.c index fc752c3846..f4fb2afa8f 100644 --- a/libs/spandsp/src/power_meter.c +++ b/libs/spandsp/src/power_meter.c @@ -122,7 +122,7 @@ SPAN_DECLARE(float) power_meter_current_dbm0(power_meter_t *s) if (s->reading <= 0) return -96.329f + DBM0_MAX_POWER; /* This is based on A-law, but u-law is only 0.03dB different, so don't worry. */ - return log10f((float) s->reading/(32767.0f*32767.0f))*10.0f + DBM0_MAX_POWER; + return 10.0f*log10f((float) s->reading/(32767.0f*32767.0f) + 1.0e-10f) + DBM0_MAX_POWER; } /*- End of function --------------------------------------------------------*/ @@ -130,7 +130,7 @@ SPAN_DECLARE(float) power_meter_current_dbov(power_meter_t *s) { if (s->reading <= 0) return -96.329f; - return log10f((float) s->reading/(32767.0f*32767.0f))*10.0f; + return 10.0f*log10f((float) s->reading/(32767.0f*32767.0f) + 1.0e-10f); } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/silence_gen.c b/libs/spandsp/src/silence_gen.c index 96559d5d14..ad7d7caed0 100644 --- a/libs/spandsp/src/silence_gen.c +++ b/libs/spandsp/src/silence_gen.c @@ -108,7 +108,7 @@ SPAN_DECLARE(int) silence_gen_generated(silence_gen_state_t *s) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) silence_gen_status_handler(silence_gen_state_t *s, modem_tx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) silence_gen_status_handler(silence_gen_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; diff --git a/libs/spandsp/src/spandsp/arctan2.h b/libs/spandsp/src/spandsp/arctan2.h index 628a559987..321476715a 100644 --- a/libs/spandsp/src/spandsp/arctan2.h +++ b/libs/spandsp/src/spandsp/arctan2.h @@ -49,8 +49,18 @@ static __inline__ int32_t arctan2(float y, float x) float abs_y; float angle; - if (x == 0.0f || y == 0.0f) - return 0; + if (y == 0.0f) + { + if (x < 0.0f) + return 0x80000000; + return 0x00000000; + } + if (x == 0.0f) + { + if (y < 0.0f) + return 0xc0000000; + return 0x40000000; + } abs_y = fabsf(y); @@ -77,8 +87,18 @@ static __inline__ float arctan2f(float y, float x) float fx; float fy; - if (x == 0.0f || y == 0.0f) - return 0; + if (y == 0.0f) + { + if (x < 0.0f) + return 3.1415926f; + return 0.0f; + } + if (x == 0.0f) + { + if (y < 0.0f) + return 3.1415926f*1.5f; + return 3.1415926f*0.5f; + } fx = fabsf(x); fy = fabsf(y); /* Deal with the octants */ diff --git a/libs/spandsp/src/spandsp/async.h b/libs/spandsp/src/spandsp/async.h index 9c6c66cf8a..e0124e55c2 100644 --- a/libs/spandsp/src/spandsp/async.h +++ b/libs/spandsp/src/spandsp/async.h @@ -80,7 +80,13 @@ enum /*! \brief Notification that a modem has detected signal quality degradation. */ SIG_STATUS_POOR_SIGNAL_QUALITY = -12, /*! \brief Notification that a modem retrain has occurred. */ - SIG_STATUS_MODEM_RETRAIN_OCCURRED = -13 + SIG_STATUS_MODEM_RETRAIN_OCCURRED = -13, + /*! \brief The link protocol (e.g. V.42) has connected. */ + SIG_STATUS_LINK_CONNECTED = -14, + /*! \brief The link protocol (e.g. V.42) has disconnected. */ + SIG_STATUS_LINK_DISCONNECTED = -15, + /*! \brief An error has occurred in the link protocol (e.g. V.42). */ + SIG_STATUS_LINK_ERROR = -16 }; /*! Message put function for data pumps */ @@ -101,11 +107,8 @@ typedef void (*put_bit_func_t)(void *user_data, int bit); /*! Bit get function for data pumps */ typedef int (*get_bit_func_t)(void *user_data); -/*! Completion callback function for tx data pumps */ -typedef void (*modem_tx_status_func_t)(void *user_data, int status); - -/*! Completion callback function for rx data pumps */ -typedef void (*modem_rx_status_func_t)(void *user_data, int status); +/*! Status change callback function for data pumps */ +typedef void (*modem_status_func_t)(void *user_data, int status); enum { diff --git a/libs/spandsp/src/spandsp/bit_operations.h b/libs/spandsp/src/spandsp/bit_operations.h index df308d9ec2..8ce3c44430 100644 --- a/libs/spandsp/src/spandsp/bit_operations.h +++ b/libs/spandsp/src/spandsp/bit_operations.h @@ -225,7 +225,7 @@ SPAN_DECLARE(uint32_t) bit_reverse_4bytes(uint32_t data); SPAN_DECLARE(uint64_t) bit_reverse_8bytes(uint64_t data); #endif -/*! \brief Bit reverse each bytes in a buffer. +/*! \brief Bit reverse each byte in a buffer. \param to The buffer to place the reversed data in. \param from The buffer containing the data to be reversed. \param len The length of the data in the buffer. */ diff --git a/libs/spandsp/src/spandsp/complex.h b/libs/spandsp/src/spandsp/complex.h index 3bc8c5407d..af98c078d1 100644 --- a/libs/spandsp/src/spandsp/complex.h +++ b/libs/spandsp/src/spandsp/complex.h @@ -477,6 +477,12 @@ static __inline__ complexi32_t complex_conji32(const complexi32_t *x) } /*- End of function --------------------------------------------------------*/ +static __inline__ int32_t poweri16(const complexi16_t *x) +{ + return (int32_t) x->re*x->re + (int32_t) x->im*x->im; +} +/*- End of function --------------------------------------------------------*/ + static __inline__ float powerf(const complexf_t *x) { return x->re*x->re + x->im*x->im; diff --git a/libs/spandsp/src/spandsp/fsk.h b/libs/spandsp/src/spandsp/fsk.h index df6829514e..03082ce3d0 100644 --- a/libs/spandsp/src/spandsp/fsk.h +++ b/libs/spandsp/src/spandsp/fsk.h @@ -175,7 +175,7 @@ SPAN_DECLARE(void) fsk_tx_set_get_bit(fsk_tx_state_t *s, get_bit_func_t get_bit, \param s The modem context. \param handler The callback routine used to report modem status changes. \param user_data An opaque pointer. */ -SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_tx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_status_func_t handler, void *user_data); /*! Generate a block of FSK modem audio samples. \brief Generate a block of FSK modem audio samples. @@ -243,7 +243,7 @@ SPAN_DECLARE(void) fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit, \param s The modem context. \param handler The callback routine used to report modem status changes. \param user_data An opaque pointer. */ -SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_rx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_status_func_t handler, void *user_data); #if defined(__cplusplus) } diff --git a/libs/spandsp/src/spandsp/hdlc.h b/libs/spandsp/src/spandsp/hdlc.h index a6259a4544..ce37a701fc 100644 --- a/libs/spandsp/src/spandsp/hdlc.h +++ b/libs/spandsp/src/spandsp/hdlc.h @@ -113,7 +113,7 @@ SPAN_DECLARE(void) hdlc_rx_set_frame_handler(hdlc_rx_state_t *s, hdlc_frame_hand \param handler The callback routine used to report status changes. \param user_data An opaque parameter for the callback routine. */ -SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_rx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_status_func_t handler, void *user_data); /*! Release an HDLC receiver context. \brief Release an HDLC receiver context. diff --git a/libs/spandsp/src/spandsp/private/fsk.h b/libs/spandsp/src/spandsp/private/fsk.h index b08a9294fd..c1c1720157 100644 --- a/libs/spandsp/src/spandsp/private/fsk.h +++ b/libs/spandsp/src/spandsp/private/fsk.h @@ -39,7 +39,7 @@ struct fsk_tx_state_s void *get_bit_user_data; /*! \brief The callback function used to report modem status changes. */ - modem_tx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief A user specified opaque pointer passed to the status function. */ void *status_user_data; @@ -66,7 +66,7 @@ struct fsk_rx_state_s void *put_bit_user_data; /*! \brief The callback function used to report modem status changes. */ - modem_tx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief A user specified opaque pointer passed to the status function. */ void *status_user_data; diff --git a/libs/spandsp/src/spandsp/private/hdlc.h b/libs/spandsp/src/spandsp/private/hdlc.h index e58ef8720c..b5a677887d 100644 --- a/libs/spandsp/src/spandsp/private/hdlc.h +++ b/libs/spandsp/src/spandsp/private/hdlc.h @@ -40,7 +40,7 @@ struct hdlc_rx_state_s /*! \brief An opaque parameter passed to the frame callback routine. */ void *frame_user_data; /*! \brief The callback routine called to report status changes. */ - modem_rx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief An opaque parameter passed to the status callback routine. */ void *status_user_data; /*! \brief TRUE if bad frames are to be reported. */ diff --git a/libs/spandsp/src/spandsp/private/silence_gen.h b/libs/spandsp/src/spandsp/private/silence_gen.h index 6068c41171..695e472c3c 100644 --- a/libs/spandsp/src/spandsp/private/silence_gen.h +++ b/libs/spandsp/src/spandsp/private/silence_gen.h @@ -29,7 +29,7 @@ struct silence_gen_state_s { /*! \brief The callback function used to report status changes. */ - modem_tx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief A user specified opaque pointer passed to the status function. */ void *status_user_data; diff --git a/libs/spandsp/src/spandsp/private/v17rx.h b/libs/spandsp/src/spandsp/private/v17rx.h index 03b320c11b..da97bf05c7 100644 --- a/libs/spandsp/src/spandsp/private/v17rx.h +++ b/libs/spandsp/src/spandsp/private/v17rx.h @@ -61,7 +61,7 @@ struct v17_rx_state_s void *put_bit_user_data; /*! \brief The callback function used to report modem status changes. */ - modem_rx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief A user specified opaque pointer passed to the status function. */ void *status_user_data; diff --git a/libs/spandsp/src/spandsp/private/v17tx.h b/libs/spandsp/src/spandsp/private/v17tx.h index 4d4582f69d..07d29f6dd9 100644 --- a/libs/spandsp/src/spandsp/private/v17tx.h +++ b/libs/spandsp/src/spandsp/private/v17tx.h @@ -45,7 +45,7 @@ struct v17_tx_state_s void *get_bit_user_data; /*! \brief The callback function used to report modem status changes. */ - modem_tx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief A user specified opaque pointer passed to the status function. */ void *status_user_data; diff --git a/libs/spandsp/src/spandsp/private/v22bis.h b/libs/spandsp/src/spandsp/private/v22bis.h index 92317f6d72..d81bd039c5 100644 --- a/libs/spandsp/src/spandsp/private/v22bis.h +++ b/libs/spandsp/src/spandsp/private/v22bis.h @@ -84,7 +84,7 @@ struct v22bis_state_s /*! \brief A user specified opaque pointer passed to the put_bit callback routine. */ void *put_bit_user_data; /*! \brief The callback function used to report modem status changes. */ - modem_rx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief A user specified opaque pointer passed to the status function. */ void *status_user_data; diff --git a/libs/spandsp/src/spandsp/private/v27ter_rx.h b/libs/spandsp/src/spandsp/private/v27ter_rx.h index bc26c2d106..8ae99b4f81 100644 --- a/libs/spandsp/src/spandsp/private/v27ter_rx.h +++ b/libs/spandsp/src/spandsp/private/v27ter_rx.h @@ -58,7 +58,7 @@ struct v27ter_rx_state_s void *put_bit_user_data; /*! \brief The callback function used to report modem status changes. */ - modem_rx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief A user specified opaque pointer passed to the status function. */ void *status_user_data; diff --git a/libs/spandsp/src/spandsp/private/v27ter_tx.h b/libs/spandsp/src/spandsp/private/v27ter_tx.h index 12d77510d4..f9781aeb0f 100644 --- a/libs/spandsp/src/spandsp/private/v27ter_tx.h +++ b/libs/spandsp/src/spandsp/private/v27ter_tx.h @@ -43,7 +43,7 @@ struct v27ter_tx_state_s void *get_bit_user_data; /*! \brief The callback function used to report modem status changes. */ - modem_tx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief A user specified opaque pointer passed to the status function. */ void *status_user_data; diff --git a/libs/spandsp/src/spandsp/private/v29rx.h b/libs/spandsp/src/spandsp/private/v29rx.h index 3f6433bad9..ee7cd9932c 100644 --- a/libs/spandsp/src/spandsp/private/v29rx.h +++ b/libs/spandsp/src/spandsp/private/v29rx.h @@ -50,7 +50,7 @@ struct v29_rx_state_s void *put_bit_user_data; /*! \brief The callback function used to report modem status changes. */ - modem_rx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief A user specified opaque pointer passed to the status function. */ void *status_user_data; diff --git a/libs/spandsp/src/spandsp/private/v29tx.h b/libs/spandsp/src/spandsp/private/v29tx.h index bb95dba527..062ef7ee5c 100644 --- a/libs/spandsp/src/spandsp/private/v29tx.h +++ b/libs/spandsp/src/spandsp/private/v29tx.h @@ -43,7 +43,7 @@ struct v29_tx_state_s void *get_bit_user_data; /*! \brief The callback function used to report modem status changes. */ - modem_tx_status_func_t status_handler; + modem_status_func_t status_handler; /*! \brief A user specified opaque pointer passed to the status function. */ void *status_user_data; @@ -68,7 +68,7 @@ struct v29_tx_state_s int rrc_filter_step; /*! \brief The register for the data scrambler. */ - unsigned int scramble_reg; + uint32_t scramble_reg; /*! \brief The register for the training scrambler. */ uint8_t training_scramble_reg; /*! \brief TRUE if transmitting the training sequence, or shutting down transmission. diff --git a/libs/spandsp/src/spandsp/private/v42.h b/libs/spandsp/src/spandsp/private/v42.h index 0689c1d01a..b45b716349 100644 --- a/libs/spandsp/src/spandsp/private/v42.h +++ b/libs/spandsp/src/spandsp/private/v42.h @@ -5,7 +5,7 @@ * * Written by Steve Underwood * - * Copyright (C) 2003 Steve Underwood + * Copyright (C) 2003, 2011 Steve Underwood * * All rights reserved. * @@ -26,75 +26,94 @@ #if !defined(_SPANDSP_PRIVATE_V42_H_) #define _SPANDSP_PRIVATE_V42_H_ +/*! Max retries (9.2.2) */ +#define V42_DEFAULT_N_400 5 +/*! Default for max octets in an information field (9.2.3) */ +#define V42_DEFAULT_N_401 128 +/*! Maximum supported value for max octets in an information field */ +#define V42_MAX_N_401 128 +/*! Default window size (k) (9.2.4) */ +#define V42_DEFAULT_WINDOW_SIZE_K 15 +/*! Maximum supported window size (k) */ +#define V42_MAX_WINDOW_SIZE_K 15 + +/*! The number of info frames to allocate */ +#define V42_INFO_FRAMES (V42_MAX_WINDOW_SIZE_K + 1) +/*! The number of control frames to allocate */ +#define V42_CTRL_FRAMES 8 + +typedef struct +{ + /* V.42 LAP.M parameters */ + uint8_t v42_tx_window_size_k; + uint8_t v42_rx_window_size_k; + uint16_t v42_tx_n401; + uint16_t v42_rx_n401; + + /* V.42bis compressor parameters */ + uint8_t comp; + int comp_dict_size; + int comp_max_string; +} v42_config_parameters_t; + +typedef struct frame_s +{ + int len; + uint8_t buf[4 + V42_MAX_N_401]; +} v42_frame_t; + /*! LAP-M descriptor. This defines the working state for a single instance of LAP-M. */ -struct lapm_state_s +typedef struct { - int handle; + get_msg_func_t iframe_get; + void *iframe_get_user_data; + + put_msg_func_t iframe_put; + void *iframe_put_user_data; + + modem_status_func_t status_handler; + void *status_user_data; + hdlc_rx_state_t hdlc_rx; hdlc_tx_state_t hdlc_tx; - - v42_frame_handler_t iframe_receive; - void *iframe_receive_user_data; - v42_status_func_t status_callback; - void *status_callback_user_data; + /*! Negotiated values for the window and maximum info sizes */ + uint8_t tx_window_size_k; + uint8_t rx_window_size_k; + uint16_t tx_n401; + uint16_t rx_n401; + uint8_t cmd_addr; + uint8_t rsp_addr; + uint8_t vs; + uint8_t va; + uint8_t vr; int state; - int tx_waiting; - int debug; - /*! TRUE if originator. FALSE if answerer */ - int we_are_originator; - /*! Remote network type (unknown, answerer. originator) */ - int peer_is_originator; - /*! Next N(S) for transmission */ - int next_tx_frame; - /*! The last of our frames which the peer acknowledged */ - int last_frame_peer_acknowledged; - /*! Next N(R) for reception */ - int next_expected_frame; - /*! The last of the peer's frames which we acknowledged */ - int last_frame_we_acknowledged; - /*! TRUE if we sent an I or S frame with the F-bit set */ - int solicit_f_bit; - /*! Retransmission count */ - int retransmissions; - /*! TRUE if peer is busy */ - int busy; + int configuring; + int local_busy; + int far_busy; + int rejected; + int retry_count; - /*! Acknowledgement timer */ - int t401_timer; - /*! Reply delay timer - optional */ - int t402_timer; - /*! Inactivity timer - optional */ - int t403_timer; - /*! Maximum number of octets in an information field */ - int n401; - /*! Window size */ - int window_size_k; - - lapm_frame_queue_t *txqueue; - lapm_frame_queue_t *tx_next; - lapm_frame_queue_t *tx_last; - queue_state_t *tx_queue; - - span_sched_state_t sched; - /*! \brief Error and flow logging control */ - logging_state_t logging; -}; + /* The control frame buffer, and its pointers */ + int ctrl_put; + int ctrl_get; + v42_frame_t ctrl_buf[V42_CTRL_FRAMES]; -/*! - V.42 descriptor. This defines the working state for a single instance of V.42. -*/ -struct v42_state_s + /* The info frame buffer, and its pointers */ + int info_put; + int info_get; + int info_acked; + v42_frame_t info_buf[V42_INFO_FRAMES]; + + void (*packer_process)(v42_state_t *m, int bits); +} lapm_state_t; + +/*! V.42 support negotiation parameters */ +typedef struct { - /*! TRUE if we are the calling party, otherwise FALSE */ - int calling_party; - /*! TRUE if we should detect whether the far end is V.42 capable. FALSE if we go - directly to protocol establishment */ - int detect; - /*! Stage in negotiating V.42 support */ int rx_negotiation_step; int rxbits; @@ -104,11 +123,30 @@ struct v42_state_s int txbits; int txstream; int txadps; - /*! The LAP.M context */ +} v42_negotiation_t; + +/*! + V.42 descriptor. This defines the working state for a single + instance of a V.42 error corrector. +*/ +struct v42_state_s +{ + /*! TRUE if we are the calling party, otherwise FALSE. */ + int calling_party; + /*! TRUE if we should detect whether the far end is V.42 capable. FALSE if we go + directly to protocol establishment. */ + int detect; + + /*! The bit rate, used to time events */ + int tx_bit_rate; + + v42_config_parameters_t config; + v42_negotiation_t neg; lapm_state_t lapm; - /*! V.42 support detection timer */ - int t400_timer; + int bit_timer; + void (*bit_timer_func)(v42_state_t *m); + /*! \brief Error and flow logging control */ logging_state_t logging; }; diff --git a/libs/spandsp/src/spandsp/private/v42bis.h b/libs/spandsp/src/spandsp/private/v42bis.h index 287c26bd2c..2c801ebe24 100644 --- a/libs/spandsp/src/spandsp/private/v42bis.h +++ b/libs/spandsp/src/spandsp/private/v42bis.h @@ -28,100 +28,85 @@ /*! V.42bis dictionary node. + Note that 0 is not a valid node to point to (0 is always a control code), so 0 is used + as a "no such value" marker in this structure. */ typedef struct { - /*! \brief The prior code for each defined code. */ - uint16_t parent_code; - /*! \brief The number of leaf nodes this node has */ - int16_t leaves; - /*! \brief This leaf octet for each defined code. */ + /*! \brief The value of the octet represented by the current dictionary node */ uint8_t node_octet; - /*! \brief Bit map of the children which exist */ - uint32_t children[8]; + /*! \brief The parent of this node */ + uint16_t parent; + /*! \brief The first child of this node */ + uint16_t child; + /*! \brief The next node at the same depth */ + uint16_t next; } v42bis_dict_node_t; /*! - V.42bis compression. This defines the working state for a single instance - of V.42bis compression. + V.42bis compression or decompression. This defines the working state for a single instance + of V.42bis compression or decompression. */ typedef struct { + /*! \brief Compression enabled. */ + int v42bis_parm_p0; /*! \brief Compression mode. */ int compression_mode; - /*! \brief Callback function to handle received frames. */ - v42bis_frame_handler_t handler; - /*! \brief An opaque pointer passed in calls to frame_handler. */ + /*! \brief Callback function to handle output data. */ + put_msg_func_t handler; + /*! \brief An opaque pointer passed in calls to the data handler. */ void *user_data; - /*! \brief The maximum frame length allowed */ - int max_len; + /*! \brief The maximum amount to be passed to the data handler. */ + int max_output_len; - uint32_t string_code; - uint32_t latest_code; + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + /*! \brief Next empty dictionary entry */ + uint16_t v42bis_parm_c1; + /*! \brief Current codeword size */ + uint16_t v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint16_t v42bis_parm_c3; + /*! \brief The current update point in the dictionary */ + uint16_t update_at; + /*! \brief The last entry matched in the dictionary */ + uint16_t last_matched; + /*! \brief The last entry added to the dictionary */ + uint16_t last_added; + /*! \brief Total number of codewords in the dictionary */ + int v42bis_parm_n2; + /*! \brief Maximum permitted string length */ + int v42bis_parm_n7; + /*! \brief The dictionary */ + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + + /*! \brief The octet string in progress */ + uint8_t string[V42BIS_MAX_STRING_SIZE]; + /*! \brief The current length of the octet string in progress */ int string_length; - uint32_t output_bit_buffer; - int output_bit_count; + /*! \brief The amount of the octet string in progress which has already + been flushed out of the buffer */ + int flushed_length; + + /*! \brief Compression performance metric */ + uint16_t compression_performance; + + /*! \brief Outgoing bit buffer (compression), or incoming bit buffer (decompression) */ + uint32_t bit_buffer; + /*! \brief Outgoing bit count (compression), or incoming bit count (decompression) */ + int bit_count; + + /*! \brief The output composition buffer */ + uint8_t output_buf[V42BIS_MAX_OUTPUT_LENGTH]; + /*! \brief The length of the contents of the output composition buffer */ int output_octet_count; - uint8_t output_buf[1024]; - v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; - /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ - int transparent; - int change_transparency; - /*! \brief IIR filter state, used in assessing compressibility. */ - int compressibility_filter; - int compressibility_persistence; - - /*! \brief Next empty dictionary entry */ - uint32_t v42bis_parm_c1; - /*! \brief Current codeword size */ - int v42bis_parm_c2; - /*! \brief Threshold for codeword size change */ - uint32_t v42bis_parm_c3; - /*! \brief Mark that this is the first octet/code to be processed */ - int first; - uint8_t escape_code; -} v42bis_compress_state_t; - -/*! - V.42bis decompression. This defines the working state for a single instance - of V.42bis decompression. -*/ -typedef struct -{ - /*! \brief Callback function to handle decompressed data. */ - v42bis_data_handler_t handler; - /*! \brief An opaque pointer passed in calls to data_handler. */ - void *user_data; - /*! \brief The maximum decompressed data block length allowed */ - int max_len; - - uint32_t old_code; - uint32_t last_old_code; - uint32_t input_bit_buffer; - int input_bit_count; - int octet; - int last_length; - int output_octet_count; - uint8_t output_buf[1024]; - v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; - /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ - int transparent; - - int last_extra_octet; - - /*! \brief Next empty dictionary entry */ - uint32_t v42bis_parm_c1; - /*! \brief Current codeword size */ - int v42bis_parm_c2; - /*! \brief Threshold for codeword size change */ - uint32_t v42bis_parm_c3; - - /*! \brief Mark that this is the first octet/code to be processed */ - int first; + /*! \brief The current value of the escape code */ uint8_t escape_code; + /*! \brief TRUE if we just hit an escape code, and are waiting for the following octet */ int escaped; -} v42bis_decompress_state_t; +} v42bis_comp_state_t; /*! V.42bis compression/decompression descriptor. This defines the working state for a @@ -129,20 +114,13 @@ typedef struct */ struct v42bis_state_s { - /*! \brief V.42bis data compression directions. */ - int v42bis_parm_p0; - /*! \brief Compression state. */ - v42bis_compress_state_t compress; + v42bis_comp_state_t compress; /*! \brief Decompression state. */ - v42bis_decompress_state_t decompress; - - /*! \brief Maximum codeword size (bits) */ - int v42bis_parm_n1; - /*! \brief Total number of codewords */ - uint32_t v42bis_parm_n2; - /*! \brief Maximum string length */ - int v42bis_parm_n7; + v42bis_comp_state_t decompress; + + /*! \brief Error and flow logging control */ + logging_state_t logging; }; #endif diff --git a/libs/spandsp/src/spandsp/silence_gen.h b/libs/spandsp/src/spandsp/silence_gen.h index c2300c845c..df90ec0e9e 100644 --- a/libs/spandsp/src/spandsp/silence_gen.h +++ b/libs/spandsp/src/spandsp/silence_gen.h @@ -84,7 +84,7 @@ SPAN_DECLARE(int) silence_gen_generated(silence_gen_state_t *s); \param s The silence generator context. \param handler The callback routine used to report status changes. \param user_data An opaque pointer. */ -SPAN_DECLARE(void) silence_gen_status_handler(silence_gen_state_t *s, modem_tx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) silence_gen_status_handler(silence_gen_state_t *s, modem_status_func_t handler, void *user_data); /*! Initialise a timed silence generator context. \brief Initialise a timed silence generator context. diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h index a2fff2d28c..6fde8caf48 100644 --- a/libs/spandsp/src/spandsp/t30.h +++ b/libs/spandsp/src/spandsp/t30.h @@ -261,7 +261,7 @@ enum T30_ERR_RX_GOTDCS, /*! DCS received while waiting for DTC */ T30_ERR_RX_INVALCMD, /*! Unexpected command after page received */ T30_ERR_RX_NOCARRIER, /*! Carrier lost during fax receive */ - T30_ERR_RX_NOEOL, /*! Timed out while waiting for EOL (end Of line) */ + T30_ERR_RX_NOEOL, /*! Timed out while waiting for EOL (end of line) */ T30_ERR_RX_NOFAX, /*! Timed out while waiting for first line */ T30_ERR_RX_T2EXPDCN, /*! Timer T2 expired while waiting for DCN */ T30_ERR_RX_T2EXPD, /*! Timer T2 expired while waiting for phase D */ diff --git a/libs/spandsp/src/spandsp/telephony.h b/libs/spandsp/src/spandsp/telephony.h index f6998e09f5..49d7200e83 100644 --- a/libs/spandsp/src/spandsp/telephony.h +++ b/libs/spandsp/src/spandsp/telephony.h @@ -77,6 +77,27 @@ typedef int (span_tx_handler_t)(void *s, int16_t amp[], int max_len); #define TRUE (!FALSE) #endif +/* Fixed point constant macros */ +#define FP_Q_9_7(x) ((int16_t) (128.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_8_8(x) ((int16_t) (256.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_7_9(x) ((int16_t) (512.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_6_10(x) ((int16_t) (1024.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_5_11(x) ((int16_t) (2048.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_4_12(x) ((int16_t) (4096.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_3_13(x) ((int16_t) (8192.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_2_14(x) ((int16_t) (16384.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_1_15(x) ((int16_t) (32768.0*x + ((x >= 0.0) ? 0.5 : -0.5))) + +#define FP_Q_9_23(x) ((int32_t) (65536.0*128.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_8_24(x) ((int32_t) (65536.0*256.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_7_25(x) ((int32_t) (65536.0*512.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_6_26(x) ((int32_t) (65536.0*1024.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_5_27(x) ((int32_t) (65536.0*2048.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_4_28(x) ((int32_t) (65536.0*4096.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_3_29(x) ((int32_t) (65536.0*8192.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_2_30(x) ((int32_t) (65536.0*16384.0*x + ((x >= 0.0) ? 0.5 : -0.5))) +#define FP_Q_1_31(x) ((int32_t) (65536.0*32768.0*x + ((x >= 0.0) ? 0.5 : -0.5))) + #if defined(__cplusplus) /* C++ doesn't seem to have sane rounding functions/macros yet */ #if !defined(WIN32) diff --git a/libs/spandsp/src/spandsp/v17rx.h b/libs/spandsp/src/spandsp/v17rx.h index 164fa25232..d6ac46caa1 100644 --- a/libs/spandsp/src/spandsp/v17rx.h +++ b/libs/spandsp/src/spandsp/v17rx.h @@ -267,7 +267,7 @@ SPAN_DECLARE(void) v17_rx_set_put_bit(v17_rx_state_t *s, put_bit_func_t put_bit, \param s The modem context. \param handler The callback routine used to report modem status changes. \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_rx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_status_func_t handler, void *user_data); /*! Process a block of received V.17 modem audio samples. \brief Process a block of received V.17 modem audio samples. diff --git a/libs/spandsp/src/spandsp/v17tx.h b/libs/spandsp/src/spandsp/v17tx.h index e288817e7a..91fd595149 100644 --- a/libs/spandsp/src/spandsp/v17tx.h +++ b/libs/spandsp/src/spandsp/v17tx.h @@ -146,7 +146,7 @@ SPAN_DECLARE(void) v17_tx_set_get_bit(v17_tx_state_t *s, get_bit_func_t get_bit, \param s The modem context. \param handler The callback routine used to report modem status changes. \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_tx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_status_func_t handler, void *user_data); /*! Generate a block of V.17 modem audio samples. \brief Generate a block of V.17 modem audio samples. diff --git a/libs/spandsp/src/spandsp/v22bis.h b/libs/spandsp/src/spandsp/v22bis.h index 5bdc1791a3..073fb7135a 100644 --- a/libs/spandsp/src/spandsp/v22bis.h +++ b/libs/spandsp/src/spandsp/v22bis.h @@ -213,7 +213,7 @@ SPAN_DECLARE(void) v22bis_set_put_bit(v22bis_state_t *s, put_bit_func_t put_bit, \param s The modem context. \param handler The callback routine used to report modem status changes. \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_rx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_status_func_t handler, void *user_data); #if defined(__cplusplus) } diff --git a/libs/spandsp/src/spandsp/v27ter_rx.h b/libs/spandsp/src/spandsp/v27ter_rx.h index baa04b54fe..bb12801b50 100644 --- a/libs/spandsp/src/spandsp/v27ter_rx.h +++ b/libs/spandsp/src/spandsp/v27ter_rx.h @@ -102,7 +102,7 @@ SPAN_DECLARE(void) v27ter_rx_set_put_bit(v27ter_rx_state_t *s, put_bit_func_t pu \param s The modem context. \param handler The callback routine used to report modem status changes. \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_rx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_status_func_t handler, void *user_data); /*! Process a block of received V.27ter modem audio samples. \brief Process a block of received V.27ter modem audio samples. diff --git a/libs/spandsp/src/spandsp/v27ter_tx.h b/libs/spandsp/src/spandsp/v27ter_tx.h index ce5f440272..8a04e2018c 100644 --- a/libs/spandsp/src/spandsp/v27ter_tx.h +++ b/libs/spandsp/src/spandsp/v27ter_tx.h @@ -127,7 +127,7 @@ SPAN_DECLARE(void) v27ter_tx_set_get_bit(v27ter_tx_state_t *s, get_bit_func_t ge \param s The modem context. \param handler The callback routine used to report modem status changes. \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_tx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_status_func_t handler, void *user_data); /*! Generate a block of V.27ter modem audio samples. \brief Generate a block of V.27ter modem audio samples. diff --git a/libs/spandsp/src/spandsp/v29rx.h b/libs/spandsp/src/spandsp/v29rx.h index dc8c7b4367..d7874b68dc 100644 --- a/libs/spandsp/src/spandsp/v29rx.h +++ b/libs/spandsp/src/spandsp/v29rx.h @@ -178,7 +178,7 @@ SPAN_DECLARE(void) v29_rx_set_put_bit(v29_rx_state_t *s, put_bit_func_t put_bit, \param s The modem context. \param handler The callback routine used to report modem status changes. \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_rx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_status_func_t handler, void *user_data); /*! Process a block of received V.29 modem audio samples. \brief Process a block of received V.29 modem audio samples. diff --git a/libs/spandsp/src/spandsp/v29tx.h b/libs/spandsp/src/spandsp/v29tx.h index 8a765445c2..3cb14fea94 100644 --- a/libs/spandsp/src/spandsp/v29tx.h +++ b/libs/spandsp/src/spandsp/v29tx.h @@ -158,7 +158,7 @@ SPAN_DECLARE(void) v29_tx_set_get_bit(v29_tx_state_t *s, get_bit_func_t get_bit, \param s The modem context. \param handler The callback routine used to report modem status changes. \param user_data An opaque pointer. */ -SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_tx_status_func_t handler, void *user_data); +SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_status_func_t handler, void *user_data); /*! Generate a block of V.29 modem audio samples. \brief Generate a block of V.29 modem audio samples. diff --git a/libs/spandsp/src/spandsp/v42.h b/libs/spandsp/src/spandsp/v42.h index 22d6122b60..0341c28a03 100644 --- a/libs/spandsp/src/spandsp/v42.h +++ b/libs/spandsp/src/spandsp/v42.h @@ -5,7 +5,7 @@ * * Written by Steve Underwood * - * Copyright (C) 2003 Steve Underwood + * Copyright (C) 2003, 2011 Steve Underwood * * All rights reserved. * @@ -36,45 +36,8 @@ far modem supports V.42 is also defined. #if !defined(_SPANDSP_V42_H_) #define _SPANDSP_V42_H_ -enum -{ - LAPM_DETECT = 0, - LAPM_ESTABLISH = 1, - LAPM_DATA = 2, - LAPM_RELEASE = 3, - LAPM_SIGNAL = 4, - LAPM_SETPARM = 5, - LAPM_TEST = 6, - LAPM_UNSUPPORTED = 7 -}; - -typedef void (*v42_status_func_t)(void *user_data, int status); -typedef void (*v42_frame_handler_t)(void *user_data, const uint8_t *pkt, int len); - -typedef struct lapm_frame_queue_s -{ - struct lapm_frame_queue_s *next; - int len; - uint8_t frame[]; -} lapm_frame_queue_t; - -/*! - LAP-M descriptor. This defines the working state for a single instance of LAP-M. -*/ -typedef struct lapm_state_s lapm_state_t; - -/*! - V.42 descriptor. This defines the working state for a single instance of V.42. -*/ typedef struct v42_state_s v42_state_t; -/*! Log the raw HDLC frames */ -#define LAPM_DEBUG_LAPM_RAW (1 << 0) -/*! Log the interpreted frames */ -#define LAPM_DEBUG_LAPM_DUMP (1 << 1) -/*! Log state machine changes */ -#define LAPM_DEBUG_LAPM_STATE (1 << 2) - #if defined(__cplusplus) extern "C" { @@ -82,58 +45,46 @@ extern "C" SPAN_DECLARE(const char *) lapm_status_to_str(int status); -/*! Dump LAP.M frames in a raw and/or decoded forms - \param frame The frame itself - \param len The length of the frame, in octets - \param showraw TRUE if the raw octets should be dumped - \param txrx TRUE if tx, FALSE if rx. Used to highlight the packet's direction. -*/ -SPAN_DECLARE(void) lapm_dump(lapm_state_t *s, const uint8_t *frame, int len, int showraw, int txrx); +SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok); -/*! Accept an HDLC packet -*/ -SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *buf, int len, int ok); +SPAN_DECLARE(void) v42_start(v42_state_t *s); -/*! Transmit a LAP.M frame -*/ -SPAN_DECLARE(int) lapm_tx(lapm_state_t *s, const void *buf, int len); +SPAN_DECLARE(void) v42_stop(v42_state_t *s); -/*! Transmit a LAP.M information frame +/*! Set the busy status of the local end of a V.42 context. + \param s The V.42 context. + \param busy The new local end busy status. + \return The previous local end busy status. */ -SPAN_DECLARE(int) lapm_tx_iframe(lapm_state_t *s, const void *buf, int len, int cr); +SPAN_DECLARE(int) v42_set_local_busy_status(v42_state_t *s, int busy); -/*! Send a break over a LAP.M connection +/*! Get the busy status of the far end of a V.42 context. + \param s The V.42 context. + \return The far end busy status. */ -SPAN_DECLARE(int) lapm_break(lapm_state_t *s, int enable); +SPAN_DECLARE(int) v42_get_far_busy_status(v42_state_t *s); -/*! Initiate an orderly release of a LAP.M connection -*/ -SPAN_DECLARE(int) lapm_release(lapm_state_t *s); - -/*! Enable or disable loopback of a LAP.M connection -*/ -SPAN_DECLARE(int) lapm_loopback(lapm_state_t *s, int enable); - -/*! Assign or remove a callback routine used to deal with V.42 status changes. -*/ -SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, v42_status_func_t callback, void *user_data); - -/*! Process a newly received bit for a V.42 context. -*/ SPAN_DECLARE(void) v42_rx_bit(void *user_data, int bit); -/*! Get the next transmit bit for a V.42 context. -*/ SPAN_DECLARE(int) v42_tx_bit(void *user_data); +SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, modem_status_func_t callback, void *user_data); + /*! Initialise a V.42 context. \param s The V.42 context. \param calling_party TRUE if caller mode, else answerer mode. - \param frame_handler A callback function to handle received frames of data. - \param user_data An opaque pointer passed to the frame handler routine. + \param detect TRUE to perform the V.42 detection, else go straight into LAP.M + \param iframe_get A callback function to handle received frames of data. + \param iframe_put A callback function to get frames of data for transmission. + \param user_data An opaque pointer passed to the frame handler routines. \return ??? */ -SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int calling_party, int detect, v42_frame_handler_t frame_handler, void *user_data); +SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, + int calling_party, + int detect, + get_msg_func_t iframe_get, + put_msg_func_t iframe_put, + void *user_data); /*! Restart a V.42 context. \param s The V.42 context. @@ -143,12 +94,12 @@ SPAN_DECLARE(void) v42_restart(v42_state_t *s); /*! Release a V.42 context. \param s The V.42 context. \return 0 if OK */ -SPAN_DECLARE(int) v42_release(v42_state_t *s); +SPAN_DECLARE(void) v42_release(v42_state_t *s); /*! Free a V.42 context. \param s The V.42 context. \return 0 if OK */ -SPAN_DECLARE(int) v42_free(v42_state_t *s); +SPAN_DECLARE(void) v42_free(v42_state_t *s); #if defined(__cplusplus) } diff --git a/libs/spandsp/src/spandsp/v42bis.h b/libs/spandsp/src/spandsp/v42bis.h index 35d5be3f42..b947a61cd3 100644 --- a/libs/spandsp/src/spandsp/v42bis.h +++ b/libs/spandsp/src/spandsp/v42bis.h @@ -5,7 +5,7 @@ * * Written by Steve Underwood * - * Copyright (C) 2005 Steve Underwood + * Copyright (C) 2005, 2011 Steve Underwood * * All rights reserved. * @@ -39,7 +39,7 @@ conjunction with the error correction scheme defined in V.42. #define V42BIS_MIN_DICTIONARY_SIZE 512 #define V42BIS_MAX_BITS 12 #define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ -#define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */ +#define V42BIS_MAX_OUTPUT_LENGTH 1024 enum { @@ -56,9 +56,6 @@ enum V42BIS_COMPRESSION_MODE_NEVER }; -typedef void (*v42bis_frame_handler_t)(void *user_data, const uint8_t *pkt, int len); -typedef void (*v42bis_data_handler_t)(void *user_data, const uint8_t *buf, int len); - /*! V.42bis compression/decompression descriptor. This defines the working state for a single instance of V.42bis compress/decompression. @@ -75,7 +72,7 @@ extern "C" \param buf The data to be compressed. \param len The length of the data buffer. \return 0 */ -SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len); +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t buf[], int len); /*! Flush out any data remaining in a compression buffer. \param s The V.42bis context. @@ -87,7 +84,7 @@ SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s); \param buf The data to be decompressed. \param len The length of the data buffer. \return 0 */ -SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len); +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t buf[], int len); /*! Flush out any data remaining in the decompression buffer. \param s The V.42bis context. @@ -107,23 +104,23 @@ SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode); \param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec. \param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec. \param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec. - \param frame_handler Frame callback handler. - \param frame_user_data An opaque pointer passed to the frame callback handler. - \param max_frame_len The maximum length that should be passed to the frame handler. - \param data_handler data callback handler. - \param data_user_data An opaque pointer passed to the data callback handler. - \param max_data_len The maximum length that should be passed to the data handler. + \param encode_handler Encode callback handler. + \param encode_user_data An opaque pointer passed to the encode callback handler. + \param max_encode_len The maximum length that should be passed to the encode handler. + \param decode_handler Decode callback handler. + \param decode_user_data An opaque pointer passed to the decode callback handler. + \param max_decode_len The maximum length that should be passed to the decode handler. \return The V.42bis context. */ SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, - v42bis_frame_handler_t frame_handler, - void *frame_user_data, - int max_frame_len, - v42bis_data_handler_t data_handler, - void *data_user_data, - int max_data_len); + put_msg_func_t encode_handler, + void *encode_user_data, + int max_encode_len, + put_msg_func_t decode_handler, + void *decode_user_data, + int max_decode_len); /*! Release a V.42bis context. \param s The V.42bis context. diff --git a/libs/spandsp/src/timezone.c b/libs/spandsp/src/timezone.c index b991531e69..04dfa51daf 100644 --- a/libs/spandsp/src/timezone.c +++ b/libs/spandsp/src/timezone.c @@ -114,11 +114,11 @@ static const int year_lengths[2] = static int increment_overflow(int *number, int delta) { - int number0; + int last_number; - number0 = *number; + last_number = *number; *number += delta; - return (*number < number0) != (delta < 0); + return (*number < last_number) != (delta < 0); } /*- End of function --------------------------------------------------------*/ @@ -164,6 +164,10 @@ static struct tm *time_sub(const time_t * const timep, const long int offset, co int y; int hit; int i; + int newy; + time_t tdelta; + int idelta; + int leapdays; corr = 0; hit = 0; @@ -198,11 +202,6 @@ static struct tm *time_sub(const time_t * const timep, const long int offset, co rem = *timep - tdays*SECS_PER_DAY; while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { - int newy; - time_t tdelta; - int idelta; - int leapdays; - tdelta = tdays / DAYS_PER_LEAP_YEAR; idelta = tdelta; if (tdelta - idelta >= 1 || idelta - tdelta >= 1) diff --git a/libs/spandsp/src/v17rx.c b/libs/spandsp/src/v17rx.c index 974448b46a..3fac6a00ad 100644 --- a/libs/spandsp/src/v17rx.c +++ b/libs/spandsp/src/v17rx.c @@ -1248,7 +1248,7 @@ SPAN_DECLARE(void) v17_rx_set_put_bit(v17_rx_state_t *s, put_bit_func_t put_bit, } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_tx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; diff --git a/libs/spandsp/src/v17tx.c b/libs/spandsp/src/v17tx.c index 8cce8940e9..0e4f603c0b 100644 --- a/libs/spandsp/src/v17tx.c +++ b/libs/spandsp/src/v17tx.c @@ -364,7 +364,7 @@ SPAN_DECLARE(void) v17_tx_set_get_bit(v17_tx_state_t *s, get_bit_func_t get_bit, } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_tx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; diff --git a/libs/spandsp/src/v22bis_tx.c b/libs/spandsp/src/v22bis_tx.c index 5619e87120..39ad4dd240 100644 --- a/libs/spandsp/src/v22bis_tx.c +++ b/libs/spandsp/src/v22bis_tx.c @@ -552,7 +552,7 @@ SPAN_DECLARE(void) v22bis_set_put_bit(v22bis_state_t *s, put_bit_func_t put_bit, } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_tx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; diff --git a/libs/spandsp/src/v27ter_rx.c b/libs/spandsp/src/v27ter_rx.c index 8685ef1d77..22ce185408 100644 --- a/libs/spandsp/src/v27ter_rx.c +++ b/libs/spandsp/src/v27ter_rx.c @@ -1019,7 +1019,7 @@ SPAN_DECLARE(void) v27ter_rx_set_put_bit(v27ter_rx_state_t *s, put_bit_func_t pu } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_tx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; diff --git a/libs/spandsp/src/v27ter_tx.c b/libs/spandsp/src/v27ter_tx.c index 5f35510231..bff8bb7071 100644 --- a/libs/spandsp/src/v27ter_tx.c +++ b/libs/spandsp/src/v27ter_tx.c @@ -374,7 +374,7 @@ SPAN_DECLARE(void) v27ter_tx_set_get_bit(v27ter_tx_state_t *s, get_bit_func_t ge } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_tx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; diff --git a/libs/spandsp/src/v29rx.c b/libs/spandsp/src/v29rx.c index 17ddada9e8..a94af80574 100644 --- a/libs/spandsp/src/v29rx.c +++ b/libs/spandsp/src/v29rx.c @@ -1052,7 +1052,7 @@ SPAN_DECLARE(void) v29_rx_set_put_bit(v29_rx_state_t *s, put_bit_func_t put_bit, } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_tx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; diff --git a/libs/spandsp/src/v29tx.c b/libs/spandsp/src/v29tx.c index 39c6c99b9a..10007a93fb 100644 --- a/libs/spandsp/src/v29tx.c +++ b/libs/spandsp/src/v29tx.c @@ -316,7 +316,7 @@ SPAN_DECLARE(void) v29_tx_set_get_bit(v29_tx_state_t *s, get_bit_func_t get_bit, } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_tx_status_func_t handler, void *user_data) +SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_status_func_t handler, void *user_data) { s->status_handler = handler; s->status_user_data = user_data; diff --git a/libs/spandsp/src/v42.c b/libs/spandsp/src/v42.c index 74630ee84d..7aea3f2116 100644 --- a/libs/spandsp/src/v42.c +++ b/libs/spandsp/src/v42.c @@ -5,7 +5,7 @@ * * Written by Steve Underwood * - * Copyright (C) 2004 Steve Underwood + * Copyright (C) 2004, 2011 Steve Underwood * * All rights reserved. * @@ -36,323 +36,125 @@ #include #include #include +#include +#include +#include #include "spandsp/telephony.h" #include "spandsp/logging.h" +#include "spandsp/bit_operations.h" #include "spandsp/async.h" #include "spandsp/hdlc.h" -#include "spandsp/schedule.h" -#include "spandsp/queue.h" #include "spandsp/v42.h" #include "spandsp/private/logging.h" -#include "spandsp/private/schedule.h" #include "spandsp/private/hdlc.h" #include "spandsp/private/v42.h" -#if !defined(FALSE) -#define FALSE 0 -#endif -#if !defined(TRUE) -#define TRUE (!FALSE) -#endif +#define FALSE 0 +#define TRUE (!FALSE) -#define LAPM_FRAMETYPE_MASK 0x03 - -#define LAPM_FRAMETYPE_I 0x00 -#define LAPM_FRAMETYPE_I_ALT 0x02 -#define LAPM_FRAMETYPE_S 0x01 -#define LAPM_FRAMETYPE_U 0x03 - -/* Timer values */ - -#define T_WAIT_MIN 2000 -#define T_WAIT_MAX 10000 /* Detection phase timer */ -#define T_400 750000 +#define T_400 750 /* Acknowledgement timer - 1 second between SABME's */ -#define T_401 1000000 +#define T_401 1000 /* Replay delay timer (optional) */ -#define T_402 1000000 +#define T_402 1000 /* Inactivity timer (optional). No default - use 10 seconds with no packets */ -#define T_403 10000000 -/* Max retries */ -#define N_400 3 -/* Max octets in an information field */ -#define N_401 128 +#define T_403 10000 -#define LAPM_DLCI_DTE_TO_DTE 0 -#define LAPM_DLCI_LAYER2_MANAGEMENT 63 +#define LAPM_DLCI_DTE_TO_DTE 0 +#define LAPM_DLCI_LAYER2_MANAGEMENT 63 -static void t401_expired(span_sched_state_t *s, void *user_data); -static void t403_expired(span_sched_state_t *s, void *user_data); +#define elements(a) (sizeof(a)/sizeof((a)[0])) -SPAN_DECLARE(void) lapm_reset(lapm_state_t *s); -SPAN_DECLARE(void) lapm_restart(lapm_state_t *s); +/* LAPM definitions */ -static void lapm_link_down(lapm_state_t *s); +#define LAPM_FRAMETYPE_MASK 0x03 -static __inline__ void lapm_init_header(uint8_t *frame, int command) +enum { - /* Data link connection identifier (0) */ - /* Command/response (0 if answerer, 1 if originator) */ - /* Extended address (1) */ - frame[0] = (LAPM_DLCI_DTE_TO_DTE << 2) | ((command) ? 0x02 : 0x00) | 0x01; -} -/*- End of function --------------------------------------------------------*/ + LAPM_FRAMETYPE_I = 0x00, + LAPM_FRAMETYPE_I_ALT = 0x02, + LAPM_FRAMETYPE_S = 0x01, + LAPM_FRAMETYPE_U = 0x03 +}; -static int lapm_tx_frame(lapm_state_t *s, uint8_t *frame, int len) +/* Supervisory headers */ +enum { - if ((s->debug & LAPM_DEBUG_LAPM_DUMP)) - lapm_dump(s, frame, len, s->debug & LAPM_DEBUG_LAPM_RAW, TRUE); - /*endif*/ - hdlc_tx_frame(&s->hdlc_tx, frame, len); - return 0; -} -/*- End of function --------------------------------------------------------*/ + LAPM_S_RR = 0x00, /* cr */ + LAPM_S_RNR = 0x04, /* cr */ + LAPM_S_REJ = 0x08, /* cr */ + LAPM_S_SREJ = 0x0C /* cr */ +}; -static void t400_expired(span_sched_state_t *ss, void *user_data) +#define LAPM_S_PF 0x01 + +/* Unnumbered headers */ +enum { - v42_state_t *s; - - /* Give up trying to detect a V.42 capable peer. */ - s = (v42_state_t *) user_data; - s->t400_timer = -1; - s->lapm.state = LAPM_UNSUPPORTED; - if (s->lapm.status_callback) - s->lapm.status_callback(s->lapm.status_callback_user_data, s->lapm.state); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ + LAPM_U_UI = 0x00, /* cr */ + LAPM_U_DM = 0x0C, /* r */ + LAPM_U_DISC = 0x40, /* c */ + LAPM_U_UA = 0x60, /* r */ + LAPM_U_SABME = 0x6C, /* c */ + LAPM_U_FRMR = 0x84, /* r */ + LAPM_U_XID = 0xAC, /* cr */ + LAPM_U_TEST = 0xE0 /* c */ +}; -static void lapm_send_ua(lapm_state_t *s, int pfbit) +#define LAPM_U_PF 0x10 + +/* XID sub-field definitions */ +#define FI_GENERAL 0x82 +#define GI_PARAM_NEGOTIATION 0x80 +#define GI_PRIVATE_NEGOTIATION 0xF0 +#define GI_USER_DATA 0xFF + +/* Param negotiation (Table 11a/V.42) */ +enum { - uint8_t frame[3]; + PI_HDLC_OPTIONAL_FUNCTIONS = 0x03, + PI_TX_INFO_MAXSIZE = 0x05, + PI_RX_INFO_MAXSIZE = 0x06, + PI_TX_WINDOW_SIZE = 0x07, + PI_RX_WINDOW_SIZE = 0x08 +}; - lapm_init_header(frame, !s->we_are_originator); - frame[1] = (uint8_t) (0x63 | (pfbit << 4)); - frame[2] = 0; - span_log(&s->logging, SPAN_LOG_FLOW, "Sending unnumbered acknowledgement\n"); - lapm_tx_frame(s, frame, 3); -} -/*- End of function --------------------------------------------------------*/ - -static void lapm_send_sabme(span_sched_state_t *ss, void *user_data) +/* Private param negotiation (Table 11b/V.42) */ +enum { - lapm_state_t *s; - uint8_t frame[3]; + PI_PARAMETER_SET_ID = 0x00, + PI_V42BIS_COMPRESSION_REQUEST = 0x01, + PI_V42BIS_NUM_CODEWORDS = 0x02, + PI_V42BIS_MAX_STRING_LENGTH = 0x03 +}; - s = (lapm_state_t *) user_data; - if (s->t401_timer >= 0) - { -fprintf(stderr, "Deleting T401 q [%p] %d\n", (void *) s, s->t401_timer); - span_schedule_del(&s->sched, s->t401_timer); - s->t401_timer = -1; - } - /*endif*/ - if (++s->retransmissions > N_400) - { - /* 8.3.2.2 Too many retries */ - s->state = LAPM_RELEASE; - if (s->status_callback) - s->status_callback(s->status_callback_user_data, s->state); - /*endif*/ - return; - } - /*endif*/ -fprintf(stderr, "Setting T401 a1 [%p]\n", (void *) s); - s->t401_timer = span_schedule_event(&s->sched, T_401, lapm_send_sabme, s); - lapm_init_header(frame, s->we_are_originator); - frame[1] = 0x7F; - frame[2] = 0; - span_log(&s->logging, SPAN_LOG_FLOW, "Sending SABME (set asynchronous balanced mode extended)\n"); - lapm_tx_frame(s, frame, 3); -} -/*- End of function --------------------------------------------------------*/ +#define LAPM_DLCI_DTE_TO_DTE 0 +#define LAPM_DLCI_LAYER2_MANAGEMENT 63 -static int lapm_ack_packet(lapm_state_t *s, int num) +/* Type definitions */ +enum { - lapm_frame_queue_t *f; - lapm_frame_queue_t *prev; + LAPM_DETECT = 0, + LAPM_IDLE = 1, + LAPM_ESTABLISH = 2, + LAPM_DATA = 3, + LAPM_RELEASE = 4, + LAPM_SIGNAL = 5, + LAPM_SETPARM = 6, + LAPM_TEST = 7, + LAPM_V42_UNSUPPORTED = 8 +}; - for (prev = NULL, f = s->txqueue; f; prev = f, f = f->next) - { - if ((f->frame[1] >> 1) == num) - { - /* Cancel each packet, as necessary */ - if (prev) - prev->next = f->next; - else - s->txqueue = f->next; - /*endif*/ - span_log(&s->logging, - SPAN_LOG_FLOW, - "-- ACKing packet %d. New txqueue is %d (-1 means empty)\n", - (f->frame[1] >> 1), - (s->txqueue) ? (s->txqueue->frame[1] >> 1) : -1); - s->last_frame_peer_acknowledged = num; - free(f); - /* Reset retransmission count if we actually acked something */ - s->retransmissions = 0; - return 1; - } - /*endif*/ - } - /*endfor*/ - return 0; -} -/*- End of function --------------------------------------------------------*/ +/* Prototypes */ +static int lapm_connect(v42_state_t *ss); +static int lapm_disconnect(v42_state_t *s); +static void reset_lapm(v42_state_t *s); +static void lapm_hdlc_underflow(void *user_data); -static void lapm_ack_rx(lapm_state_t *s, int ack) -{ - int i; - int cnt; - - /* This might not be acking anything new */ - if (s->last_frame_peer_acknowledged == ack) - return; - /*endif*/ - /* It should be acking something that is actually outstanding */ - if ((s->last_frame_peer_acknowledged < s->next_tx_frame && (ack < s->last_frame_peer_acknowledged || ack > s->next_tx_frame)) - || - (s->last_frame_peer_acknowledged > s->next_tx_frame && (ack > s->last_frame_peer_acknowledged || ack < s->next_tx_frame))) - { - /* ACK was outside our window --- ignore */ - span_log(&s->logging, SPAN_LOG_FLOW, "ACK received outside window, ignoring\n"); - return; - } - /*endif*/ - - /* Cancel each packet, as necessary */ - span_log(&s->logging, - SPAN_LOG_FLOW, - "-- ACKing all packets from %d to (but not including) %d\n", - s->last_frame_peer_acknowledged, - ack); - for (cnt = 0, i = s->last_frame_peer_acknowledged; i != ack; i = (i + 1) & 0x7F) - cnt += lapm_ack_packet(s, i); - /*endfor*/ - s->last_frame_peer_acknowledged = ack; - if (s->txqueue == NULL) - { - span_log(&s->logging, SPAN_LOG_FLOW, "-- Since there was nothing left, stopping timer T_401\n"); - /* Something was ACK'd. Stop timer T_401. */ -fprintf(stderr, "T401 a2 is %d [%p]\n", s->t401_timer, (void *) s); - if (s->t401_timer >= 0) - { -fprintf(stderr, "Deleting T401 a3 [%p] %d\n", (void *) s, s->t401_timer); - span_schedule_del(&s->sched, s->t401_timer); - s->t401_timer = -1; - } - /*endif*/ - } - /*endif*/ - if (s->t403_timer >= 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "-- Stopping timer T_403, since we got an ACK\n"); - if (s->t403_timer >= 0) - { -fprintf(stderr, "Deleting T403 b %d\n", s->t403_timer); - span_schedule_del(&s->sched, s->t403_timer); - s->t403_timer = -1; - } - /*endif*/ - } - /*endif*/ - if (s->txqueue) - { - /* Something left to transmit. Start timer T_401 again if it is stopped */ - span_log(&s->logging, - SPAN_LOG_FLOW, - "-- Something left to transmit (%d). Restarting timer T_401\n", - s->txqueue->frame[1] >> 1); - if (s->t401_timer < 0) - { -fprintf(stderr, "Setting T401 b [%p]\n", (void *) s); - s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s); - } - /*endif*/ - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "-- Nothing left, starting timer T_403\n"); - /* Nothing to transmit. Start timer T_403. */ -fprintf(stderr, "Setting T403 c\n"); - s->t403_timer = span_schedule_event(&s->sched, T_403, t403_expired, s); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -static void lapm_reject(lapm_state_t *s) -{ - uint8_t frame[4]; - - lapm_init_header(frame, !s->we_are_originator); - frame[1] = (uint8_t) (0x00 | 0x08 | LAPM_FRAMETYPE_S); - /* Where to start retransmission */ - frame[2] = (uint8_t) ((s->next_expected_frame << 1) | 0x01); - span_log(&s->logging, SPAN_LOG_FLOW, "Sending REJ (reject (%d)\n", s->next_expected_frame); - lapm_tx_frame(s, frame, 4); -} -/*- End of function --------------------------------------------------------*/ - -static void lapm_rr(lapm_state_t *s, int pfbit) -{ - uint8_t frame[4]; - - lapm_init_header(frame, !s->we_are_originator); - frame[1] = (uint8_t) (0x00 | 0x00 | LAPM_FRAMETYPE_S); - frame[2] = (uint8_t) ((s->next_expected_frame << 1) | pfbit); - /* Note that we have already ACKed this */ - s->last_frame_we_acknowledged = s->next_expected_frame; - span_log(&s->logging, SPAN_LOG_FLOW, "Sending RR (receiver ready) (%d)\n", s->next_expected_frame); - lapm_tx_frame(s, frame, 4); -} -/*- End of function --------------------------------------------------------*/ - -static void t401_expired(span_sched_state_t *ss, void *user_data) -{ - lapm_state_t *s; - - s = (lapm_state_t *) user_data; -fprintf(stderr, "Expiring T401 a4 [%p]\n", (void *) s); - s->t401_timer = -1; - if (s->txqueue) - { - /* Retransmit first packet in the queue, setting the poll bit */ - span_log(&s->logging, SPAN_LOG_FLOW, "-- Timer T_401 expired, What to do...\n"); - /* Update N(R), and set the poll bit */ - s->txqueue->frame[2] = (uint8_t)((s->next_expected_frame << 1) | 0x01); - s->last_frame_we_acknowledged = s->next_expected_frame; - s->solicit_f_bit = TRUE; - if (++s->retransmissions <= N_400) - { - /* Reschedule timer T401 */ - span_log(&s->logging, SPAN_LOG_FLOW, "-- Retransmitting %d bytes\n", s->txqueue->len); - lapm_tx_frame(s, s->txqueue->frame, s->txqueue->len); - span_log(&s->logging, SPAN_LOG_FLOW, "-- Scheduling retransmission (%d)\n", s->retransmissions); -fprintf(stderr, "Setting T401 d [%p]\n", (void *) s); - s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "-- Timeout occured\n"); - s->state = LAPM_RELEASE; - if (s->status_callback) - s->status_callback(s->status_callback_user_data, s->state); - lapm_link_down(s); - lapm_restart(s); - } - /*endif*/ - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Timer T_401 expired. Nothing to send...\n"); - } - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ +static int lapm_config(v42_state_t *ss); SPAN_DECLARE(const char *) lapm_status_to_str(int status) { @@ -360,6 +162,8 @@ SPAN_DECLARE(const char *) lapm_status_to_str(int status) { case LAPM_DETECT: return "LAPM_DETECT"; + case LAPM_IDLE: + return "LAPM_IDLE"; case LAPM_ESTABLISH: return "LAPM_ESTABLISH"; case LAPM_DATA: @@ -372,740 +176,1048 @@ SPAN_DECLARE(const char *) lapm_status_to_str(int status) return "LAPM_SETPARM"; case LAPM_TEST: return "LAPM_TEST"; - case LAPM_UNSUPPORTED: - return "LAPM_UNSUPPORTED"; + case LAPM_V42_UNSUPPORTED: + return "LAPM_V42_UNSUPPORTED"; } /*endswitch*/ return "???"; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) lapm_tx(lapm_state_t *s, const void *buf, int len) +static void report_rx_status_change(v42_state_t *s, int status) { - return queue_write(s->tx_queue, buf, len); + if (s->lapm.status_handler) + s->lapm.status_handler(s->lapm.status_user_data, status); + else if (s->lapm.iframe_put) + s->lapm.iframe_put(s->lapm.iframe_put_user_data, NULL, status); } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) lapm_release(lapm_state_t *s) +static inline uint32_t pack_value(const uint8_t *buf, int len) { - s->state = LAPM_RELEASE; - return 0; -} -/*- End of function --------------------------------------------------------*/ + uint32_t val; -SPAN_DECLARE(int) lapm_loopback(lapm_state_t *s, int enable) -{ - s->state = LAPM_TEST; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) lapm_break(lapm_state_t *s, int enable) -{ - s->state = LAPM_SIGNAL; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) lapm_tx_iframe(lapm_state_t *s, const void *buf, int len, int cr) -{ - lapm_frame_queue_t *f; - - if ((f = malloc(sizeof(*f) + len + 4)) == NULL) + val = 0; + while (len--) { - span_log(&s->logging, SPAN_LOG_FLOW, "Out of memory\n"); + val <<= 8; + val |= *buf++; + } + return val; +} +/*- End of function --------------------------------------------------------*/ + +static inline v42_frame_t *get_next_free_ctrl_frame(lapm_state_t *s) +{ + v42_frame_t *f; + int ctrl_put_next; + + if ((ctrl_put_next = s->ctrl_put + 1) >= V42_CTRL_FRAMES) + ctrl_put_next = 0; + if (ctrl_put_next == s->ctrl_get) + return NULL; + f = &s->ctrl_buf[s->ctrl_put]; + s->ctrl_put = ctrl_put_next; + return f; +} +/*- End of function --------------------------------------------------------*/ + +static int tx_unnumbered_frame(lapm_state_t *s, uint8_t addr, uint8_t ctrl, uint8_t *info, int len) +{ + v42_frame_t *f; + uint8_t *buf; + + if ((f = get_next_free_ctrl_frame(s)) == NULL) + return -1; + buf = f->buf; + buf[0] = addr; + buf[1] = LAPM_FRAMETYPE_U | ctrl; + f->len = 2; + if (info && len) + { + memcpy(buf + f->len, info, len); + f->len += len; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int tx_supervisory_frame(lapm_state_t *s, uint8_t addr, uint8_t ctrl, uint8_t pf_mask) +{ + v42_frame_t *f; + uint8_t *buf; + + if ((f = get_next_free_ctrl_frame(s)) == NULL) + return -1; + buf = f->buf; + buf[0] = addr; + buf[1] = LAPM_FRAMETYPE_S | ctrl; + buf[2] = (s->vr << 1) | pf_mask; + f->len = 3; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int set_param(int param, int value, int def) +{ + if ((value < def && param >= def) || (value >= def && param < def)) + return def; + if ((value < def && param < value) || (value >= def && param > value)) + return value; + return param; +} +/*- End of function --------------------------------------------------------*/ + +static int receive_xid(v42_state_t *ss, const uint8_t *frame, int len) +{ + lapm_state_t *s; + v42_config_parameters_t config; + const uint8_t *buf; + uint8_t group_id; + uint16_t group_len; + uint32_t param_val; + uint8_t param_id; + uint8_t param_len; + + s = &ss->lapm; + if (frame[2] != FI_GENERAL) + return -1; + memset(&config, 0, sizeof(config)); + /* Skip the header octets */ + frame += 3; + len -= 3; + while (len > 0) + { + group_id = frame[0]; + group_len = frame[1]; + group_len = (group_len << 8) | frame[2]; + frame += 3; + len -= (3 + group_len); + if (len < 0) + break; + buf = frame; + frame += group_len; + switch (group_id) + { + case GI_PARAM_NEGOTIATION: + while (group_len > 0) + { + param_id = buf[0]; + param_len = buf[1]; + buf += 2; + group_len -= (2 + param_len); + if (group_len < 0) + break; + switch (param_id) + { + case PI_HDLC_OPTIONAL_FUNCTIONS: + param_val = pack_value(buf, param_len); + break; + case PI_TX_INFO_MAXSIZE: + param_val = pack_value(buf, param_len); + param_val >>= 3; + config.v42_tx_n401 = + s->tx_n401 = set_param(s->tx_n401, param_val, ss->config.v42_tx_n401); + break; + case PI_RX_INFO_MAXSIZE: + param_val = pack_value(buf, param_len); + param_val >>= 3; + config.v42_rx_n401 = + s->rx_n401 = set_param(s->rx_n401, param_val, ss->config.v42_rx_n401); + break; + case PI_TX_WINDOW_SIZE: + param_val = pack_value(buf, param_len); + config.v42_tx_window_size_k = + s->tx_window_size_k = set_param(s->tx_window_size_k, param_val, ss->config.v42_tx_window_size_k); + break; + case PI_RX_WINDOW_SIZE: + param_val = pack_value(buf, param_len); + config.v42_rx_window_size_k = + s->rx_window_size_k = set_param(s->rx_window_size_k, param_val, ss->config.v42_rx_window_size_k); + break; + default: + break; + } + buf += param_len; + } + break; + case GI_PRIVATE_NEGOTIATION: + while (group_len > 0) + { + param_id = buf[0]; + param_len = buf[1]; + buf += 2; + group_len -= (2 + param_len); + if (group_len < 0) + break; + switch (param_id) + { + case PI_PARAMETER_SET_ID: + /* This might be worth monitoring, but it doesn't serve mnuch other purpose */ + break; + case PI_V42BIS_COMPRESSION_REQUEST: + config.comp = pack_value(buf, param_len); + break; + case PI_V42BIS_NUM_CODEWORDS: + config.comp_dict_size = pack_value(buf, param_len); + break; + case PI_V42BIS_MAX_STRING_LENGTH: + config.comp_max_string = pack_value(buf, param_len); + break; + default: + break; + } + buf += param_len; + } + break; + default: + break; + } + } + //v42_update_config(ss, &config); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static void transmit_xid(v42_state_t *ss, uint8_t addr) +{ + lapm_state_t *s; + uint8_t *buf; + int len; + int group_len; + uint32_t param_val; + v42_frame_t *f; + + s = &ss->lapm; + if ((f = get_next_free_ctrl_frame(s)) == NULL) + return; + + buf = f->buf; + len = 0; + + /* Figure 11/V.42 */ + *buf++ = addr; + *buf++ = LAPM_U_XID | LAPM_FRAMETYPE_U; + /* Format identifier subfield */ + *buf++ = FI_GENERAL; + len += 3; + + /* Parameter negotiation group */ + group_len = 20; + *buf++ = GI_PARAM_NEGOTIATION; + *buf++ = (group_len >> 8) & 0xFF; + *buf++ = group_len & 0xFF; + len += 3; + + /* For conformance with the encoding rules in ISO/IEC 8885, the transmitter of an XID command frame shall + set bit positions 2, 4, 8, 9, 12 and 16 to 1. (Table 11a/V.42) + Optional bits are: + 3 Selective retransmission procedure (SREJ frame) single I frame request + 14 Loop-back test procedure (TEST frame) + 17 + Extended FCS procedure (32-bit FCS) + 24 Selective retransmission procedure (SREJ frame) multiple I frame request with span list + capability. */ + *buf++ = PI_HDLC_OPTIONAL_FUNCTIONS; + *buf++ = 4; + *buf++ = 0x8A; /* Bits 2, 4, and 8 set */ + *buf++ = 0x89; /* Bits 9, 12, and 16 set */ + *buf++ = 0x00; + *buf++ = 0x00; + + /* Send the maximum as a number of bits, rather than octets */ + param_val = ss->config.v42_tx_n401 << 3; + *buf++ = PI_TX_INFO_MAXSIZE; + *buf++ = 2; + *buf++ = (param_val >> 8) & 0xFF; + *buf++ = (param_val & 0xFF); + + /* Send the maximum as a number of bits, rather than octets */ + param_val = ss->config.v42_rx_n401 << 3; + *buf++ = PI_RX_INFO_MAXSIZE; + *buf++ = 2; + *buf++ = (param_val >> 8) & 0xFF; + *buf++ = (param_val & 0xFF); + + *buf++ = PI_TX_WINDOW_SIZE; + *buf++ = 1; + *buf++ = ss->config.v42_tx_window_size_k; + + *buf++ = PI_RX_WINDOW_SIZE; + *buf++ = 1; + *buf++ = ss->config.v42_rx_window_size_k; + + len += group_len; + + if (ss->config.comp) + { + /* Private parameter negotiation group */ + group_len = 15; + *buf++ = GI_PRIVATE_NEGOTIATION; + *buf++ = (group_len >> 8) & 0xFF; + *buf++ = group_len & 0xFF; + len += 3; + + /* Private parameter for V.42 (ASCII for V42). V.42 says ".42", but V.42bis says "V42", + and that seems to be what should be used. */ + *buf++ = PI_PARAMETER_SET_ID; + *buf++ = 3; + *buf++ = 'V'; + *buf++ = '4'; + *buf++ = '2'; + + /* V.42bis P0 + 00 Compression in neither direction (default); + 01 Negotiation initiator-responder direction only; + 10 Negotiation responder-initiator direction only; + 11 Both directions. */ + *buf++ = PI_V42BIS_COMPRESSION_REQUEST; + *buf++ = 1; + *buf++ = ss->config.comp; + + /* V.42bis P1 */ + param_val = ss->config.comp_dict_size; + *buf++ = PI_V42BIS_NUM_CODEWORDS; + *buf++ = 2; + *buf++ = (param_val >> 8) & 0xFF; + *buf++ = param_val & 0xFF; + + /* V.42bis P2 */ + *buf++ = PI_V42BIS_MAX_STRING_LENGTH; + *buf++ = 1; + *buf++ = ss->config.comp_max_string; + + len += group_len; + } + + f->len = len; +} +/*- End of function --------------------------------------------------------*/ + +static int ms_to_bits(v42_state_t *s, int time) +{ + return ((time*s->tx_bit_rate)/1000); +} +/*- End of function --------------------------------------------------------*/ + +static void t400_expired(v42_state_t *ss) +{ + /* Give up trying to detect a V.42 capable peer. */ + ss->bit_timer = 0; + ss->lapm.state = LAPM_V42_UNSUPPORTED; + report_rx_status_change(ss, ss->lapm.state); +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void t400_start(v42_state_t *s) +{ + s->bit_timer = ms_to_bits(s, T_400); + s->bit_timer_func = t400_expired; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void t400_stop(v42_state_t *s) +{ + s->bit_timer = 0; +} +/*- End of function --------------------------------------------------------*/ + +static void t401_expired(v42_state_t *ss) +{ + lapm_state_t *s; + + span_log(&ss->logging, SPAN_LOG_FLOW, "T.401 expired\n"); + s = &ss->lapm; + if (s->retry_count > V42_DEFAULT_N_400) + { + s->retry_count = 0; + switch (s->state) + { + case LAPM_ESTABLISH: + case LAPM_RELEASE: + s->state = LAPM_IDLE; + report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); + break; + case LAPM_DATA: + lapm_disconnect(ss); + break; + } + return ; + } + s->retry_count++; + if (s->configuring) + { + transmit_xid(ss, s->cmd_addr); + } + else + { + switch (s->state) + { + case LAPM_ESTABLISH: + tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_SABME | LAPM_U_PF, NULL, 0); + break; + case LAPM_RELEASE: + tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_DISC | LAPM_U_PF, NULL, 0); + break; + case LAPM_DATA: + tx_supervisory_frame(s, s->cmd_addr, (s->local_busy) ? LAPM_S_RNR : LAPM_S_RR, 1); + break; + } + } + ss->bit_timer = ms_to_bits(ss, T_401); + ss->bit_timer_func = t401_expired; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void t401_start(v42_state_t *s) +{ + s->bit_timer = ms_to_bits(s, T_401); + s->bit_timer_func = t401_expired; + s->lapm.retry_count = 0; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void t401_stop(v42_state_t *s) +{ + s->bit_timer = 0; + s->lapm.retry_count = 0; +} +/*- End of function --------------------------------------------------------*/ + +static void t403_expired(v42_state_t *ss) +{ + lapm_state_t *s; + + span_log(&ss->logging, SPAN_LOG_FLOW, "T.403 expired\n"); + if (ss->lapm.state != LAPM_DATA) + return; + s = &ss->lapm; + tx_supervisory_frame(s, s->cmd_addr, (ss->lapm.local_busy) ? LAPM_S_RNR : LAPM_S_RR, 1); + t401_start(ss); + ss->lapm.retry_count = 1; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void t401_stop_t403_start(v42_state_t *s) +{ + s->bit_timer = ms_to_bits(s, T_403); + s->bit_timer_func = t403_expired; + s->lapm.retry_count = 0; +} +/*- End of function --------------------------------------------------------*/ + +static void initiate_negotiation_expired(v42_state_t *s) +{ + /* Timer service routine */ + span_log(&s->logging, SPAN_LOG_FLOW, "Start negotiation\n"); + lapm_config(s); + lapm_hdlc_underflow(s); +} +/*- End of function --------------------------------------------------------*/ + +static int tx_information_frame(v42_state_t *ss) +{ + lapm_state_t *s; + v42_frame_t *f; + uint8_t *buf; + int n; + int info_put_next; + + s = &ss->lapm; + if (s->far_busy || ((s->vs - s->va) & 0x7F) >= s->tx_window_size_k) + return FALSE; + if (s->info_get != s->info_put) + return TRUE; + if ((info_put_next = s->info_put + 1) >= V42_INFO_FRAMES) + info_put_next = 0; + if (info_put_next == s->info_get || info_put_next == s->info_acked) + return FALSE; + f = &s->info_buf[s->info_put]; + buf = f->buf; + if (s->iframe_get == NULL) + return FALSE; + n = s->iframe_get(s->iframe_get_user_data, buf + 3, s->tx_n401); + if (n < 0) + { + /* Error */ + report_rx_status_change(ss, SIG_STATUS_LINK_ERROR); + return FALSE; + } + if (n == 0) + return FALSE; + + f->len = n + 3; + s->info_put = info_put_next; + return TRUE; +} +/*- End of function --------------------------------------------------------*/ + +static void tx_information_rr_rnr_response(v42_state_t *ss, const uint8_t *frame, int len) +{ + lapm_state_t *s; + + s = &ss->lapm; + /* Respond with information frame, RR, or RNR, as appropriate */ + /* p = 1 may be used for status checking */ + if ((frame[2] & 0x1) || !tx_information_frame(ss)) + tx_supervisory_frame(s, frame[0], (s->local_busy) ? LAPM_S_RNR : LAPM_S_RR, 1); +} +/*- End of function --------------------------------------------------------*/ + +static int reject_info(lapm_state_t *s) +{ + uint8_t n; + + /* Reject all non-acked frames */ + if (s->state != LAPM_DATA) + return 0; + n = (s->vs - s->va) & 0x7F; + s->vs = s->va; + s->info_get = s->info_acked; + return n; +} +/*- End of function --------------------------------------------------------*/ + +static int ack_info(v42_state_t *ss, uint8_t nr) +{ + lapm_state_t *s; + int n; + + s = &ss->lapm; + /* Check that NR is valid - i.e. VA <= NR <= VS && VS-VA <= k */ + if (!((((nr - s->va) & 0x7F) + ((s->vs - nr) & 0x7F)) <= s->tx_window_size_k + && + ((s->vs - s->va) & 0x7F) <= s->tx_window_size_k)) + { + lapm_disconnect(ss); return -1; } - /*endif*/ + n = 0; + while (s->va != nr && s->info_acked != s->info_get) + { + if (++s->info_acked >= V42_INFO_FRAMES) + s->info_acked = 0; + s->va = (s->va + 1) & 0x7F; + n++; + } + if (n > 0 && s->retry_count == 0) + { + t401_stop_t403_start(ss); + /* 8.4.8 */ + if (((s->vs - s->va) & 0x7F)) + t401_start(ss); + } + return n; +} +/*- End of function --------------------------------------------------------*/ - lapm_init_header(f->frame, (s->peer_is_originator) ? cr : !cr); - f->next = NULL; - f->len = len + 4; - f->frame[1] = (uint8_t) (s->next_tx_frame << 1); - f->frame[2] = (uint8_t) (s->next_expected_frame << 1); - memcpy(f->frame + 3, buf, len); - s->next_tx_frame = (s->next_tx_frame + 1) & 0x7F; - s->last_frame_we_acknowledged = s->next_expected_frame; - /* Clear poll bit */ - f->frame[2] &= ~0x01; - if (s->tx_last) - s->tx_last->next = f; - else - s->txqueue = f; - /*endif*/ - s->tx_last = f; - /* Immediately transmit unless we're in a recovery state */ - if (s->retransmissions == 0) - lapm_tx_frame(s, f->frame, f->len); - /*endif*/ - if (s->t403_timer >= 0) +static int valid_data_state(v42_state_t *ss) +{ + lapm_state_t *s; + + s = &ss->lapm; + switch (s->state) { - span_log(&s->logging, SPAN_LOG_FLOW, "Stopping T_403 timer\n"); -fprintf(stderr, "Deleting T403 c %d\n", s->t403_timer); - span_schedule_del(&s->sched, s->t403_timer); - s->t403_timer = -1; + case LAPM_DETECT: + case LAPM_IDLE: + break; + case LAPM_ESTABLISH: + reset_lapm(ss); + s->state = LAPM_DATA; + report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED); + return 1; + case LAPM_DATA: + return 1; + case LAPM_RELEASE: + reset_lapm(ss); + s->state = LAPM_IDLE; + report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); + break; + case LAPM_SIGNAL: + case LAPM_SETPARM: + case LAPM_TEST: + case LAPM_V42_UNSUPPORTED: + break; } - /*endif*/ - if (s->t401_timer < 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Starting timer T_401\n"); - s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s); -fprintf(stderr, "Setting T401 e %d [%p]\n", s->t401_timer, (void *) s); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "Timer T_401 already running (%d)\n", s->t401_timer); - } - /*endif*/ return 0; } /*- End of function --------------------------------------------------------*/ -static void t403_expired(span_sched_state_t *ss, void *user_data) +static void receive_information_frame(v42_state_t *ss, const uint8_t *frame, int len) +{ + lapm_state_t *s; + int ret; + int n; + + s = &ss->lapm; + if (!valid_data_state(ss)) + return; + if (len > s->rx_n401 + 3) + return; + ret = 0; + /* Ack I frames: NR - 1 */ + n = ack_info(ss, frame[2] >> 1); + if (s->local_busy) + { + /* 8.4.7 */ + if ((frame[2] & 0x1)) + tx_supervisory_frame(s, s->rsp_addr, LAPM_S_RNR, 1); + return; + } + /* NS sequence error */ + if ((frame[1] >> 1) != s->vr) + { + if (!s->rejected) + { + tx_supervisory_frame(s, s->rsp_addr, LAPM_S_REJ, (frame[2] & 0x1)); + s->rejected = TRUE; + } + return; + } + s->rejected = FALSE; + + s->iframe_put(s->iframe_put_user_data, frame + 3, len - 3); + /* Increment vr */ + s->vr = (s->vr + 1) & 0x7F; + tx_information_rr_rnr_response(ss, frame, len); +} +/*- End of function --------------------------------------------------------*/ + +static void rx_supervisory_cmd_frame(v42_state_t *ss, const uint8_t *frame, int len) +{ + lapm_state_t *s; + int n; + + s = &ss->lapm; + /* If l->local_busy each RR,RNR,REJ with p=1 should be replied by RNR with f=1 (8.4.7) */ + switch (frame[1] & 0x0C) + { + case LAPM_S_RR: + s->far_busy = FALSE; + n = ack_info(ss, frame[2] >> 1); + /* If p = 1 may be used for status checking? */ + tx_information_rr_rnr_response(ss, frame, len); + break; + case LAPM_S_RNR: + s->far_busy = TRUE; + n = ack_info(ss, frame[2] >> 1); + /* If p = 1 may be used for status checking? */ + if ((frame[2] & 0x1)) + tx_supervisory_frame(s, s->rsp_addr, (s->local_busy) ? LAPM_S_RNR : LAPM_S_RR, 1); + break; + case LAPM_S_REJ: + s->far_busy = FALSE; + n = ack_info(ss, frame[2] >> 1); + if (s->retry_count == 0) + { + t401_stop_t403_start(ss); + reject_info(s); + } + tx_information_rr_rnr_response(ss, frame, len); + break; + case LAPM_S_SREJ: + /* TODO: */ + return; + default: + return; + } +} +/*- End of function --------------------------------------------------------*/ + +static void rx_supervisory_rsp_frame(v42_state_t *ss, const uint8_t *frame, int len) +{ + lapm_state_t *s; + int n; + + s = &ss->lapm; + if (s->retry_count == 0 && (frame[2] & 0x1)) + return; + /* Ack I frames <= NR - 1 */ + switch (frame[1] & 0x0C) + { + case LAPM_S_RR: + s->far_busy = FALSE; + n = ack_info(ss, frame[2] >> 1); + if (s->retry_count && (frame[2] & 0x1)) + { + reject_info(s); + t401_stop_t403_start(ss); + } + break; + case LAPM_S_RNR: + s->far_busy = TRUE; + n = ack_info(ss, frame[2] >> 1); + if (s->retry_count && (frame[2] & 0x1)) + { + reject_info(s); + t401_stop_t403_start(ss); + } + if (s->retry_count == 0) + t401_start(ss); + break; + case LAPM_S_REJ: + s->far_busy = FALSE; + n = ack_info(ss, frame[2] >> 1); + if (s->retry_count == 0 || (frame[2] & 0x1)) + { + reject_info(s); + t401_stop_t403_start(ss); + } + break; + case LAPM_S_SREJ: + /* TODO: */ + return; + default: + return; + } +} +/*- End of function --------------------------------------------------------*/ + +static int rx_unnumbered_cmd_frame(v42_state_t *ss, const uint8_t *frame, int len) { lapm_state_t *s; - s = (lapm_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "Timer T_403 expired. Sending RR and scheduling T_403 again\n"); - s->t403_timer = -1; - s->retransmissions = 0; - /* Solicit an F-bit in the other end's RR */ - s->solicit_f_bit = TRUE; - lapm_rr(s, 1); - /* Restart ourselves */ -fprintf(stderr, "Setting T403 f\n"); - s->t401_timer = span_schedule_event(&s->sched, T_401, t401_expired, s); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) lapm_dump(lapm_state_t *s, const uint8_t *frame, int len, int showraw, int txrx) -{ - const char *type; - char direction_tag[2]; - - direction_tag[0] = txrx ? '>' : '<'; - direction_tag[1] = '\0'; - if (showraw) - span_log_buf(&s->logging, SPAN_LOG_FLOW, direction_tag, frame, len); - /*endif*/ - - switch ((frame[1] & LAPM_FRAMETYPE_MASK)) + s = &ss->lapm; + switch (frame[1] & 0xEC) { - case LAPM_FRAMETYPE_I: - case LAPM_FRAMETYPE_I_ALT: - span_log(&s->logging, SPAN_LOG_FLOW, "%c Information frame:\n", direction_tag[0]); + case LAPM_U_SABME: + /* Discard un-acked I frames. Reset vs, vr, and va. Clear exceptions */ + reset_lapm(ss); + /* Going to connected state */ + s->state = LAPM_DATA; + /* Respond UA (or DM on error) */ + // fixme: why may be error and LAPM_U_DM ?? + tx_unnumbered_frame(s, s->rsp_addr, LAPM_U_UA | (frame[1] & 0x10), NULL, 0); + t401_stop_t403_start(ss); + report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED); break; - case LAPM_FRAMETYPE_S: - span_log(&s->logging, SPAN_LOG_FLOW, "%c Supervisory frame:\n", direction_tag[0]); + case LAPM_U_UI: + /* Break signal */ + /* TODO: */ break; - case LAPM_FRAMETYPE_U: - span_log(&s->logging, SPAN_LOG_FLOW, "%c Unnumbered frame:\n", direction_tag[0]); - break; - } - /*endswitch*/ - - span_log(&s->logging, - SPAN_LOG_FLOW, - "%c DLCI: %2d C/R: %d EA: %d\n", - direction_tag[0], - (frame[0] >> 2), - (frame[0] & 0x02) ? 1 : 0, - (frame[0] & 0x01), - direction_tag[0]); - switch ((frame[1] & LAPM_FRAMETYPE_MASK)) - { - case LAPM_FRAMETYPE_I: - case LAPM_FRAMETYPE_I_ALT: - /* Information frame */ - span_log(&s->logging, - SPAN_LOG_FLOW, - "%c N(S): %03d\n", - direction_tag[0], - (frame[1] >> 1)); - span_log(&s->logging, - SPAN_LOG_FLOW, - "%c N(R): %03d P: %d\n", - direction_tag[0], - (frame[2] >> 1), - (frame[2] & 0x01)); - span_log(&s->logging, - SPAN_LOG_FLOW, - "%c %d bytes of data\n", - direction_tag[0], - len - 4); - break; - case LAPM_FRAMETYPE_S: - /* Supervisory frame */ - switch (frame[1] & 0x0C) + case LAPM_U_DISC: + /* Respond UA (or DM) */ + if (s->state == LAPM_IDLE) { - case 0x00: - type = "RR (receive ready)"; - break; - case 0x04: - type = "RNR (receive not ready)"; - break; - case 0x08: - type = "REJ (reject)"; - break; - case 0x0C: - type = "SREJ (selective reject)"; - break; - default: - type = "???"; - break; - } - /*endswitch*/ - span_log(&s->logging, - SPAN_LOG_FLOW, - "%c S: %03d [ %s ]\n", - direction_tag[0], - frame[1], - type); - span_log(&s->logging, - SPAN_LOG_FLOW, - "%c N(R): %03d P/F: %d\n", - direction_tag[0], - frame[2] >> 1, - frame[2] & 0x01); - span_log(&s->logging, - SPAN_LOG_FLOW, - "%c %d bytes of data\n", - direction_tag[0], - len - 4); - break; - case LAPM_FRAMETYPE_U: - /* Unnumbered frame */ - switch (frame[1] & 0xEC) - { - case 0x00: - type = "UI (unnumbered information)"; - break; - case 0x0C: - type = "DM (disconnect mode)"; - break; - case 0x40: - type = "DISC (disconnect)"; - break; - case 0x60: - type = "UA (unnumbered acknowledgement)"; - break; - case 0x6C: - type = "SABME (set asynchronous balanced mode extended)"; - break; - case 0x84: - type = "FRMR (frame reject)"; - break; - case 0xAC: - type = "XID (exchange identification)"; - break; - case 0xE0: - type = "TEST (test)"; - break; - default: - type = "???"; - break; - } - /*endswitch*/ - span_log(&s->logging, - SPAN_LOG_FLOW, - "%c M: %03d [ %s ] P/F: %d\n", - direction_tag[0], - frame[1], - type, - (frame[1] >> 4) & 1); - span_log(&s->logging, - SPAN_LOG_FLOW, - "%c %d bytes of data\n", - direction_tag[0], - len - 3); - break; - } - /*endswitch*/ -} -/*- End of function --------------------------------------------------------*/ - -static void lapm_link_up(lapm_state_t *s) -{ - uint8_t buf[1024]; - int len; - - lapm_reset(s); - /* Go into connection established state */ - s->state = LAPM_DATA; - if (s->status_callback) - s->status_callback(s->status_callback_user_data, s->state); - /*endif*/ - if (!queue_empty(s->tx_queue)) - { - if ((len = queue_read(s->tx_queue, buf, s->n401)) > 0) - lapm_tx_iframe(s, buf, len, TRUE); - /*endif*/ - } - /*endif*/ - if (s->t401_timer >= 0) - { -fprintf(stderr, "Deleting T401 x [%p] %d\n", (void *) s, s->t401_timer); - span_schedule_del(&s->sched, s->t401_timer); - s->t401_timer = -1; - } - /*endif*/ - /* Start the T403 timer */ -fprintf(stderr, "Setting T403 g\n"); - s->t403_timer = span_schedule_event(&s->sched, T_403, t403_expired, s); -} -/*- End of function --------------------------------------------------------*/ - -static void lapm_link_down(lapm_state_t *s) -{ - lapm_reset(s); - - if (s->status_callback) - s->status_callback(s->status_callback_user_data, s->state); - /*endif*/ -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) lapm_reset(lapm_state_t *s) -{ - lapm_frame_queue_t *f; - lapm_frame_queue_t *p; - - /* Having received a SABME, we need to reset our entire state */ - s->next_tx_frame = 0; - s->last_frame_peer_acknowledged = 0; - s->next_expected_frame = 0; - s->last_frame_we_acknowledged = 0; - s->window_size_k = 15; - s->n401 = 128; - if (s->t401_timer >= 0) - { -fprintf(stderr, "Deleting T401 d [%p] %d\n", (void *) s, s->t401_timer); - span_schedule_del(&s->sched, s->t401_timer); - s->t401_timer = -1; - } - /*endif*/ - if (s->t403_timer >= 0) - { -fprintf(stderr, "Deleting T403 e %d\n", s->t403_timer); - span_schedule_del(&s->sched, s->t403_timer); - s->t403_timer = -1; - } - /*endif*/ - s->busy = FALSE; - s->solicit_f_bit = FALSE; - s->state = LAPM_RELEASE; - s->retransmissions = 0; - /* Discard anything waiting to go out */ - for (f = s->txqueue; f; ) - { - p = f; - f = f->next; - free(p); - } - /*endfor*/ - s->txqueue = NULL; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok) -{ - lapm_state_t *s; - lapm_frame_queue_t *f; - int sendnow; - int octet; - int s_field; - int m_field; - -fprintf(stderr, "LAPM receive %d %d\n", ok, len); - if (!ok || len == 0) - return; - /*endif*/ - s = (lapm_state_t *) user_data; - if (len < 0) - { - /* Special conditions */ - span_log(&s->logging, SPAN_LOG_DEBUG, "V.42 rx status is %s (%d)\n", signal_status_to_str(len), len); - return; - } - /*endif*/ - - if ((s->debug & LAPM_DEBUG_LAPM_DUMP)) - lapm_dump(s, frame, len, s->debug & LAPM_DEBUG_LAPM_RAW, FALSE); - /*endif*/ - octet = 0; - /* We do not expect extended addresses */ - if ((frame[octet] & 0x01) == 0) - return; - /*endif*/ - /* Check for DLCIs we do not recognise */ - if ((frame[octet] >> 2) != LAPM_DLCI_DTE_TO_DTE) - return; - /*endif*/ - octet++; - switch (frame[octet] & LAPM_FRAMETYPE_MASK) - { - case LAPM_FRAMETYPE_I: - case LAPM_FRAMETYPE_I_ALT: - if (s->state != LAPM_DATA) - { - span_log(&s->logging, SPAN_LOG_FLOW, "!! Got an I-frame while link state is %d\n", s->state); - break; - } - /*endif*/ - /* Information frame */ - if (len < 4) - { - span_log(&s->logging, SPAN_LOG_FLOW, "!! Received short I-frame (expected 4, got %d)\n", len); - break; - } - /*endif*/ - /* Make sure this is a valid packet */ - if ((frame[1] >> 1) == s->next_expected_frame) - { - /* Increment next expected I-frame */ - s->next_expected_frame = (s->next_expected_frame + 1) & 0x7F; - /* Handle their ACK */ - lapm_ack_rx(s, frame[2] >> 1); - if ((frame[2] & 0x01)) - { - /* If the Poll/Final bit is set, send the RR immediately */ - lapm_rr(s, 1); - } - /*endif*/ - s->iframe_receive(s->iframe_receive_user_data, frame + 3, len - 4); - /* Send an RR if one wasn't sent already */ - if (s->last_frame_we_acknowledged != s->next_expected_frame) - lapm_rr(s, 0); - /*endif*/ + tx_unnumbered_frame(s, s->rsp_addr, LAPM_U_DM | LAPM_U_PF, NULL, 0); } else { - if (((s->next_expected_frame - (frame[1] >> 1)) & 127) < s->window_size_k) - { - /* It's within our window -- send back an RR */ - lapm_rr(s, 0); - } - else - { - lapm_reject(s); - } - /*endif*/ + /* Going to disconnected state, discard unacked I frames, reset all. */ + s->state = LAPM_IDLE; + reset_lapm(ss); + tx_unnumbered_frame(s, s->rsp_addr, LAPM_U_UA | (frame[1] & 0x10), NULL, 0); + t401_stop(ss); + /* TODO: notify CF */ + report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); } - /*endif*/ break; - case LAPM_FRAMETYPE_S: - if (s->state != LAPM_DATA) + case LAPM_U_XID: + /* Exchange general ID info */ + receive_xid(ss, frame, len); + transmit_xid(ss, s->rsp_addr); + break; + case LAPM_U_TEST: + /* TODO: */ + break; + default: + return -1; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int rx_unnumbered_rsp_frame(v42_state_t *ss, const uint8_t *frame, int len) +{ + lapm_state_t *s; + + s = &ss->lapm; + switch (frame[1] & 0xEC) + { + case LAPM_U_DM: + switch (s->state) { - span_log(&s->logging, SPAN_LOG_FLOW, "!! Got S-frame while link down\n"); - break; - } - /*endif*/ - if (len < 4) - { - span_log(&s->logging, SPAN_LOG_FLOW, "!! Received short S-frame (expected 4, got %d)\n", len); - break; - } - /*endif*/ - s_field = frame[octet] & 0xEC; - switch (s_field) - { - case 0x00: - /* RR (receive ready) */ - s->busy = FALSE; - /* Acknowledge frames as necessary */ - lapm_ack_rx(s, frame[2] >> 1); - if ((frame[2] & 0x01)) + case LAPM_IDLE: + if (!(frame[1] & 0x10)) { - /* If P/F is one, respond with an RR with the P/F bit set */ - if (s->solicit_f_bit) - { - span_log(&s->logging, SPAN_LOG_FLOW, "-- Got RR response to our frame\n"); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "-- Unsolicited RR with P/F bit, responding\n"); - lapm_rr(s, 1); - } - /*endif*/ - s->solicit_f_bit = FALSE; + /* TODO: notify CF */ + report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED); } - /*endif*/ break; - case 0x04: - /* RNR (receive not ready) */ - span_log(&s->logging, SPAN_LOG_FLOW, "-- Got receiver not ready\n"); - s->busy = TRUE; - break; - case 0x08: - /* REJ (reject) */ - /* Just retransmit */ - span_log(&s->logging, SPAN_LOG_FLOW, "-- Got reject requesting packet %d... Retransmitting.\n", frame[2] >> 1); - if ((frame[2] & 0x01)) + case LAPM_ESTABLISH: + case LAPM_RELEASE: + if ((frame[1] & 0x10)) { - /* If it has the poll bit set, send an appropriate supervisory response */ - lapm_rr(s, 1); + s->state = LAPM_IDLE; + reset_lapm(ss); + t401_stop(ss); + /* TODO: notify CF */ + report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); } - /*endif*/ - sendnow = FALSE; - /* Resend the appropriate I-frame */ - for (f = s->txqueue; f; f = f->next) - { - if (sendnow || (f->frame[1] >> 1) == (frame[2] >> 1)) - { - /* Matches the request, or follows in our window */ - sendnow = TRUE; - span_log(&s->logging, - SPAN_LOG_FLOW, - "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", - frame[2] >> 1, - f->frame[1] >> 1); - f->frame[2] = (uint8_t) (s->next_expected_frame << 1); - lapm_tx_frame(s, f->frame, f->len); - } - /*endif*/ - } - /*endfor*/ - if (!sendnow) - { - if (s->txqueue) - { - /* This should never happen */ - if ((frame[2] & 0x01) == 0 || (frame[2] >> 1)) - { - span_log(&s->logging, - SPAN_LOG_FLOW, - "!! Got reject for frame %d, but we only have others!\n", - frame[2] >> 1); - } - /*endif*/ - } - else - { - /* Hrm, we have nothing to send, but have been REJ'd. Reset last_frame_peer_acknowledged, next_tx_frame, etc */ - span_log(&s->logging, SPAN_LOG_FLOW, "!! Got reject for frame %d, but we have nothing -- resetting!\n", frame[2] >> 1); - s->last_frame_peer_acknowledged = - s->next_tx_frame = frame[2] >> 1; - /* Reset t401 timer if it was somehow going */ - if (s->t401_timer >= 0) - { -fprintf(stderr, "Deleting T401 f [%p] %d\n", (void *) s, s->t401_timer); - span_schedule_del(&s->sched, s->t401_timer); - s->t401_timer = -1; - } - /*endif*/ - /* Reset and restart t403 timer */ - if (s->t403_timer >= 0) - { -fprintf(stderr, "Deleting T403 g %d\n", s->t403_timer); - span_schedule_del(&s->sched, s->t403_timer); - s->t403_timer = -1; - } - /*endif*/ -fprintf(stderr, "Setting T403 h\n"); - s->t403_timer = span_schedule_event(&s->sched, T_403, t403_expired, s); - } - /*endif*/ - } - /*endif*/ break; - case 0x0C: - /* SREJ (selective reject) */ + case LAPM_DATA: + if (s->retry_count || !(frame[1] & 0x10)) + { + s->state = LAPM_IDLE; + reset_lapm(ss); + /* TODO: notify CF */ + report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); + } break; default: - span_log(&s->logging, - SPAN_LOG_FLOW, - "!! XXX Unknown Supervisory frame sd=0x%02x,pf=%02xnr=%02x vs=%02x, va=%02x XXX\n", - s_field, - frame[2] & 0x01, - frame[2] >> 1, - s->next_tx_frame, - s->last_frame_peer_acknowledged); break; } - /*endswitch*/ break; - case LAPM_FRAMETYPE_U: - if (len < 3) + case LAPM_U_UI: + /* TODO: */ + break; + case LAPM_U_UA: + switch (s->state) { - span_log(&s->logging, SPAN_LOG_FLOW, "!! Received too short unnumbered frame\n"); + case LAPM_ESTABLISH: + s->state = LAPM_DATA; + reset_lapm(ss); + t401_stop_t403_start(ss); + report_rx_status_change(ss, SIG_STATUS_LINK_CONNECTED); break; - } - /*endif*/ - m_field = frame[octet] & 0xEC; - switch (m_field) - { - case 0x00: - /* UI (unnumbered information) */ - switch (frame[++octet] & 0x7F) - { - case 0x40: - /* BRK */ - span_log(&s->logging, SPAN_LOG_FLOW, "BRK - option %d, length %d\n", (frame[octet] >> 5), frame[octet + 1]); - octet += 2; - break; - case 0x60: - /* BRKACK */ - span_log(&s->logging, SPAN_LOG_FLOW, "BRKACK\n"); - break; - default: - /* Unknown */ - span_log(&s->logging, SPAN_LOG_FLOW, "Unknown UI type\n"); - break; - } - /*endswitch*/ - break; - case 0x0C: - /* DM (disconnect mode) */ - if ((frame[octet] & 0x10)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "-- Got Unconnected Mode from peer.\n"); - /* Disconnected mode, try again */ - lapm_link_down(s); - lapm_restart(s); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "-- DM (disconnect mode) requesting SABME, starting.\n"); - /* Requesting that we start */ - lapm_restart(s); - } - /*endif*/ - break; - case 0x40: - /* DISC (disconnect) */ - span_log(&s->logging, SPAN_LOG_FLOW, "-- Got DISC (disconnect) from peer.\n"); - /* Acknowledge */ - lapm_send_ua(s, (frame[octet] & 0x10)); - lapm_link_down(s); - break; - case 0x60: - /* UA (unnumbered acknowledgement) */ - if (s->state == LAPM_ESTABLISH) - { - span_log(&s->logging, SPAN_LOG_FLOW, "-- Got UA (unnumbered acknowledgement) from %s peer. Link up.\n", (frame[0] & 0x02) ? "xxx" : "yyy"); - lapm_link_up(s); - } - else - { - span_log(&s->logging, SPAN_LOG_FLOW, "!! Got a UA (unnumbered acknowledgement) in state %d\n", s->state); - } - /*endif*/ - break; - case 0x6C: - /* SABME (set asynchronous balanced mode extended) */ - span_log(&s->logging, SPAN_LOG_FLOW, "-- Got SABME (set asynchronous balanced mode extended) from %s peer.\n", (frame[0] & 0x02) ? "yyy" : "xxx"); - if ((frame[0] & 0x02)) - { - s->peer_is_originator = TRUE; - if (s->we_are_originator) - { - /* We can't both be originators */ - span_log(&s->logging, SPAN_LOG_FLOW, "We think we are the originator, but they think so too."); - break; - } - /*endif*/ - } - else - { - s->peer_is_originator = FALSE; - if (!s->we_are_originator) - { - /* We can't both be answerers */ - span_log(&s->logging, SPAN_LOG_FLOW, "We think we are the answerer, but they think so too.\n"); - break; - } - /*endif*/ - } - /*endif*/ - /* Send unnumbered acknowledgement */ - lapm_send_ua(s, (frame[octet] & 0x10)); - lapm_link_up(s); - break; - case 0x84: - /* FRMR (frame reject) */ - span_log(&s->logging, SPAN_LOG_FLOW, "!! FRMR (frame reject).\n"); - break; - case 0xAC: - /* XID (exchange identification) */ - span_log(&s->logging, SPAN_LOG_FLOW, "!! XID (exchange identification) frames not supported\n"); - break; - case 0xE0: - /* TEST (test) */ - span_log(&s->logging, SPAN_LOG_FLOW, "!! TEST (test) frames not supported\n"); + case LAPM_RELEASE: + s->state = LAPM_IDLE; + reset_lapm(ss); + t401_stop(ss); + report_rx_status_change(ss, SIG_STATUS_LINK_DISCONNECTED); break; default: - span_log(&s->logging, SPAN_LOG_FLOW, "!! Don't know what to do with M=%X u-frames\n", m_field); + /* Unsolicited UA */ + /* TODO: */ break; } - /*endswitch*/ + /* Clear all exceptions, busy states (self and peer) */ + /* Reset vars */ + break; + case LAPM_U_FRMR: + /* Non-recoverable error */ + /* TODO: */ + break; + case LAPM_U_XID: + if (s->configuring) + { + receive_xid(ss, frame, len); + s->configuring = FALSE; + t401_stop(ss); + switch (s->state) + { + case LAPM_IDLE: + lapm_connect(ss); + break; + case LAPM_DATA: + s->local_busy = FALSE; + tx_supervisory_frame(s, s->cmd_addr, LAPM_S_RR, 0); + break; + } + } + break; + default: break; } - /*endswitch*/ + return 0; } /*- End of function --------------------------------------------------------*/ static void lapm_hdlc_underflow(void *user_data) { lapm_state_t *s; - uint8_t buf[1024]; - int len; + v42_state_t *ss; + v42_frame_t *f; - s = (lapm_state_t *) user_data; - span_log(&s->logging, SPAN_LOG_FLOW, "HDLC underflow\n"); - if (s->state == LAPM_DATA) + ss = (v42_state_t *) user_data; + s = &ss->lapm; + if (s->ctrl_get != s->ctrl_put) { - if (!queue_empty(s->tx_queue)) - { - if ((len = queue_read(s->tx_queue, buf, s->n401)) > 0) - lapm_tx_iframe(s, buf, len, TRUE); - /*endif*/ - } - /*endif*/ + /* Send control frame */ + f = &s->ctrl_buf[s->ctrl_get]; + if (++s->ctrl_get >= V42_CTRL_FRAMES) + s->ctrl_get = 0; } - /*endif*/ + else + { + if (s->far_busy || s->configuring || s->state != LAPM_DATA) + { + hdlc_tx_flags(&s->hdlc_tx, 10); + return; + } + if (s->info_get == s->info_put && !tx_information_frame(ss)) + { + hdlc_tx_flags(&s->hdlc_tx, 10); + return; + } + /* Send info frame */ + f = &s->info_buf[s->info_get]; + if (++s->info_get >= V42_INFO_FRAMES) + s->info_get = 0; + + f->buf[0] = s->cmd_addr; + f->buf[1] = s->vs << 1; + f->buf[2] = s->vr << 1; + s->vs = (s->vs + 1) & 0x7F; + if (ss->bit_timer == 0) + t401_start(ss); + } + hdlc_tx_frame(&s->hdlc_tx, f->buf, f->len); } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) lapm_restart(lapm_state_t *s) +SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok) { -#if 0 - if (s->state != LAPM_RELEASE) + lapm_state_t *s; + v42_state_t *ss; + + ss = (v42_state_t *) user_data; + s = &ss->lapm; + if (len < 0) { - span_log(&s->logging, SPAN_LOG_FLOW, "!! lapm_restart: Not in 'Link Connection Released' state\n"); + span_log(&ss->logging, SPAN_LOG_DEBUG, "V.42 rx status is %s (%d)\n", signal_status_to_str(len), len); return; } - /*endif*/ -#endif - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "LAP.M"); - hdlc_tx_init(&s->hdlc_tx, FALSE, 1, TRUE, lapm_hdlc_underflow, s); - hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, 1, lapm_receive, s); - /* TODO: This is a bodge! */ - s->t401_timer = -1; - s->t402_timer = -1; - s->t403_timer = -1; - lapm_reset(s); - /* TODO: Maybe we should implement T_WAIT? */ - lapm_send_sabme(NULL, s); + if (!ok) + return; + + switch ((frame[1] & LAPM_FRAMETYPE_MASK)) + { + case LAPM_FRAMETYPE_I: + case LAPM_FRAMETYPE_I_ALT: + receive_information_frame(ss, frame, len); + break; + case LAPM_FRAMETYPE_S: + if (!valid_data_state(ss)) + return; + if (frame[0] == s->rsp_addr) + rx_supervisory_cmd_frame(ss, frame, len); + else + rx_supervisory_rsp_frame(ss, frame, len); + break; + case LAPM_FRAMETYPE_U: + if (frame[0] == s->rsp_addr) + rx_unnumbered_cmd_frame(ss, frame, len); + else + rx_unnumbered_rsp_frame(ss, frame, len); + break; + default: + break; + } } /*- End of function --------------------------------------------------------*/ -#if 0 -static void lapm_init(lapm_state_t *s) +static int lapm_connect(v42_state_t *ss) { - lapm_restart(s); + lapm_state_t *s; + + s = &ss->lapm; + if (s->state != LAPM_IDLE) + return -1; + + /* Negotiate params */ + //transmit_xid(s, s->cmd_addr); + + reset_lapm(ss); + /* Connect */ + s->state = LAPM_ESTABLISH; + tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_SABME | LAPM_U_PF, NULL, 0); + /* Start T401 (and not T403) */ + t401_start(ss); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int lapm_disconnect(v42_state_t *ss) +{ + lapm_state_t *s; + + s = &ss->lapm; + s->state = LAPM_RELEASE; + tx_unnumbered_frame(s, s->cmd_addr, LAPM_U_DISC | LAPM_U_PF, NULL, 0); + t401_start(ss); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int lapm_config(v42_state_t *ss) +{ + lapm_state_t *s; + + s = &ss->lapm; + s->configuring = TRUE; + if (s->state == LAPM_DATA) + { + s->local_busy = TRUE; + tx_supervisory_frame(s, s->cmd_addr, LAPM_S_RNR, 1); + } + transmit_xid(ss, s->cmd_addr); + t401_start(ss); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static void reset_lapm(v42_state_t *ss) +{ + lapm_state_t *s; + + s = &ss->lapm; + /* Reset the LAP.M state */ + s->local_busy = FALSE; + s->far_busy = FALSE; + s->vs = 0; + s->va = 0; + s->vr = 0; + /* Discard any info frames still queued for transmission */ + s->info_put = 0; + s->info_acked = 0; + s->info_get = 0; + /* Discard any control frames */ + s->ctrl_put = 0; + s->ctrl_get = 0; + + s->tx_window_size_k = ss->config.v42_tx_window_size_k; + s->rx_window_size_k = ss->config.v42_rx_window_size_k; + s->tx_n401 = ss->config.v42_tx_n401; + s->rx_n401 = ss->config.v42_rx_n401; +} +/*- End of function --------------------------------------------------------*/ + +void v42_stop(v42_state_t *ss) +{ + lapm_state_t *s; + + s = &ss->lapm; + ss->bit_timer = 0; + s->packer_process = NULL; + lapm_disconnect(ss); +} +/*- End of function --------------------------------------------------------*/ + +static void restart_lapm(v42_state_t *s) +{ + if (s->calling_party) + { + s->bit_timer = 48*8; + s->bit_timer_func = initiate_negotiation_expired; + } + else + { + lapm_hdlc_underflow(s); + } + s->lapm.packer_process = NULL; + s->lapm.state = LAPM_IDLE; } /*- End of function --------------------------------------------------------*/ -#endif static void negotiation_rx_bit(v42_state_t *s, int new_bit) { /* DC1 with even parity, 8-16 ones, DC1 with odd parity, 8-16 ones */ - //uint8_t odp = "0100010001 11111111 0100010011 11111111"; + /* uint8_t odp = "0100010001 11111111 0100010011 11111111"; */ /* V.42 OK E , 8-16 ones, C, 8-16 ones */ - //uint8_t adp_v42 = "0101000101 11111111 0110000101 11111111"; + /* uint8_t adp_v42 = "0101000101 11111111 0110000101 11111111"; */ /* V.42 disabled E, 8-16 ones, NULL, 8-16 ones */ - //uint8_t adp_nov42 = "0101000101 11111111 0000000001 11111111"; + /* uint8_t adp_nov42 = "0101000101 11111111 0000000001 11111111"; */ /* There may be no negotiation, so we need to process this data through the HDLC receiver as well */ @@ -1117,124 +1229,117 @@ static void negotiation_rx_bit(v42_state_t *s, int new_bit) } /*endif*/ new_bit &= 1; - s->rxstream = (s->rxstream << 1) | new_bit; - switch (s->rx_negotiation_step) + s->neg.rxstream = (s->neg.rxstream << 1) | new_bit; + switch (s->neg.rx_negotiation_step) { case 0: /* Look for some ones */ if (new_bit) break; /*endif*/ - s->rx_negotiation_step = 1; - s->rxbits = 0; - s->rxstream = ~1; - s->rxoks = 0; + s->neg.rx_negotiation_step = 1; + s->neg.rxbits = 0; + s->neg.rxstream = ~1; + s->neg.rxoks = 0; break; case 1: /* Look for the first character */ - if (++s->rxbits < 9) + if (++s->neg.rxbits < 9) break; /*endif*/ - s->rxstream &= 0x3FF; - if (s->calling_party && s->rxstream == 0x145) + s->neg.rxstream &= 0x3FF; + if (s->calling_party && s->neg.rxstream == 0x145) { - s->rx_negotiation_step++; + s->neg.rx_negotiation_step++; } - else if (!s->calling_party && s->rxstream == 0x111) + else if (!s->calling_party && s->neg.rxstream == 0x111) { - s->rx_negotiation_step++; + s->neg.rx_negotiation_step++; } else { - s->rx_negotiation_step = 0; + s->neg.rx_negotiation_step = 0; } /*endif*/ - s->rxbits = 0; - s->rxstream = ~0; + s->neg.rxbits = 0; + s->neg.rxstream = ~0; break; case 2: /* Look for 8 to 16 ones */ - s->rxbits++; + s->neg.rxbits++; if (new_bit) break; /*endif*/ - if (s->rxbits >= 8 && s->rxbits <= 16) - s->rx_negotiation_step++; + if (s->neg.rxbits >= 8 && s->neg.rxbits <= 16) + s->neg.rx_negotiation_step++; else - s->rx_negotiation_step = 0; + s->neg.rx_negotiation_step = 0; /*endif*/ - s->rxbits = 0; - s->rxstream = ~1; + s->neg.rxbits = 0; + s->neg.rxstream = ~1; break; case 3: /* Look for the second character */ - if (++s->rxbits < 9) + if (++s->neg.rxbits < 9) break; /*endif*/ - s->rxstream &= 0x3FF; - if (s->calling_party && s->rxstream == 0x185) + s->neg.rxstream &= 0x3FF; + if (s->calling_party && s->neg.rxstream == 0x185) { - s->rx_negotiation_step++; + s->neg.rx_negotiation_step++; } - else if (s->calling_party && s->rxstream == 0x001) + else if (s->calling_party && s->neg.rxstream == 0x001) { - s->rx_negotiation_step++; + s->neg.rx_negotiation_step++; } - else if (!s->calling_party && s->rxstream == 0x113) + else if (!s->calling_party && s->neg.rxstream == 0x113) { - s->rx_negotiation_step++; + s->neg.rx_negotiation_step++; } else { - s->rx_negotiation_step = 0; + s->neg.rx_negotiation_step = 0; } /*endif*/ - s->rxbits = 0; - s->rxstream = ~0; + s->neg.rxbits = 0; + s->neg.rxstream = ~0; break; case 4: /* Look for 8 to 16 ones */ - s->rxbits++; + s->neg.rxbits++; if (new_bit) break; /*endif*/ - if (s->rxbits >= 8 && s->rxbits <= 16) + if (s->neg.rxbits >= 8 && s->neg.rxbits <= 16) { - if (++s->rxoks >= 2) + if (++s->neg.rxoks >= 2) { - /* HIT */ - s->rx_negotiation_step++; + /* HIT - we have found the "V.42 supported" pattern. */ + s->neg.rx_negotiation_step++; if (s->calling_party) { - if (s->t400_timer >= 0) - { -fprintf(stderr, "Deleting T400 h %d\n", s->t400_timer); - span_schedule_del(&s->lapm.sched, s->t400_timer); - s->t400_timer = -1; - } - /*endif*/ - s->lapm.state = LAPM_ESTABLISH; - if (s->lapm.status_callback) - s->lapm.status_callback(s->lapm.status_callback_user_data, s->lapm.state); - /*endif*/ + t400_stop(s); + s->lapm.state = LAPM_IDLE; + report_rx_status_change(s, s->lapm.state); + restart_lapm(s); } else { - s->odp_seen = TRUE; + s->neg.odp_seen = TRUE; } /*endif*/ break; } /*endif*/ - s->rx_negotiation_step = 1; - s->rxbits = 0; - s->rxstream = ~1; + s->neg.rx_negotiation_step = 1; + s->neg.rxbits = 0; + s->neg.rxstream = ~1; } else { - s->rx_negotiation_step = 0; - s->rxbits = 0; - s->rxstream = ~0; + s->neg.rx_negotiation_step = 0; + s->neg.rxbits = 0; + s->neg.rxstream = ~0; } /*endif*/ break; @@ -1252,56 +1357,49 @@ static int v42_support_negotiation_tx_bit(v42_state_t *s) if (s->calling_party) { - if (s->txbits <= 0) + if (s->neg.txbits <= 0) { - s->txstream = 0x3FE22; - s->txbits = 36; + s->neg.txstream = 0x3FE22; + s->neg.txbits = 36; } - else if (s->txbits == 18) + else if (s->neg.txbits == 18) { - s->txstream = 0x3FF22; + s->neg.txstream = 0x3FF22; } /*endif*/ - bit = s->txstream & 1; - s->txstream >>= 1; - s->txbits--; + bit = s->neg.txstream & 1; + s->neg.txstream >>= 1; + s->neg.txbits--; } else { - if (s->odp_seen && s->txadps < 10) + if (s->neg.odp_seen && s->neg.txadps < 10) { - if (s->txbits <= 0) + if (s->neg.txbits <= 0) { - if (++s->txadps >= 10) + if (++s->neg.txadps >= 10) { - if (s->t400_timer >= 0) - { -fprintf(stderr, "Deleting T400 i %d\n", s->t400_timer); - span_schedule_del(&s->lapm.sched, s->t400_timer); - s->t400_timer = -1; - } - /*endif*/ - s->lapm.state = LAPM_ESTABLISH; - if (s->lapm.status_callback) - s->lapm.status_callback(s->lapm.status_callback_user_data, s->lapm.state); - /*endif*/ - s->txstream = 1; + t400_stop(s); + s->lapm.state = LAPM_IDLE; + report_rx_status_change(s, s->lapm.state); + s->neg.txstream = 1; + restart_lapm(s); } else { - s->txstream = 0x3FE8A; - s->txbits = 36; + s->neg.txstream = 0x3FE8A; + s->neg.txbits = 36; } /*endif*/ } - else if (s->txbits == 18) + else if (s->neg.txbits == 18) { - s->txstream = 0x3FE86; + s->neg.txstream = 0x3FE86; } /*endif*/ - bit = s->txstream & 1; - s->txstream >>= 1; - s->txbits--; + bit = s->neg.txstream & 1; + s->neg.txstream >>= 1; + s->neg.txbits--; } else { @@ -1333,6 +1431,11 @@ SPAN_DECLARE(int) v42_tx_bit(void *user_data) int bit; s = (v42_state_t *) user_data; + if (s->bit_timer && (--s->bit_timer) <= 0) + { + s->bit_timer = 0; + s->bit_timer_func(s); + } if (s->lapm.state == LAPM_DETECT) bit = v42_support_negotiation_tx_bit(s); else @@ -1342,89 +1445,124 @@ SPAN_DECLARE(int) v42_tx_bit(void *user_data) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, v42_status_func_t callback, void *user_data) +SPAN_DECLARE(int) v42_set_local_busy_status(v42_state_t *s, int busy) { - s->lapm.status_callback = callback; - s->lapm.status_callback_user_data = user_data; + int previous_busy; + + previous_busy = s->lapm.local_busy; + s->lapm.local_busy = busy; + return previous_busy; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42_get_far_busy_status(v42_state_t *s) +{ + return s->lapm.far_busy; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, modem_status_func_t status_handler, void *user_data) +{ + s->lapm.status_handler = status_handler; + s->lapm.status_user_data = user_data; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(void) v42_restart(v42_state_t *s) { - span_schedule_init(&s->lapm.sched); + hdlc_tx_init(&s->lapm.hdlc_tx, FALSE, 1, TRUE, lapm_hdlc_underflow, s); + hdlc_rx_init(&s->lapm.hdlc_rx, FALSE, FALSE, 1, lapm_receive, s); - s->lapm.we_are_originator = s->calling_party; - lapm_restart(&s->lapm); if (s->detect) { - s->txstream = ~0; - s->txbits = 0; - s->rxstream = ~0; - s->rxbits = 0; - s->rxoks = 0; - s->txadps = 0; - s->rx_negotiation_step = 0; - s->odp_seen = FALSE; -fprintf(stderr, "Setting T400 i\n"); - s->t400_timer = span_schedule_event(&s->lapm.sched, T_400, t400_expired, s); + /* We need to do the V.42 support detection sequence */ + s->neg.txstream = ~0; + s->neg.txbits = 0; + s->neg.rxstream = ~0; + s->neg.rxbits = 0; + s->neg.rxoks = 0; + s->neg.txadps = 0; + s->neg.rx_negotiation_step = 0; + s->neg.odp_seen = FALSE; + t400_start(s); s->lapm.state = LAPM_DETECT; } else { - s->lapm.state = LAPM_ESTABLISH; + /* Go directly to LAP.M mode */ + s->lapm.state = LAPM_IDLE; + restart_lapm(s); } /*endif*/ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int calling_party, int detect, v42_frame_handler_t frame_handler, void *user_data) +SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *ss, + int calling_party, + int detect, + get_msg_func_t iframe_get, + put_msg_func_t iframe_put, + void *user_data) { - int alloced; - - if (frame_handler == NULL) - return NULL; - /*endif*/ - alloced = FALSE; - if (s == NULL) + lapm_state_t *s; + + if (ss == NULL) { - if ((s = (v42_state_t *) malloc(sizeof(*s))) == NULL) + if ((ss = (v42_state_t *) malloc(sizeof(*ss))) == NULL) return NULL; - alloced = TRUE; } - memset(s, 0, sizeof(*s)); - s->calling_party = calling_party; - s->detect = detect; - s->lapm.iframe_receive = frame_handler; - s->lapm.iframe_receive_user_data = user_data; - s->lapm.debug |= (LAPM_DEBUG_LAPM_RAW | LAPM_DEBUG_LAPM_DUMP | LAPM_DEBUG_LAPM_STATE); - s->lapm.t401_timer = - s->lapm.t402_timer = - s->lapm.t403_timer = -1; + memset(ss, 0, sizeof(*ss)); - if ((s->lapm.tx_queue = queue_init(NULL, 16384, 0)) == NULL) - { - if (alloced) - free(s); - return NULL; - } - /*endif*/ - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "V.42"); - v42_restart(s); - return s; + s = &ss->lapm; + ss->calling_party = calling_party; + ss->detect = detect; + s->iframe_get = iframe_get; + s->iframe_get_user_data = user_data; + s->iframe_put = iframe_put; + s->iframe_put_user_data = user_data; + + s->state = (ss->detect) ? LAPM_DETECT : LAPM_IDLE; + s->local_busy = FALSE; + s->far_busy = FALSE; + + /* The address octet is: + Data link connection identifier (0) + Command/response (0 if answerer, 1 if originator) + Extended address (1) */ + s->cmd_addr = (LAPM_DLCI_DTE_TO_DTE << 2) | ((ss->calling_party) ? 0x02 : 0x00) | 0x01; + s->rsp_addr = (LAPM_DLCI_DTE_TO_DTE << 2) | ((ss->calling_party) ? 0x00 : 0x02) | 0x01; + + /* Set default values for the LAP.M parameters. These can be modified later. */ + ss->config.v42_tx_window_size_k = V42_DEFAULT_WINDOW_SIZE_K; + ss->config.v42_rx_window_size_k = V42_DEFAULT_WINDOW_SIZE_K; + ss->config.v42_tx_n401 = V42_DEFAULT_N_401; + ss->config.v42_rx_n401 = V42_DEFAULT_N_401; + + /* TODO: This should be part of the V.42bis startup */ + ss->config.comp = 1; + ss->config.comp_dict_size = 512; + ss->config.comp_max_string = 6; + + ss->tx_bit_rate = 28800; + + reset_lapm(ss); + + span_log_init(&ss->logging, SPAN_LOG_NONE, NULL); + span_log_set_protocol(&ss->logging, "V.42"); + return ss; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v42_release(v42_state_t *s) +SPAN_DECLARE(void) v42_release(v42_state_t *s) { - return 0; + reset_lapm(s); } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v42_free(v42_state_t *s) +SPAN_DECLARE(void) v42_free(v42_state_t *s) { + v42_release(s); free(s); - return 0; } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/v42bis.c b/libs/spandsp/src/v42bis.c index f4aee8ce93..d025ea9f7d 100644 --- a/libs/spandsp/src/v42bis.c +++ b/libs/spandsp/src/v42bis.c @@ -5,7 +5,7 @@ * * Written by Steve Underwood * - * Copyright (C) 2005 Steve Underwood + * Copyright (C) 2005, 2011 Steve Underwood * * All rights reserved. * @@ -45,19 +45,28 @@ #include "spandsp/telephony.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" +#include "spandsp/async.h" #include "spandsp/v42bis.h" #include "spandsp/private/logging.h" #include "spandsp/private/v42bis.h" /* Fixed parameters from the spec. */ -#define V42BIS_N3 8 /* Character size (bits) */ -#define V42BIS_N4 256 /* Number of characters in the alphabet */ -#define V42BIS_N5 (V42BIS_N4 + V42BIS_N6) /* Index number of first dictionary entry used to store a string */ -#define V42BIS_N6 3 /* Number of control codewords */ - +/* Character size (bits) */ +#define V42BIS_N3 8 +/* Number of characters in the alphabet */ +#define V42BIS_N4 256 +/* Index number of first dictionary entry used to store a string */ +#define V42BIS_N5 (V42BIS_N4 + V42BIS_N6) +/* Number of control codewords */ +#define V42BIS_N6 3 /* V.42bis/9.2 */ -#define V42BIS_ESC_STEP 51 +#define V42BIS_ESC_STEP 51 + +/* Compreeibility monitoring parameters for assessing automated switches between + transparent and compressed mode */ +#define COMPRESSIBILITY_MONITOR (256*V42BIS_N3) +#define COMPRESSIBILITY_MONITOR_HYSTERESIS 11 /* Control code words in compressed mode */ enum @@ -75,558 +84,627 @@ enum V42BIS_RESET = 2 /* Force reinitialisation */ }; -static __inline__ void push_compressed_raw_octet(v42bis_compress_state_t *ss, int octet) +static __inline__ void push_octet(v42bis_comp_state_t *s, int octet) { - ss->output_buf[ss->output_octet_count++] = (uint8_t) octet; - if (ss->output_octet_count >= ss->max_len) + s->output_buf[s->output_octet_count++] = (uint8_t) octet; + if (s->output_octet_count >= s->max_output_len) { - ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); - ss->output_octet_count = 0; + s->handler(s->user_data, s->output_buf, s->output_octet_count); + s->output_octet_count = 0; } } /*- End of function --------------------------------------------------------*/ -static __inline__ void push_compressed_code(v42bis_compress_state_t *ss, int code) +static __inline__ void push_octets(v42bis_comp_state_t *s, const uint8_t buf[], int len) { - ss->output_bit_buffer |= code << (32 - ss->v42bis_parm_c2 - ss->output_bit_count); - ss->output_bit_count += ss->v42bis_parm_c2; - while (ss->output_bit_count >= 8) - { - push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); - ss->output_bit_buffer <<= 8; - ss->output_bit_count -= 8; - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void push_compressed_octet(v42bis_compress_state_t *ss, int code) -{ - ss->output_bit_buffer |= code << (32 - 8 - ss->output_bit_count); - ss->output_bit_count += 8; - while (ss->output_bit_count >= 8) - { - push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); - ss->output_bit_buffer <<= 8; - ss->output_bit_count -= 8; - } -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len) -{ - int ptr; int i; - uint32_t octet; - uint32_t code; - v42bis_compress_state_t *ss; + int chunk; - ss = &s->compress; - if ((s->v42bis_parm_p0 & 2) == 0) + i = 0; + while ((s->output_octet_count + len - i) >= s->max_output_len) + { + chunk = s->max_output_len - s->output_octet_count; + memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk); + s->handler(s->user_data, s->output_buf, s->max_output_len); + s->output_octet_count = 0; + i += chunk; + } + chunk = len - i; + if (chunk > 0) + { + memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk); + s->output_octet_count += chunk; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_compressed_code(v42bis_comp_state_t *s, int code) +{ + s->bit_buffer |= code << s->bit_count; + s->bit_count += s->v42bis_parm_c2; + while (s->bit_count >= 8) + { + push_octet(s, s->bit_buffer & 0xFF); + s->bit_buffer >>= 8; + s->bit_count -= 8; + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void push_octet_alignment(v42bis_comp_state_t *s) +{ + if ((s->bit_count & 7)) + { + s->bit_count += (8 - (s->bit_count & 7)); + while (s->bit_count >= 8) + { + push_octet(s, s->bit_buffer & 0xFF); + s->bit_buffer >>= 8; + s->bit_count -= 8; + } + } +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ void flush_octets(v42bis_comp_state_t *s) +{ + if (s->output_octet_count > 0) + { + s->handler(s->user_data, s->output_buf, s->output_octet_count); + s->output_octet_count = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +static void dictionary_init(v42bis_comp_state_t *s) +{ + int i; + + memset(s->dict, 0, sizeof(s->dict)); + for (i = 0; i < V42BIS_N4; i++) + s->dict[i + V42BIS_N6].node_octet = i; + s->v42bis_parm_c1 = V42BIS_N5; + s->v42bis_parm_c2 = V42BIS_N3 + 1; + s->v42bis_parm_c3 = V42BIS_N4 << 1; + s->last_matched = 0; + s->update_at = 0; + s->last_added = 0; + s->bit_buffer = 0; + s->bit_count = 0; + s->flushed_length = 0; + s->string_length = 0; + s->escape_code = 0; + s->transparent = TRUE; + s->escaped = FALSE; + s->compression_performance = COMPRESSIBILITY_MONITOR; +} +/*- End of function --------------------------------------------------------*/ + +static uint16_t match_octet(v42bis_comp_state_t *s, uint16_t at, uint8_t octet) +{ + uint16_t e; + + if (at == 0) + return octet + V42BIS_N6; + e = s->dict[at].child; + while (e) + { + if (s->dict[e].node_octet == octet) + return e; + e = s->dict[e].next; + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static uint16_t add_octet_to_dictionary(v42bis_comp_state_t *s, uint16_t at, uint8_t octet) +{ + uint16_t newx; + uint16_t next; + uint16_t e; + + newx = s->v42bis_parm_c1; + s->dict[newx].node_octet = octet; + s->dict[newx].parent = at; + s->dict[newx].child = 0; + s->dict[newx].next = s->dict[at].child; + s->dict[at].child = newx; + next = newx; + /* 6.5 Recovering a dictionary entry to use next */ + do + { + /* 6.5(a) and (b) */ + if (++next == s->v42bis_parm_n2) + next = V42BIS_N5; + } + while (s->dict[next].child); + /* 6.5(c) We need to reuse a leaf node */ + if (s->dict[next].parent) + { + /* 6.5(d) Detach the leaf node from its parent, and re-use it */ + e = s->dict[next].parent; + if (s->dict[e].child == next) + { + s->dict[e].child = s->dict[next].next; + } + else + { + e = s->dict[e].child; + while (s->dict[e].next != next) + e = s->dict[e].next; + s->dict[e].next = s->dict[next].next; + } + } + s->v42bis_parm_c1 = next; + return newx; +} +/*- End of function --------------------------------------------------------*/ + +static void send_string(v42bis_comp_state_t *s) +{ + push_octets(s, s->string, s->string_length); + s->string_length = 0; + s->flushed_length = 0; +} +/*- End of function --------------------------------------------------------*/ + +static void expand_codeword_to_string(v42bis_comp_state_t *s, uint16_t code) +{ + int i; + uint16_t p; + + /* Work out the length */ + for (i = 0, p = code; p; i++) + p = s->dict[p].parent; + s->string_length += i; + /* Now expand the known length of string */ + i = s->string_length - 1; + for (p = code; p; ) + { + s->string[i--] = s->dict[p].node_octet; + p = s->dict[p].parent; + } +} +/*- End of function --------------------------------------------------------*/ + +static void send_encoded_data(v42bis_comp_state_t *s, uint16_t code) +{ + int i; + + /* Update compressibility metric */ + /* Integrate at the compressed bit rate, and leak at the pre-compression bit rate */ + s->compression_performance += (s->v42bis_parm_c2 - s->compression_performance*s->string_length*V42BIS_N3/COMPRESSIBILITY_MONITOR); + if (s->transparent) + { + for (i = 0; i < s->string_length; i++) + { + push_octet(s, s->string[i]); + if (s->string[i] == s->escape_code) + { + push_octet(s, V42BIS_EID); + s->escape_code += V42BIS_ESC_STEP; + } + } + } + else + { + /* Allow for any escape octets in the string */ + for (i = 0; i < s->string_length; i++) + { + if (s->string[i] == s->escape_code) + s->escape_code += V42BIS_ESC_STEP; + } + /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */ + while (code >= s->v42bis_parm_c3) + { + /* We need to increase the codeword size */ + /* 7.4(a) */ + push_compressed_code(s, V42BIS_STEPUP); + /* 7.4(b) */ + s->v42bis_parm_c2++; + /* 7.4(c) */ + s->v42bis_parm_c3 <<= 1; + /* 7.4(d) this might need to be repeated, so we loop */ + } + /* 7.5 Transfer - output the last state of the string */ + push_compressed_code(s, code); + } + s->string_length = 0; + s->flushed_length = 0; +} +/*- End of function --------------------------------------------------------*/ + +static void go_compressed(v42bis_state_t *ss) +{ + v42bis_comp_state_t *s; + + s = &ss->compress; + if (!s->transparent) + return; + span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to compressed mode\n"); + /* Switch out of transparent now, between codes. We need to send the octet which did not + match, just before switching. */ + if (s->last_matched) + { + s->update_at = s->last_matched; + send_encoded_data(s, s->last_matched); + s->last_matched = 0; + } + push_octet(s, s->escape_code); + push_octet(s, V42BIS_ECM); + s->bit_buffer = 0; + s->transparent = FALSE; +} +/*- End of function --------------------------------------------------------*/ + +static void go_transparent(v42bis_state_t *ss) +{ + v42bis_comp_state_t *s; + + s = &ss->compress; + if (s->transparent) + return; + span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to transparent mode\n"); + /* Switch into transparent now, between codes, and the unmatched octet should + go out in transparent mode, just below */ + if (s->last_matched) + { + s->update_at = s->last_matched; + send_encoded_data(s, s->last_matched); + s->last_matched = 0; + } + s->last_added = 0; + push_compressed_code(s, V42BIS_ETM); + push_octet_alignment(s); + s->transparent = TRUE; +} +/*- End of function --------------------------------------------------------*/ + +static void monitor_for_mode_change(v42bis_state_t *ss) +{ + v42bis_comp_state_t *s; + + s = &ss->compress; + switch (s->compression_mode) + { + case V42BIS_COMPRESSION_MODE_DYNAMIC: + /* 7.8 Data compressibility test */ + if (s->transparent) + { + if (s->compression_performance < COMPRESSIBILITY_MONITOR - COMPRESSIBILITY_MONITOR_HYSTERESIS) + { + /* 7.8.1 Transition to compressed mode */ + go_compressed(ss); + } + } + else + { + if (s->compression_performance > COMPRESSIBILITY_MONITOR) + { + /* 7.8.2 Transition to transparent mode */ + go_transparent(ss); + } + } + /* 7.8.3 Reset function - TODO */ + break; + case V42BIS_COMPRESSION_MODE_ALWAYS: + if (s->transparent) + go_compressed(ss); + break; + case V42BIS_COMPRESSION_MODE_NEVER: + if (!s->transparent) + go_transparent(ss); + break; + } +} +/*- End of function --------------------------------------------------------*/ + +static int v42bis_comp_init(v42bis_comp_state_t *s, + int p1, + int p2, + put_msg_func_t handler, + void *user_data, + int max_output_len) +{ + memset(s, 0, sizeof(*s)); + s->v42bis_parm_n2 = p1; + s->v42bis_parm_n7 = p2; + s->handler = handler; + s->user_data = user_data; + s->max_output_len = (max_output_len < V42BIS_MAX_OUTPUT_LENGTH) ? max_output_len : V42BIS_MAX_OUTPUT_LENGTH; + s->output_octet_count = 0; + dictionary_init(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int comp_exit(v42bis_comp_state_t *s) +{ + s->v42bis_parm_n2 = 0; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *ss, const uint8_t buf[], int len) +{ + v42bis_comp_state_t *s; + int i; + uint16_t code; + + s = &ss->compress; + if (!s->v42bis_parm_p0) { /* Compression is off - just push the incoming data out */ - for (i = 0; i < len - ss->max_len; i += ss->max_len) - ss->handler(ss->user_data, buf + i, ss->max_len); - if (i < len) - ss->handler(ss->user_data, buf + i, len - i); + push_octets(s, buf, len); return 0; } - ptr = 0; - if (ss->first && len > 0) + for (i = 0; i < len; ) { - octet = buf[ptr++]; - ss->string_code = octet + V42BIS_N6; - if (octet == ss->escape_code) + /* 6.4 Add the string to the dictionary */ + if (s->update_at) { - push_compressed_octet(ss, ss->escape_code); - ss->escape_code += V42BIS_ESC_STEP; - push_compressed_octet(ss, V42BIS_EID); + if (match_octet(s, s->update_at, buf[i]) == 0) + s->last_added = add_octet_to_dictionary(s, s->update_at, buf[i]); + s->update_at = 0; } - else + /* Match string */ + while (i < len) { - push_compressed_octet(ss, octet); - } - ss->first = FALSE; - } - while (ptr < len) - { - octet = buf[ptr++]; - if ((ss->dict[ss->string_code].children[octet >> 5] & (1 << (octet & 0x1F)))) - { - /* The leaf exists. Now find it in the table. */ - /* TODO: This is a brute force scan for a match. We need something better. */ - for (code = 0; code < ss->v42bis_parm_c3; code++) + code = match_octet(s, s->last_matched, buf[i]); + if (code == 0) { - if (ss->dict[code].parent_code == ss->string_code && ss->dict[code].node_octet == octet) - break; - } - } - else - { - /* The leaf does not exist. */ - code = s->v42bis_parm_n2; - } - /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry - created by the last invocation of the string matching procedure, then the - next character shall be read and appended to the string and this step - repeated. */ - if (code < ss->v42bis_parm_c3 && code != ss->latest_code) - { - /* The string was found */ - ss->string_code = code; - ss->string_length++; - } - else - { - /* The string is not in the table. */ - if (!ss->transparent) - { - /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */ - while (ss->v42bis_parm_c1 >= ss->v42bis_parm_c3 && ss->v42bis_parm_c3 <= s->v42bis_parm_n2) - { - /* We need to increase the codeword size */ - /* 7.4(a) */ - push_compressed_code(ss, V42BIS_STEPUP); - /* 7.4(b) */ - ss->v42bis_parm_c2++; - /* 7.4(c) */ - ss->v42bis_parm_c3 <<= 1; - /* 7.4(d) this might need to be repeated, so we loop */ - } - /* 7.5 Transfer - output the last state of the string */ - push_compressed_code(ss, ss->string_code); - } - /* 7.6 Dictionary updating */ - /* 6.4 Add the string to the dictionary */ - /* 6.4(b) The string is not in the table. */ - if (code != ss->latest_code && ss->string_length < s->v42bis_parm_n7) - { - ss->latest_code = ss->v42bis_parm_c1; - /* 6.4(a) The length of the string is in range for adding to the dictionary */ - /* If the last code was a leaf, it no longer is */ - ss->dict[ss->string_code].leaves++; - ss->dict[ss->string_code].children[octet >> 5] |= (1 << (octet & 0x1F)); - /* The new one is definitely a leaf */ - ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->string_code; - ss->dict[ss->v42bis_parm_c1].leaves = 0; - ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) octet; - /* 7.7 Node recovery */ - /* 6.5 Recovering a dictionary entry to use next */ - for (;;) - { - /* 6.5(a) and (b) */ - if ((int) (++ss->v42bis_parm_c1) >= s->v42bis_parm_n2) - ss->v42bis_parm_c1 = V42BIS_N5; - /* 6.5(c) We need to reuse a leaf node */ - if (ss->dict[ss->v42bis_parm_c1].leaves) - continue; - if (ss->dict[ss->v42bis_parm_c1].parent_code == 0xFFFF) - break; - /* 6.5(d) Detach the leaf node from its parent, and re-use it */ - /* Possibly make the parent a leaf node again */ - ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; - ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].children[ss->dict[ss->v42bis_parm_c1].node_octet >> 5] &= ~(1 << (ss->dict[ss->v42bis_parm_c1].node_octet & 0x1F)); - ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; - break; - } - } - else - { - ss->latest_code = 0xFFFFFFFF; - } - /* 7.8 Data compressibility test */ - /* Filter on the balance of what went into the compressor, and what came out */ - ss->compressibility_filter += ((((8*ss->string_length - ss->v42bis_parm_c2) << 20) - ss->compressibility_filter) >> 10); - if (ss->compression_mode == V42BIS_COMPRESSION_MODE_DYNAMIC) - { - /* Work out if it is appropriate to change between transparent and - compressed mode. */ - if (ss->transparent) - { - if (ss->compressibility_filter > 0) - { - if (++ss->compressibility_persistence > 1000) - { - /* Schedule a switch to compressed mode */ - ss->change_transparency = -1; - ss->compressibility_persistence = 0; - } - } - else - { - ss->compressibility_persistence = 0; - } - } - else - { - if (ss->compressibility_filter < 0) - { - if (++ss->compressibility_persistence > 1000) - { - /* Schedule a switch to transparent mode */ - ss->change_transparency = 1; - ss->compressibility_persistence = 0; - } - } - else - { - ss->compressibility_persistence = 0; - } - } - } - if (ss->change_transparency) - { - if (ss->change_transparency < 0) - { - if (ss->transparent) - { - printf("Going compressed\n"); - /* 7.8.1 Transition to compressed mode */ - /* Switch out of transparent now, between codes. We need to send the octet which did not - match, just before switching. */ - if (octet == ss->escape_code) - { - push_compressed_octet(ss, ss->escape_code); - ss->escape_code += V42BIS_ESC_STEP; - push_compressed_octet(ss, V42BIS_EID); - } - else - { - push_compressed_octet(ss, octet); - } - push_compressed_octet(ss, ss->escape_code); - ss->escape_code += V42BIS_ESC_STEP; - push_compressed_octet(ss, V42BIS_ECM); - ss->transparent = FALSE; - } - } - else - { - if (!ss->transparent) - { - printf("Going transparent\n"); - /* 7.8.2 Transition to transparent mode */ - /* Switch into transparent now, between codes, and the unmatched octet should - go out in transparent mode, just below */ - push_compressed_code(ss, V42BIS_ETM); - ss->transparent = TRUE; - } - } - ss->change_transparency = 0; - } - /* 7.8.3 Reset function - TODO */ - ss->string_code = octet + V42BIS_N6; - ss->string_length = 1; - } - if (ss->transparent) - { - if (octet == ss->escape_code) - { - push_compressed_octet(ss, ss->escape_code); - ss->escape_code += V42BIS_ESC_STEP; - push_compressed_octet(ss, V42BIS_EID); - } - else - { - push_compressed_octet(ss, octet); + s->update_at = s->last_matched; + send_encoded_data(s, s->last_matched); + s->last_matched = 0; + break; + } + if (code == s->last_added) + { + s->last_added = 0; + send_encoded_data(s, s->last_matched); + s->last_matched = 0; + break; + } + s->last_matched = code; + /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry + created by the last invocation of the string matching procedure, then the + next character shall be read and appended to the string and this step + repeated. */ + s->string[s->string_length++] = buf[i++]; + /* 6.4(a) The string must not exceed N7 in length */ + if (s->string_length + s->flushed_length == s->v42bis_parm_n7) + { + send_encoded_data(s, s->last_matched); + s->last_matched = 0; + break; } } + monitor_for_mode_change(ss); } return 0; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s) +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *ss) { - v42bis_compress_state_t *ss; - - ss = &s->compress; - if (!ss->transparent) - { - /* Output the last state of the string */ - push_compressed_code(ss, ss->string_code); - /* TODO: We use a positive FLUSH at all times. It is really needed, if the - previous step resulted in no leftover bits. */ - push_compressed_code(ss, V42BIS_FLUSH); - } - while (ss->output_bit_count > 0) - { - push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); - ss->output_bit_buffer <<= 8; - ss->output_bit_count -= 8; - } - /* Now push out anything remaining. */ - if (ss->output_octet_count > 0) - { - ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); - ss->output_octet_count = 0; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -#if 0 -SPAN_DECLARE(int) v42bis_compress_dump(v42bis_state_t *s) -{ - int i; + v42bis_comp_state_t *s; + int len; - for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + s = &ss->compress; + if (s->update_at) + return 0; + if (s->last_matched) { - if (s->compress.dict[i].parent_code != 0xFFFF) - { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); - } + len = s->string_length; + send_encoded_data(s, s->last_matched); + s->flushed_length += len; } + if (!s->transparent) + { + s->update_at = s->last_matched; + s->last_matched = 0; + s->flushed_length = 0; + push_compressed_code(s, V42BIS_FLUSH); + push_octet_alignment(s); + } + flush_octets(s); return 0; } /*- End of function --------------------------------------------------------*/ -#endif -SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len) +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int len) { - int ptr; + v42bis_comp_state_t *s; int i; - int this_length; - uint8_t *string; - uint32_t code; - uint32_t new_code; - int code_len; - v42bis_decompress_state_t *ss; - uint8_t decode_buf[V42BIS_MAX_STRING_SIZE]; + int j; + int yyy; + uint16_t code; + uint16_t p; + uint8_t ch; + uint8_t in; - ss = &s->decompress; - if ((s->v42bis_parm_p0 & 1) == 0) + s = &ss->decompress; + if (!s->v42bis_parm_p0) { /* Compression is off - just push the incoming data out */ - for (i = 0; i < len - ss->max_len; i += ss->max_len) - ss->handler(ss->user_data, buf + i, ss->max_len); - if (i < len) - ss->handler(ss->user_data, buf + i, len - i); + push_octets(s, buf, len); return 0; } - ptr = 0; - code_len = (ss->transparent) ? 8 : ss->v42bis_parm_c2; - for (;;) + for (i = 0; i < len; ) { - /* Fill up the bit buffer. */ - while (ss->input_bit_count < (32 - 8) && ptr < len) + if (s->transparent) { - ss->input_bit_count += 8; - ss->input_bit_buffer |= (uint32_t) buf[ptr++] << (32 - ss->input_bit_count); - } - if (ss->input_bit_count < code_len) - break; - new_code = ss->input_bit_buffer >> (32 - code_len); - ss->input_bit_count -= code_len; - ss->input_bit_buffer <<= code_len; - if (ss->transparent) - { - code = new_code; - if (ss->escaped) + in = buf[i]; + if (s->escaped) { - ss->escaped = FALSE; - switch (code) + /* Command */ + s->escaped = FALSE; + switch (in) { case V42BIS_ECM: - printf("Hit V42BIS_ECM\n"); - ss->transparent = FALSE; - code_len = ss->v42bis_parm_c2; - break; + /* Enter compressed mode */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ECM\n"); + send_string(s); + s->transparent = FALSE; + s->update_at = s->last_matched; + s->last_matched = 0; + i++; + continue; case V42BIS_EID: - printf("Hit V42BIS_EID\n"); - ss->output_buf[ss->output_octet_count++] = ss->escape_code; - ss->escape_code += V42BIS_ESC_STEP; - if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) - { - ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); - ss->output_octet_count = 0; - } + /* Escape symbol */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_EID\n"); + in = s->escape_code; + s->escape_code += V42BIS_ESC_STEP; break; case V42BIS_RESET: - printf("Hit V42BIS_RESET\n"); - break; + /* Reset dictionary */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_RESET\n"); + /* TODO: */ + send_string(s); + dictionary_init(s); + i++; + continue; default: - printf("Hit V42BIS_???? - %" PRIu32 "\n", code); - break; + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_???? - %" PRIu32 "\n", in); + return -1; } } - else if (code == ss->escape_code) + else if (in == s->escape_code) { - ss->escaped = TRUE; + s->escaped = TRUE; + i++; + continue; } - else + + yyy = TRUE; + for (j = 0; j < 2 && yyy; j++) { - ss->output_buf[ss->output_octet_count++] = (uint8_t) code; - if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) + if (s->update_at) { - ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); - ss->output_octet_count = 0; + if (match_octet(s, s->update_at, in) == 0) + s->last_added = add_octet_to_dictionary(s, s->update_at, in); + s->update_at = 0; + } + + code = match_octet(s, s->last_matched, in); + if (code == 0) + { + s->update_at = s->last_matched; + send_string(s); + s->last_matched = 0; + } + else if (code == s->last_added) + { + s->last_added = 0; + send_string(s); + s->last_matched = 0; + } + else + { + s->last_matched = code; + s->string[s->string_length++] = in; + if (s->string_length + s->flushed_length == s->v42bis_parm_n7) + { + send_string(s); + s->last_matched = 0; + } + i++; + yyy = FALSE; } } } else { - if (new_code < V42BIS_N6) + /* Get code from input */ + while (s->bit_count < s->v42bis_parm_c2 && i < len) + { + s->bit_buffer |= buf[i++] << s->bit_count; + s->bit_count += 8; + } + if (s->bit_count < s->v42bis_parm_c2) + continue; + code = s->bit_buffer & ((1 << s->v42bis_parm_c2) - 1); + s->bit_buffer >>= s->v42bis_parm_c2; + s->bit_count -= s->v42bis_parm_c2; + + if (code < V42BIS_N6) { /* We have a control code. */ - switch (new_code) + switch (code) { case V42BIS_ETM: - printf("Hit V42BIS_ETM\n"); - ss->transparent = TRUE; - code_len = 8; + /* Enter transparent mode */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ETM\n"); + s->bit_count = 0; + s->transparent = TRUE; + s->last_matched = 0; + s->last_added = 0; break; case V42BIS_FLUSH: - printf("Hit V42BIS_FLUSH\n"); - v42bis_decompress_flush(s); + /* Flush signal */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_FLUSH\n"); + s->bit_count = 0; break; case V42BIS_STEPUP: - /* We need to increase the codeword size */ - printf("Hit V42BIS_STEPUP\n"); - if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) - { - /* Invalid condition */ + /* Increase code word size */ + span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_STEPUP\n"); + s->v42bis_parm_c2++; + s->v42bis_parm_c3 <<= 1; + if (s->v42bis_parm_c2 > (s->v42bis_parm_n2 >> 3)) return -1; - } - code_len = ++ss->v42bis_parm_c2; - ss->v42bis_parm_c3 <<= 1; break; } continue; } - if (ss->first) - { - ss->first = FALSE; - ss->octet = new_code - V42BIS_N6; - ss->output_buf[0] = (uint8_t) ss->octet; - ss->output_octet_count = 1; - if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) - { - ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); - ss->output_octet_count = 0; - } - ss->old_code = new_code; - continue; - } - /* Start at the end of the buffer, and decode backwards */ - string = &decode_buf[V42BIS_MAX_STRING_SIZE - 1]; - /* Check the received code is valid. It can't be too big, as we pulled only the expected number - of bits from the input stream. It could, however, be unknown. */ - if (ss->dict[new_code].parent_code == 0xFFFF) + /* Regular codeword */ + if (code == s->v42bis_parm_c1) return -1; - /* Otherwise we do a straight decode of the new code. */ - code = new_code; - /* Trace back through the octets which form the string, and output them. */ - while (code >= V42BIS_N5) + expand_codeword_to_string(s, code); + if (s->update_at) { -if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} - *string-- = ss->dict[code].node_octet; - code = ss->dict[code].parent_code; - } - *string = (uint8_t) (code - V42BIS_N6); - ss->octet = code - V42BIS_N6; - /* Output the decoded string. */ - this_length = V42BIS_MAX_STRING_SIZE - (int) (string - decode_buf); - for (i = 0; i < this_length; i++) - { - if (string[i] == ss->escape_code) - ss->escape_code += V42BIS_ESC_STEP; - } - memcpy(ss->output_buf + ss->output_octet_count, string, this_length); - ss->output_octet_count += this_length; - if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) - { - ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); - ss->output_octet_count = 0; - } - /* 6.4 Add the string to the dictionary */ - if (ss->last_length < s->v42bis_parm_n7) - { - /* 6.4(a) The string does not exceed N7 in length */ - if (ss->last_old_code != ss->old_code - || - ss->last_extra_octet != *string) + ch = s->string[0]; + if ((p = match_octet(s, s->update_at, ch)) == 0) { - /* 6.4(b) The string is not in the table. */ - ss->dict[ss->old_code].leaves++; - /* The new one is definitely a leaf */ - ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->old_code; - ss->dict[ss->v42bis_parm_c1].leaves = 0; - ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) ss->octet; - /* 6.5 Recovering a dictionary entry to use next */ - for (;;) - { - /* 6.5(a) and (b) */ - if (++ss->v42bis_parm_c1 >= s->v42bis_parm_n2) - ss->v42bis_parm_c1 = V42BIS_N5; - /* 6.5(c) We need to reuse a leaf node */ - if (ss->dict[ss->v42bis_parm_c1].leaves) - continue; - /* 6.5(d) This is a leaf node, so re-use it */ - /* Possibly make the parent a leaf node again */ - if (ss->dict[ss->v42bis_parm_c1].parent_code != 0xFFFF) - ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; - ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; - break; - } + s->last_added = add_octet_to_dictionary(s, s->update_at, ch); + if (code == s->v42bis_parm_c1) + return -1; + } + else if (p == s->last_added) + { + s->last_added = 0; } } - /* Record the addition to the dictionary, so we can check for repeat attempts - at the next code - see II.4.3 */ - ss->last_old_code = ss->old_code; - ss->last_extra_octet = *string; - - ss->old_code = new_code; - ss->last_length = this_length; + s->update_at = ((s->string_length + s->flushed_length) == s->v42bis_parm_n7) ? 0 : code; + /* Allow for any escapes which may be in this string */ + for (j = 0; j < s->string_length; j++) + { + if (s->string[j] == s->escape_code) + s->escape_code += V42BIS_ESC_STEP; + } + send_string(s); } } return 0; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s) +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *ss) { - v42bis_decompress_state_t *ss; - - ss = &s->decompress; - /* Push out anything remaining. */ - if (ss->output_octet_count > 0) - { - ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); - ss->output_octet_count = 0; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -#if 0 -SPAN_DECLARE(int) v42bis_decompress_dump(v42bis_state_t *s) -{ - int i; + v42bis_comp_state_t *s; + int len; - for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) - { - if (s->decompress.dict[i].parent_code != 0xFFFF) - { - printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); - } - } + s = &ss->decompress; + len = s->string_length; + send_string(s); + s->flushed_length += len; + flush_octets(s); return 0; } /*- End of function --------------------------------------------------------*/ -#endif SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode) { s->compress.compression_mode = mode; - switch (mode) - { - case V42BIS_COMPRESSION_MODE_ALWAYS: - s->compress.change_transparency = -1; - break; - case V42BIS_COMPRESSION_MODE_NEVER: - s->compress.change_transparency = 1; - break; - } } /*- End of function --------------------------------------------------------*/ @@ -634,14 +712,14 @@ SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, int negotiated_p0, int negotiated_p1, int negotiated_p2, - v42bis_frame_handler_t frame_handler, - void *frame_user_data, - int max_frame_len, - v42bis_data_handler_t data_handler, - void *data_user_data, - int max_data_len) + put_msg_func_t encode_handler, + void *encode_user_data, + int max_encode_len, + put_msg_func_t decode_handler, + void *decode_user_data, + int max_decode_len) { - int i; + int ret; if (negotiated_p1 < V42BIS_MIN_DICTIONARY_SIZE || negotiated_p1 > 65535) return NULL; @@ -653,55 +731,18 @@ SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, return NULL; } memset(s, 0, sizeof(*s)); + span_log_init(&s->logging, SPAN_LOG_NONE, NULL); + span_log_set_protocol(&s->logging, "V.42bis"); - s->compress.handler = frame_handler; - s->compress.user_data = frame_user_data; - s->compress.max_len = (max_frame_len < 1024) ? max_frame_len : 1024; - - s->decompress.handler = data_handler; - s->decompress.user_data = data_user_data; - s->decompress.max_len = (max_data_len < 1024) ? max_data_len : 1024; - - s->v42bis_parm_p0 = negotiated_p0; /* default is both ways off */ - - s->v42bis_parm_n1 = top_bit(negotiated_p1 - 1) + 1; - s->v42bis_parm_n2 = negotiated_p1; - s->v42bis_parm_n7 = negotiated_p2; - - /* 6.5 */ - s->compress.v42bis_parm_c1 = - s->decompress.v42bis_parm_c1 = V42BIS_N5; - - s->compress.v42bis_parm_c2 = - s->decompress.v42bis_parm_c2 = V42BIS_N3 + 1; - - s->compress.v42bis_parm_c3 = - s->decompress.v42bis_parm_c3 = 2*V42BIS_N4; - - s->compress.first = - s->decompress.first = TRUE; - for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) + if ((ret = v42bis_comp_init(&s->compress, negotiated_p1, negotiated_p2, encode_handler, encode_user_data, max_encode_len))) + return NULL; + if ((ret = v42bis_comp_init(&s->decompress, negotiated_p1, negotiated_p2, decode_handler, decode_user_data, max_decode_len))) { - s->compress.dict[i].parent_code = - s->decompress.dict[i].parent_code = 0xFFFF; - s->compress.dict[i].leaves = - s->decompress.dict[i].leaves = 0; + comp_exit(&s->compress); + return NULL; } - /* Point the root nodes for decompression to themselves. It doesn't matter much what - they are set to, as long as they are considered "known" codes. */ - for (i = 0; i < V42BIS_N5; i++) - s->decompress.dict[i].parent_code = (uint16_t) i; - s->compress.string_code = 0xFFFFFFFF; - s->compress.latest_code = 0xFFFFFFFF; - s->compress.transparent = TRUE; - s->compress.first = TRUE; - - s->decompress.last_old_code = 0xFFFFFFFF; - s->decompress.last_extra_octet = -1; - s->decompress.transparent = TRUE; - s->compress.first = TRUE; - - s->compress.compression_mode = V42BIS_COMPRESSION_MODE_DYNAMIC; + s->compress.v42bis_parm_p0 = negotiated_p0 & 2; + s->decompress.v42bis_parm_p0 = negotiated_p0 & 1; return s; } @@ -715,7 +756,8 @@ SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s) SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) { - free(s); + comp_exit(&s->compress); + comp_exit(&s->decompress); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/tests/Makefile.am b/libs/spandsp/tests/Makefile.am index 52769e78d8..150977f39c 100644 --- a/libs/spandsp/tests/Makefile.am +++ b/libs/spandsp/tests/Makefile.am @@ -23,11 +23,11 @@ LIBS += $(TESTLIBS) noinst_DATA = sound_c1_8k.wav sound_c3_8k.wav -EXTRA_DIST = regression_tests.sh \ +EXTRA_DIST = fax_tests.sh \ + regression_tests.sh \ tsb85_extra_tests.sh \ - v42bis_tests.sh \ - fax_tests.sh \ tsb85_tests.sh \ + v42bis_tests.sh \ msvc/adsi_tests.vcproj \ msvc/complex_tests.vcproj \ msvc/complex_vector_float_tests.vcproj \ @@ -102,15 +102,15 @@ noinst_PROGRAMS = adsi_tests \ super_tone_rx_tests \ super_tone_tx_tests \ swept_tone_tests \ - t4_tests \ t31_tests \ - t38_decode \ t38_core_tests \ + t38_decode \ t38_gateway_tests \ t38_gateway_to_terminal_tests \ t38_non_ecm_buffer_tests \ t38_terminal_tests \ t38_terminal_to_gateway_tests \ + t4_tests \ time_scale_tests \ timezone_tests \ tone_detect_tests \ @@ -126,8 +126,6 @@ noinst_PROGRAMS = adsi_tests \ v8_tests \ vector_float_tests \ vector_int_tests \ - testadsi \ - testfax \ tsb85_tests noinst_HEADERS = echo_monitor.h \ @@ -364,12 +362,6 @@ vector_float_tests_LDADD = $(LIBDIR) -lspandsp vector_int_tests_SOURCES = vector_int_tests.c vector_int_tests_LDADD = $(LIBDIR) -lspandsp -testadsi_SOURCES = testadsi.c -testadsi_LDADD = $(LIBDIR) -lspandsp - -testfax_SOURCES = testfax.c -testfax_LDADD = $(LIBDIR) -lspandsp - # We need to create the CSS files for echo cancellation tests. sound_c1_8k.wav sound_c3_8k.wav: make_g168_css$(EXEEXT) diff --git a/libs/spandsp/tests/fax_tests.c b/libs/spandsp/tests/fax_tests.c index 084a2b034f..a01747fb15 100644 --- a/libs/spandsp/tests/fax_tests.c +++ b/libs/spandsp/tests/fax_tests.c @@ -80,7 +80,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase B:", i); + snprintf(tag, sizeof(tag), "%c: Phase B", i); printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_rx_parameters(s, tag); return T30_ERR_OK; @@ -93,7 +93,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase D:", i); + snprintf(tag, sizeof(tag), "%c: Phase D", i); printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); @@ -136,7 +136,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase E:", i); + snprintf(tag, sizeof(tag), "%c: Phase E", i); printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); diff --git a/libs/spandsp/tests/oki_adpcm_tests.c b/libs/spandsp/tests/oki_adpcm_tests.c index 0b761d9607..b36968c59a 100644 --- a/libs/spandsp/tests/oki_adpcm_tests.c +++ b/libs/spandsp/tests/oki_adpcm_tests.c @@ -123,6 +123,9 @@ int main(int argc, char *argv[]) } } + encoded_fd = -1; + inhandle = NULL; + oki_enc_state = NULL; if (encoded_file_name) { if ((encoded_fd = open(encoded_file_name, O_RDONLY)) < 0) diff --git a/libs/spandsp/tests/pcap_parse.c b/libs/spandsp/tests/pcap_parse.c index e5e0014826..900f957068 100644 --- a/libs/spandsp/tests/pcap_parse.c +++ b/libs/spandsp/tests/pcap_parse.c @@ -34,14 +34,17 @@ #include #include #include + +#if defined(HAVE_PCAP_H) #include +#endif #include #include -#if defined(__HPUX) || defined(__CYGWIN) || defined(__FreeBSD__) +#if defined(__HPUX) || defined(__CYGWIN__) || defined(__FreeBSD__) #include #endif #include -#ifndef __CYGWIN +#if !defined(__CYGWIN__) #include #endif #include @@ -55,7 +58,7 @@ #include "spandsp.h" #include "pcap_parse.h" -#if defined(__HPUX) || defined(__DARWIN) || defined(__CYGWIN) || defined(__FreeBSD__) +#if defined(__HPUX) || defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__) struct iphdr { @@ -90,15 +93,22 @@ typedef struct _ether_hdr { char ether_dst[6]; char ether_src[6]; - u_int16_t ether_type; /* we only need the type, so we can determine, if the next header is IPv4 or IPv6 */ + u_int16_t ether_type; } ether_hdr; +typedef struct _null_hdr +{ + uint32_t pf_type; +} null_hdr; + +#if !defined(__CYGWIN__) typedef struct _ipv6_hdr { char dontcare[6]; u_int8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */ char dontcare2[33]; } ipv6_hdr; +#endif char errbuf[PCAP_ERRBUF_SIZE]; @@ -119,9 +129,14 @@ int pcap_scan_pkts(const char *file, int total_pkts; uint32_t pktlen; ether_hdr *ethhdr; + null_hdr *nullhdr; struct iphdr *iphdr; +#if !defined(__CYGWIN__) ipv6_hdr *ip6hdr; +#endif struct udphdr *udphdr; + int datalink; + int packet_type; total_pkts = 0; if ((pcap = pcap_open_offline(file, errbuf)) == NULL) @@ -129,6 +144,15 @@ int pcap_scan_pkts(const char *file, fprintf(stderr, "Can't open PCAP file '%s'\n", file); return -1; } + datalink = pcap_datalink(pcap); + /* DLT_EN10MB seems to apply to all forms of ethernet, not just the 10MB kind. */ + if (datalink != DLT_EN10MB && datalink != DLT_NULL) + { + fprintf(stderr, "Unsupported data link type %d\n", datalink); + return -1; + } + + printf("Datalink type %d\n", datalink); pkthdr = NULL; pktdata = NULL; #if defined(HAVE_PCAP_NEXT_EX) @@ -143,14 +167,43 @@ int pcap_scan_pkts(const char *file, while ((pktdata = (uint8_t *) pcap_next(pcap, pkthdr)) != NULL) { #endif - ethhdr = (ether_hdr *) pktdata; - if (ntohs(ethhdr->ether_type) != 0x0800 /* IPv4 */ - && - ntohs(ethhdr->ether_type) != 0x86dd) /* IPv6 */ + if (datalink == DLT_EN10MB) + { + ethhdr = (ether_hdr *) pktdata; + packet_type = ntohs(ethhdr->ether_type); +#if !defined(__CYGWIN__) + if (packet_type != 0x0800 /* IPv4 */ + && + packet_type != 0x86DD) /* IPv6 */ +#else + if (packet_type != 0x0800) /* IPv4 */ +#endif + { + continue; + } + iphdr = (struct iphdr *) ((uint8_t *) ethhdr + sizeof(*ethhdr)); + } + else if (datalink == DLT_NULL) + { + nullhdr = (null_hdr *) pktdata; + if (nullhdr->pf_type != PF_INET && nullhdr->pf_type != PF_INET6) + continue; + iphdr = (struct iphdr *) ((uint8_t *) nullhdr + sizeof(*nullhdr)); + } + else { continue; } - iphdr = (struct iphdr *) ((uint8_t *) ethhdr + sizeof(*ethhdr)); +#if 0 + { + int i; + printf("--- %d -", pkthdr->caplen); + for (i = 0; i < pkthdr->caplen; i++) + printf(" %02x", pktdata[i]); + printf("\n"); + } +#endif +#if !defined(__CYGWIN__) if (iphdr && iphdr->version == 6) { /* ipv6 */ @@ -161,11 +214,12 @@ int pcap_scan_pkts(const char *file, udphdr = (struct udphdr *) ((uint8_t *) ip6hdr + sizeof(*ip6hdr)); } else +#endif { /* ipv4 */ if (iphdr->protocol != IPPROTO_UDP) continue; -#if defined(__DARWIN) || defined(__CYGWIN) || defined(__FreeBSD__) +#if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__) udphdr = (struct udphdr *) ((uint8_t *) iphdr + (iphdr->ihl << 2) + 4); pktlen = (uint32_t) ntohs(udphdr->uh_ulen); #elif defined ( __HPUX) @@ -176,24 +230,39 @@ int pcap_scan_pkts(const char *file, pktlen = (uint32_t) ntohs(udphdr->len); #endif } + timing_update_handler(user_data, &pkthdr->ts); + if (src_addr && ntohl(iphdr->saddr) != src_addr) continue; +#if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__) + if (src_port && ntohs(udphdr->uh_sport) != src_port) +#else if (src_port && ntohs(udphdr->source) != src_port) +#endif continue; if (dest_addr && ntohl(iphdr->daddr) != dest_addr) continue; +#if defined(__DARWIN) || defined(__CYGWIN__) || defined(__FreeBSD__) + if (dest_port && ntohs(udphdr->uh_dport) != dest_port) +#else if (dest_port && ntohs(udphdr->dest) != dest_port) +#endif continue; + if (pkthdr->len != pkthdr->caplen) + { + fprintf(stderr, "Truncated packet - total len = %d, captured len = %d\n", pkthdr->len, pkthdr->caplen); + exit(2); + } body = (const uint8_t *) udphdr; - body += sizeof(udphdr); - body_len = pktlen - sizeof(udphdr); + body += sizeof(struct udphdr); + body_len = pktlen - sizeof(struct udphdr); packet_handler(user_data, body, body_len); total_pkts++; } - fprintf(stderr, "In pcap %s, npkts %d\n", file, total_pkts); + fprintf(stderr, "In pcap %s there were %d accepted packets\n", file, total_pkts); pcap_close(pcap); return 0; diff --git a/libs/spandsp/tests/regression_tests.sh b/libs/spandsp/tests/regression_tests.sh index 56f628fdd3..2a305531a6 100755 --- a/libs/spandsp/tests/regression_tests.sh +++ b/libs/spandsp/tests/regression_tests.sh @@ -846,25 +846,23 @@ echo v29_tests completed OK #fi #echo v32bis_tests completed OK -#./v42_tests >$STDOUT_DEST 2>$STDERR_DEST -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo v42_tests failed! -# exit $RETVAL -#fi -#echo v42_tests completed OK -echo v42_tests not enabled +./v42_tests >$STDOUT_DEST 2>$STDERR_DEST +RETVAL=$? +if [ $RETVAL != 0 ] +then + echo v42_tests failed! + exit $RETVAL +fi +echo v42_tests completed OK -#./v42bis_tests.sh >/dev/null -#RETVAL=$? -#if [ $RETVAL != 0 ] -#then -# echo v42bis_tests failed! -# exit $RETVAL -#fi -#echo v42bis_tests completed OK -echo v42bis_tests not enabled +./v42bis_tests.sh >/dev/null +RETVAL=$? +if [ $RETVAL != 0 ] +then + echo v42bis_tests failed! + exit $RETVAL +fi +echo v42bis_tests completed OK ./v8_tests >$STDOUT_DEST 2>$STDERR_DEST RETVAL=$? diff --git a/libs/spandsp/tests/t31_tests.c b/libs/spandsp/tests/t31_tests.c index 49919d052d..c31c1d3aab 100644 --- a/libs/spandsp/tests/t31_tests.c +++ b/libs/spandsp/tests/t31_tests.c @@ -280,7 +280,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase B:", i); + snprintf(tag, sizeof(tag), "%c: Phase B", i); printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_rx_parameters(s, tag); return T30_ERR_OK; @@ -293,7 +293,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (int) (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase D:", i); + snprintf(tag, sizeof(tag), "%c: Phase D", i); printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); @@ -308,7 +308,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase E:", i); + snprintf(tag, sizeof(tag), "%c: Phase E", i); printf("Phase E handler on channel %c\n", i); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); diff --git a/libs/spandsp/tests/t38_decode.c b/libs/spandsp/tests/t38_decode.c index 39c8ec6b4b..bc6d6ce58a 100644 --- a/libs/spandsp/tests/t38_decode.c +++ b/libs/spandsp/tests/t38_decode.c @@ -1,7 +1,7 @@ /* * SpanDSP - a series of DSP components for telephony * - * pcap-parse.c + * t38_decode.c * * Written by Steve Underwood * @@ -53,6 +53,7 @@ #define OUTPUT_FILE_NAME "t38pcap.tif" t38_terminal_state_t *t38_state; +struct timeval now; static int phase_b_handler(t30_state_t *s, void *user_data, int result) { @@ -110,29 +111,35 @@ static int timing_update(void *user_data, struct timeval *ts) t38_core_state_t *t38_core; logging_state_t *logging; int samples; + int partial; static int64_t current = 0; int64_t when; int64_t diff; + memcpy(&now, ts, sizeof(now)); + when = ts->tv_sec*1000000LL + ts->tv_usec; if (current == 0) current = when; diff = when - current; samples = diff/125LL; - if (samples > 0) + while (samples > 0) { + partial = (samples > 160) ? 160 : samples; + //fprintf(stderr, "Update time by %d samples\n", partial); logging = t38_terminal_get_logging_state(t38_state); - span_log_bump_samples(logging, samples); + span_log_bump_samples(logging, partial); t38_core = t38_terminal_get_t38_core_state(t38_state); logging = t38_core_get_logging_state(t38_core); - span_log_bump_samples(logging, samples); + span_log_bump_samples(logging, partial); t30 = t38_terminal_get_t30_state(t38_state); logging = t30_get_logging_state(t30); - span_log_bump_samples(logging, samples); + span_log_bump_samples(logging, partial); - t38_terminal_send_timeout(t38_state, samples); + t38_terminal_send_timeout(t38_state, partial); current = when; + samples -= partial; } return 0; } @@ -188,6 +195,7 @@ int main(int argc, char *argv[]) use_ecm = FALSE; t38_version = 1; + options = 0; input_file_name = INPUT_FILE_NAME; fill_removal = FALSE; use_tep = FALSE; @@ -196,7 +204,7 @@ int main(int argc, char *argv[]) src_port = 0; dest_addr = 0; dest_port = 0; - while ((opt = getopt(argc, argv, "D:d:eFi:m:S:s:tv:")) != -1) + while ((opt = getopt(argc, argv, "D:d:eFi:m:oS:s:tv:")) != -1) { switch (opt) { @@ -218,6 +226,9 @@ int main(int argc, char *argv[]) case 'm': supported_modems = atoi(optarg); break; + case 'o': + options = atoi(optarg); + break; case 'S': src_addr = atoi(optarg); break; @@ -272,6 +283,9 @@ int main(int argc, char *argv[]) if (pcap_scan_pkts(input_file_name, src_addr, src_port, dest_addr, dest_port, timing_update, process_packet, NULL)) exit(2); + /* Push the time along, to flush out any remaining activity from the application. */ + now.tv_sec += 60; + timing_update(NULL, &now); } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t38_gateway_to_terminal_tests.c b/libs/spandsp/tests/t38_gateway_to_terminal_tests.c index 9a27985794..17d4bf93e7 100644 --- a/libs/spandsp/tests/t38_gateway_to_terminal_tests.c +++ b/libs/spandsp/tests/t38_gateway_to_terminal_tests.c @@ -595,7 +595,7 @@ int main(int argc, char *argv[]) logging = t38_core_get_logging_state(t38_core); span_log_bump_samples(logging, SAMPLES_PER_CHUNK); logging = &t38_state_a->audio.modems.v17_rx.logging; - span_log_bump_samples(logging, t30_len_a); + span_log_bump_samples(logging, SAMPLES_PER_CHUNK); logging = t38_terminal_get_logging_state(t38_state_b); span_log_bump_samples(logging, SAMPLES_PER_CHUNK); diff --git a/libs/spandsp/tests/timezone_tests.c b/libs/spandsp/tests/timezone_tests.c index fb72f98437..f3096e86dd 100644 --- a/libs/spandsp/tests/timezone_tests.c +++ b/libs/spandsp/tests/timezone_tests.c @@ -1,86 +1,86 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * timezone_tests.c - Timezone handling for time interpretation - * - * Written by Steve Underwood - * - * Copyright (C) 2010 Steve Underwood - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*! \page timezone_tests_page Timezone handling tests -\section timezone_tests_page_sec_1 What does it do? -*/ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -//#if defined(WITH_SPANDSP_INTERNALS) -#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES -//#endif - -#include "spandsp.h" - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE (!FALSE) -#endif - -int main(int argc, char *argv[]) -{ - struct tm tms; - struct tm *tmp = &tms; - time_t ltime; - tz_t *tz; - - /* Get the current time */ - ltime = time(NULL); - - /* Compute the local current time now for several localities, based on Posix tz strings */ - - tz = tz_init(NULL, "GMT0GMT0,M10.5.0,M3.5.0"); - tz_localtime(tz, tmp, ltime); - printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst)); - - tz_init(tz, "CST-8CST-8,M10.5.0,M3.5.0"); - tz_localtime(tz, tmp, ltime); - printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst)); - - tz_init(tz, "AEST-10AEDT-11,M10.5.0,M3.5.0"); - tz_localtime(tz, tmp, ltime); - printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst)); - - tz_free(tz); - - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ +/* + * SpanDSP - a series of DSP components for telephony + * + * timezone_tests.c - Timezone handling for time interpretation + * + * Written by Steve Underwood + * + * Copyright (C) 2010 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*! \page timezone_tests_page Timezone handling tests +\section timezone_tests_page_sec_1 What does it do? +*/ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +//#if defined(WITH_SPANDSP_INTERNALS) +#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES +//#endif + +#include "spandsp.h" + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +int main(int argc, char *argv[]) +{ + struct tm tms; + struct tm *tmp = &tms; + time_t ltime; + tz_t *tz; + + /* Get the current time */ + ltime = time(NULL); + + /* Compute the local current time now for several localities, based on Posix tz strings */ + + tz = tz_init(NULL, "GMT0GMT0,M10.5.0,M3.5.0"); + tz_localtime(tz, tmp, ltime); + printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst)); + + tz_init(tz, "CST-8CST-8,M10.5.0,M3.5.0"); + tz_localtime(tz, tmp, ltime); + printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst)); + + tz_init(tz, "AEST-10AEDT-11,M10.5.0,M3.5.0"); + tz_localtime(tz, tmp, ltime); + printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst)); + + tz_free(tz); + + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/tsb85_tests.c b/libs/spandsp/tests/tsb85_tests.c index ffab4e7737..e6786add0b 100644 --- a/libs/spandsp/tests/tsb85_tests.c +++ b/libs/spandsp/tests/tsb85_tests.c @@ -217,7 +217,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase D:", i); + snprintf(tag, sizeof(tag), "%c: Phase D", i); printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result)); log_transfer_statistics(s, tag); @@ -260,7 +260,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result) char tag[20]; i = (intptr_t) user_data; - snprintf(tag, sizeof(tag), "%c: Phase E:", i); + snprintf(tag, sizeof(tag), "%c: Phase E", i); printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result)); log_transfer_statistics(s, tag); log_tx_parameters(s, tag); diff --git a/libs/spandsp/tests/v17_tests.c b/libs/spandsp/tests/v17_tests.c index 22d793c2df..40d4a3de25 100644 --- a/libs/spandsp/tests/v17_tests.c +++ b/libs/spandsp/tests/v17_tests.c @@ -63,6 +63,7 @@ display of modem status is maintained. #include #include #if defined(HAVE_FENV_H) +#define __USE_GNU #include #endif diff --git a/libs/spandsp/tests/v27ter_tests.c b/libs/spandsp/tests/v27ter_tests.c index dc2053c692..d33953c318 100644 --- a/libs/spandsp/tests/v27ter_tests.c +++ b/libs/spandsp/tests/v27ter_tests.c @@ -62,6 +62,7 @@ display of modem status is maintained. #include #include #if defined(HAVE_FENV_H) +#define __USE_GNU #include #endif diff --git a/libs/spandsp/tests/v29_tests.c b/libs/spandsp/tests/v29_tests.c index 8644ac286d..72689a5288 100644 --- a/libs/spandsp/tests/v29_tests.c +++ b/libs/spandsp/tests/v29_tests.c @@ -62,6 +62,7 @@ display of modem status is maintained. #include #include #if defined(HAVE_FENV_H) +#define __USE_GNU #include #endif diff --git a/libs/spandsp/tests/v42_tests.c b/libs/spandsp/tests/v42_tests.c index 7968ff6199..3b6ca16c57 100644 --- a/libs/spandsp/tests/v42_tests.c +++ b/libs/spandsp/tests/v42_tests.c @@ -5,7 +5,7 @@ * * Written by Steve Underwood * - * Copyright (C) 2004 Steve Underwood + * Copyright (C) 2004, 2011 Steve Underwood * * All rights reserved. * @@ -32,10 +32,11 @@ then exchanged between them. */ #if defined(HAVE_CONFIG_H) -#include +#include "config.h" #endif #include +#include #include #include #include @@ -48,6 +49,7 @@ then exchanged between them. v42_state_t caller; v42_state_t answerer; +int variable_length; int rx_next[3] = {0}; int tx_next[3] = {0}; @@ -55,66 +57,120 @@ int tx_next[3] = {0}; static void v42_status(void *user_data, int status) { int x; - - x = (intptr_t) user_data; - printf("%d: Status is '%s' (%d)\n", x, lapm_status_to_str(status), status); - //if (status == LAPM_DATA) - // lapm_tx_iframe((x == 1) ? &caller.lapm : &answerer.lapm, "ABCDEFGHIJ", 10, 1); -} -static void v42_frames(void *user_data, const uint8_t *msg, int len) + x = (intptr_t) user_data; + if (status < 0) + printf("%d: Status is '%s' (%d)\n", x, signal_status_to_str(status), status); + else + printf("%d: Status is '%s' (%d)\n", x, lapm_status_to_str(status), status); +} +/*- End of function --------------------------------------------------------*/ + +static int v42_get_frames(void *user_data, uint8_t *msg, int len) +{ + int i; + int j; + int k; + int x; + + if (len < 0) + { + v42_status(user_data, len); + return 0; + } + x = (intptr_t) user_data; + if (variable_length) + { + j = make_mask32(len); + do + k = j & rand(); + while (k > len); + } + else + { + k = len; + } + for (i = 0; i < k; i++) + msg[i] = tx_next[x]++; + return k; +} +/*- End of function --------------------------------------------------------*/ + +static void v42_put_frames(void *user_data, const uint8_t *msg, int len) { int i; int x; - + + if (len < 0) + { + v42_status(user_data, len); + return; + } x = (intptr_t) user_data; for (i = 0; i < len; i++) { if (msg[i] != (rx_next[x] & 0xFF)) + { printf("%d: Mismatch 0x%02X 0x%02X\n", x, msg[i], rx_next[x] & 0xFF); + exit(2); + } rx_next[x]++; } printf("%d: Got frame len %d\n", x, len); } +/*- End of function --------------------------------------------------------*/ int main(int argc, char *argv[]) { int i; int bit; - uint8_t buf[1024]; + int insert_caller_bit_errors; + int insert_answerer_bit_errors; + int opt; - v42_init(&caller, TRUE, TRUE, v42_frames, (void *) 1); - v42_init(&answerer, FALSE, TRUE, v42_frames, (void *) 2); + insert_caller_bit_errors = FALSE; + insert_answerer_bit_errors = FALSE; + variable_length = FALSE; + while ((opt = getopt(argc, argv, "bv")) != -1) + { + switch (opt) + { + case 'b': + insert_caller_bit_errors = 11000; + insert_answerer_bit_errors = 10000; + break; + case 'v': + variable_length = TRUE; + break; + default: + //usage(); + exit(2); + break; + } + } + + v42_init(&caller, TRUE, TRUE, v42_get_frames, v42_put_frames, (void *) 1); + v42_init(&answerer, FALSE, TRUE, v42_get_frames, v42_put_frames, (void *) 2); v42_set_status_callback(&caller, v42_status, (void *) 1); v42_set_status_callback(&answerer, v42_status, (void *) 2); - span_log_set_level(&caller.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG); + v42_restart(&caller); + v42_restart(&answerer); + + span_log_set_level(&caller.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_DEBUG); span_log_set_tag(&caller.logging, "caller"); - span_log_set_level(&caller.lapm.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG); - span_log_set_tag(&caller.lapm.logging, "caller"); - span_log_set_level(&caller.lapm.sched.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG); - span_log_set_tag(&caller.lapm.sched.logging, "caller"); - span_log_set_level(&answerer.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG); + span_log_set_level(&answerer.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_DEBUG); span_log_set_tag(&answerer.logging, "answerer"); - span_log_set_level(&answerer.lapm.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG); - span_log_set_tag(&answerer.lapm.logging, "answerer"); - span_log_set_level(&answerer.lapm.sched.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_DEBUG); - span_log_set_tag(&answerer.lapm.sched.logging, "answerer"); - for (i = 0; i < 100000; i++) + + for (i = 0; i < 1000000; i++) { bit = v42_tx_bit(&caller); + if (insert_caller_bit_errors && i%insert_caller_bit_errors == 0) + bit ^= 1; v42_rx_bit(&answerer, bit); bit = v42_tx_bit(&answerer); - //if (i%10000 == 0) - // bit ^= 1; + if (insert_answerer_bit_errors && i%insert_answerer_bit_errors == 0) + bit ^= 1; v42_rx_bit(&caller, bit); - span_schedule_update(&caller.lapm.sched, 4); - span_schedule_update(&answerer.lapm.sched, 4); - buf[0] = tx_next[1]; - if (lapm_tx(&caller.lapm, buf, 1) == 1) - tx_next[1]++; - buf[0] = tx_next[2]; - if (lapm_tx(&answerer.lapm, buf, 1) == 1) - tx_next[2]++; } return 0; } diff --git a/libs/spandsp/tests/v42bis_tests.c b/libs/spandsp/tests/v42bis_tests.c index 2218d1a94b..e59d80711b 100644 --- a/libs/spandsp/tests/v42bis_tests.c +++ b/libs/spandsp/tests/v42bis_tests.c @@ -34,7 +34,7 @@ of this file should exactly match the original file. */ #if defined(HAVE_CONFIG_H) -#include +#include "config.h" #endif #include @@ -46,12 +46,14 @@ of this file should exactly match the original file. #include #include +//#if defined(WITH_SPANDSP_INTERNALS) +#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES +//#endif + #include "spandsp.h" -#include "spandsp/private/v42bis.h" - #define COMPRESSED_FILE_NAME "v42bis_tests.v42bis" -#define OUTPUT_FILE_NAME "v42bis_tests.out" +#define DECOMPRESSED_FILE_NAME "v42bis_tests.out" int in_octets_to_date = 0; int out_octets_to_date = 0; @@ -85,36 +87,96 @@ int main(int argc, char *argv[]) int out_fd; int do_compression; int do_decompression; + int stutter_compression; + int stutter_time; + int seg; + int opt; time_t now; + const char *argv0; + const char *original_file; + const char *compressed_file; + const char *decompressed_file; - do_compression = TRUE; - do_decompression = TRUE; - if (argc < 2) + argv0 = argv[0]; + do_compression = FALSE; + do_decompression = FALSE; + stutter_compression = FALSE; + while ((opt = getopt(argc, argv, "cds")) != -1) { - fprintf(stderr, "Usage: %s \n", argv[0]); + switch (opt) + { + case 'c': + do_compression = TRUE; + break; + case 'd': + do_decompression = TRUE; + break; + case 's': + stutter_compression = TRUE; + break; + default: + //usage(); + exit(2); + break; + } + } + argc -= optind; + argv += optind; + if (argc < 1) + { + fprintf(stderr, "Usage: %s [-c] [-d] [-s] []\n", argv0); exit(2); } if (do_compression) { - if ((in_fd = open(argv[1], O_RDONLY)) < 0) + original_file = argv[0]; + compressed_file = COMPRESSED_FILE_NAME; + } + else + { + original_file = NULL; + compressed_file = argv[0]; + } + decompressed_file = (argc > 1) ? argv[1] : DECOMPRESSED_FILE_NAME; + if (do_compression) + { + stutter_time = rand() & 0x3FF; + if ((in_fd = open(argv[0], O_RDONLY)) < 0) { - fprintf(stderr, "Error opening file '%s'.\n", argv[1]); + fprintf(stderr, "Error opening file '%s'.\n", original_file); exit(2); } - if ((v42bis_fd = open(COMPRESSED_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) + if ((v42bis_fd = open(compressed_file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { - fprintf(stderr, "Error opening file '%s'.\n", COMPRESSED_FILE_NAME); + fprintf(stderr, "Error opening file '%s'.\n", compressed_file); exit(2); } time(&now); v42bis_init(&state_a, 3, 512, 6, frame_handler, (void *) (intptr_t) v42bis_fd, 512, data_handler, NULL, 512); - v42bis_compression_control(&state_a, V42BIS_COMPRESSION_MODE_ALWAYS); + span_log_set_level(&state_a.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + span_log_set_tag(&state_a.logging, "XXX"); + //v42bis_compression_control(&state_a, V42BIS_COMPRESSION_MODE_ALWAYS); in_octets_to_date = 0; out_octets_to_date = 0; while ((len = read(in_fd, buf, 1024)) > 0) { - if (v42bis_compress(&state_a, buf, len)) + seg = 0; + if (stutter_compression) + { + while ((len - seg) >= stutter_time) + { + if (v42bis_compress(&state_a, buf + seg, stutter_time)) + { + fprintf(stderr, "Bad return code from compression\n"); + exit(2); + } + v42bis_compress_flush(&state_a); + seg += stutter_time; + stutter_time = rand() & 0x3FF; + } + } + if (v42bis_compress(&state_a, buf + seg, len - seg)) { fprintf(stderr, "Bad return code from compression\n"); exit(2); @@ -130,19 +192,21 @@ int main(int argc, char *argv[]) if (do_decompression) { /* Now open the files for the decompression. */ - if ((v42bis_fd = open(COMPRESSED_FILE_NAME, O_RDONLY)) < 0) + if ((v42bis_fd = open(compressed_file, O_RDONLY)) < 0) { - fprintf(stderr, "Error opening file '%s'.\n", COMPRESSED_FILE_NAME); + fprintf(stderr, "Error opening file '%s'.\n", compressed_file); exit(2); } - if ((out_fd = open(OUTPUT_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) + if ((out_fd = open(decompressed_file, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { - fprintf(stderr, "Error opening file '%s'.\n", OUTPUT_FILE_NAME); + fprintf(stderr, "Error opening file '%s'.\n", decompressed_file); exit(2); } time(&now); v42bis_init(&state_b, 3, 512, 6, frame_handler, (void *) (intptr_t) v42bis_fd, 512, data_handler, (void *) (intptr_t) out_fd, 512); + span_log_set_level(&state_b.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + span_log_set_tag(&state_b.logging, "XXX"); in_octets_to_date = 0; out_octets_to_date = 0; while ((len = read(v42bis_fd, buf, 1024)) > 0) diff --git a/libs/spandsp/tests/v42bis_tests.sh b/libs/spandsp/tests/v42bis_tests.sh index 39ae75e0df..fa86645785 100755 --- a/libs/spandsp/tests/v42bis_tests.sh +++ b/libs/spandsp/tests/v42bis_tests.sh @@ -17,7 +17,7 @@ BASE=../test-data/itu/v56ter -./v42bis_tests ${BASE}/1.TST +./v42bis_tests -c -d ${BASE}/1.TST RETVAL=$? if [ $RETVAL != 0 ] then @@ -29,7 +29,7 @@ if [ $RETVAL != 0 ] then exit $RETVAL fi -./v42bis_tests ${BASE}/1X04.TST +./v42bis_tests -c -d ${BASE}/1X04.TST RETVAL=$? if [ $RETVAL != 0 ] then @@ -41,7 +41,7 @@ if [ $RETVAL != 0 ] then exit $RETVAL fi -./v42bis_tests ${BASE}/1X30.TST +./v42bis_tests -c -d ${BASE}/1X30.TST RETVAL=$? if [ $RETVAL != 0 ] then @@ -53,7 +53,7 @@ if [ $RETVAL != 0 ] then exit $RETVAL fi -./v42bis_tests ${BASE}/2.TST +./v42bis_tests -c -d ${BASE}/2.TST RETVAL=$? if [ $RETVAL != 0 ] then @@ -65,8 +65,9 @@ if [ $RETVAL != 0 ] then exit $RETVAL fi -./v42bis_tests ${BASE}/2X10.TST +./v42bis_tests -c -d ${BASE}/2X10.TST RETVAL=$? + if [ $RETVAL != 0 ] then exit $RETVAL @@ -77,7 +78,7 @@ if [ $RETVAL != 0 ] then exit $RETVAL fi -./v42bis_tests ${BASE}/3.TST +./v42bis_tests -c -d ${BASE}/3.TST RETVAL=$? if [ $RETVAL != 0 ] then @@ -89,7 +90,7 @@ if [ $RETVAL != 0 ] then exit $RETVAL fi -./v42bis_tests ${BASE}/3X06.TST +./v42bis_tests -c -d ${BASE}/3X06.TST RETVAL=$? if [ $RETVAL != 0 ] then @@ -101,7 +102,7 @@ if [ $RETVAL != 0 ] then exit $RETVAL fi -./v42bis_tests ${BASE}/4.TST +./v42bis_tests -c -d ${BASE}/4.TST RETVAL=$? if [ $RETVAL != 0 ] then @@ -113,7 +114,7 @@ if [ $RETVAL != 0 ] then exit $RETVAL fi -./v42bis_tests ${BASE}/4X04.TST +./v42bis_tests -c -d ${BASE}/4X04.TST RETVAL=$? if [ $RETVAL != 0 ] then @@ -125,7 +126,7 @@ if [ $RETVAL != 0 ] then exit $RETVAL fi -./v42bis_tests ${BASE}/5.TST +./v42bis_tests -c -d ${BASE}/5.TST RETVAL=$? if [ $RETVAL != 0 ] then @@ -137,7 +138,7 @@ if [ $RETVAL != 0 ] then exit $RETVAL fi -./v42bis_tests ${BASE}/5X16.TST +./v42bis_tests -c -d ${BASE}/5X16.TST RETVAL=$? if [ $RETVAL != 0 ] then diff --git a/libs/spandsp/unpack_gsm0610_data.sh b/libs/spandsp/unpack_gsm0610_data.sh index 482334c79e..d1f8b92a23 100755 --- a/libs/spandsp/unpack_gsm0610_data.sh +++ b/libs/spandsp/unpack_gsm0610_data.sh @@ -53,7 +53,7 @@ else cd gsm0610 fi -if [ $1x = --no-exe-runx ] +if [ $1x == --no-exe-runx ] then # Run the .exe files, which should be here ./FR_A.EXE @@ -77,7 +77,7 @@ rm -rf READ_FRA.TXT rm -rf ACTION rm -rf unpacked -if [ $1x = --no-exex ] +if [ $1x == --no-exex ] then # We need to prepare the .exe files to be run separately rm -rf *.INP diff --git a/libs/spandsp/wrapper.xsl b/libs/spandsp/wrapper.xsl index 89e314d781..2f432262b3 100644 --- a/libs/spandsp/wrapper.xsl +++ b/libs/spandsp/wrapper.xsl @@ -2,4 +2,4 @@ version='1.0'> css.css - \ No newline at end of file +