From cdfa8bf7aec16823ec402254a185920e47582f5c Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 21 Dec 2010 15:11:22 -0500 Subject: [PATCH] freetdm: Added new OOB event FTDM_OOB_POLARITY_REVERSE Added new channel command FTDM_COMMAND_SET_POLARITY ftmod_wanpipe - Added support to enqueue polarity events on FXO lines ftmod_wanpipe - Added support to set polarity on FXS lines ftmod_analog - Added support to answer and hangup FXO lines on polarity reverse ftmod_analog - Added support to reverse polarity in the FXS line on answer and hangup mod_freetdm - Added parameters answer-on-polarity, hangup-on-polarity and polarity-delay to enable those analog features --- libs/freetdm/conf/freetdm.conf.xml | 63 +++++++- libs/freetdm/mod_freetdm/mod_freetdm.c | 12 ++ libs/freetdm/src/ftdm_io.c | 16 +- .../src/ftmod/ftmod_analog/ftdm_analog.h | 8 +- .../src/ftmod/ftmod_analog/ftmod_analog.c | 142 +++++++++++++++++- .../src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c | 57 ++++--- libs/freetdm/src/include/freetdm.h | 6 + libs/freetdm/src/include/private/ftdm_core.h | 3 + libs/freetdm/src/include/private/ftdm_types.h | 5 +- 9 files changed, 277 insertions(+), 35 deletions(-) diff --git a/libs/freetdm/conf/freetdm.conf.xml b/libs/freetdm/conf/freetdm.conf.xml index 63a3ea62cd..43197af4bc 100644 --- a/libs/freetdm/conf/freetdm.conf.xml +++ b/libs/freetdm/conf/freetdm.conf.xml @@ -12,31 +12,81 @@ with the signaling protocols that you can run on top of your I/O interfaces. + - + - - + + + + + + + - - + + + + + + + + + + + + + + + + - diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 7e099853a6..0709021aca 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2717,6 +2717,9 @@ static switch_status_t load_config(void) char *hold_music = NULL; char *fail_dial_regex = NULL; const char *enable_callerid = "true"; + const char *answer_polarity = "false"; + const char *hangup_polarity = "false"; + int polarity_delay = 600; int callwaiting = 1; uint32_t span_id = 0, to = 0, max = 0; @@ -2788,6 +2791,12 @@ static switch_status_t load_config(void) dial_regex = val; } else if (!strcasecmp(var, "enable-callerid")) { enable_callerid = val; + } else if (!strcasecmp(var, "answer-polarity-reverse")) { + answer_polarity = val; + } else if (!strcasecmp(var, "hangup-polarity-reverse")) { + hangup_polarity = val; + } else if (!strcasecmp(var, "polarity-delay")) { + polarity_delay = atoi(val); } else if (!strcasecmp(var, "fail-dial-regex")) { fail_dial_regex = val; } else if (!strcasecmp(var, "hold-music")) { @@ -2848,6 +2857,9 @@ static switch_status_t load_config(void) "max_dialstr", &max, "hotline", hotline ? hotline : "", "enable_callerid", enable_callerid, + "answer_polarity_reverse", answer_polarity, + "hangup_polarity_reverse", hangup_polarity, + "polarity_delay", &polarity_delay, "callwaiting", &callwaiting, FTDM_TAG_END) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM analog span %s\n", ftdm_span_get_name(span)); diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index c04dd85a17..955729df36 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1541,6 +1541,7 @@ end: ftdm_mutex_unlock(ftdmchan->span->mutex); } else { ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "VETO state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); + goto done; } /* there is an inherent race here between set and check of the change flag but we do not care because @@ -1570,7 +1571,7 @@ end: ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "state change from %s to %s was most likely not processed after aprox %dms\n", ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME); } - +done: return ok ? FTDM_SUCCESS : FTDM_FAIL; } @@ -2289,8 +2290,15 @@ static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const c ftdm_channel_set_state(file, func, line, chan, FTDM_CHANNEL_STATE_HANGUP, 1); } else { /* the signaling stack did not touch the state, - * core is responsible from clearing flags and stuff */ - ftdm_channel_close(&chan); + * core is responsible from clearing flags and stuff, however, because ftmod_analog + * is a bitch in a serious need of refactoring, we also check whether the channel is open + * to avoid an spurious warning about the channel not being open. This is because ftmod_analog + * does not follow our convention of sending SIGEVENT_STOP and waiting for the user to move + * to HANGUP (implicitly through ftdm_channel_call_hangup(), as soon as ftmod_analog is fixed + * this check can be removed */ + if (ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) { + ftdm_channel_close(&chan); + } } return FTDM_SUCCESS; } @@ -3933,7 +3941,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *dat if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "cannot write in channel not open\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "cannot write in channel not open\n"); snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open"); status = FTDM_FAIL; goto done; diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h index 2c79822b29..39cbc5ff2b 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h @@ -37,7 +37,9 @@ typedef enum { FTDM_ANALOG_RUNNING = (1 << 0), - FTDM_ANALOG_CALLERID = (1 << 1) + FTDM_ANALOG_CALLERID = (1 << 1), + FTDM_ANALOG_ANSWER_POLARITY_REVERSE = (1 << 2), + FTDM_ANALOG_HANGUP_POLARITY_REVERSE = (1 << 3) } ftdm_analog_flag_t; #define FTDM_MAX_HOTLINE_STR 20 @@ -47,11 +49,13 @@ struct ftdm_analog_data { uint32_t flags; uint32_t max_dialstr; uint32_t wait_dialtone_timeout; + uint32_t polarity_delay; uint32_t digit_timeout; char hotline[FTDM_MAX_HOTLINE_STR]; }; - +/* Analog flags to be set in the sflags (signaling flags) channel memeber */ +#define AF_POLARITY_REVERSE (1 << 0) static void *ftdm_analog_run(ftdm_thread_t *me, void *obj); typedef struct ftdm_analog_data ftdm_analog_data_t; diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c index 0acf70b18d..981df5dcc9 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c @@ -184,6 +184,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) uint32_t digit_timeout = 10; uint32_t wait_dialtone_timeout = 30000; uint32_t max_dialstr = MAX_DTMF; + uint32_t polarity_delay = 600; const char *var, *val; int *intval; uint32_t flags = FTDM_ANALOG_CALLERID; @@ -236,6 +237,29 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) } else { flags &= ~FTDM_ANALOG_CALLERID; } + } else if (!strcasecmp(var, "answer_polarity_reverse")) { + if (!(val = va_arg(ap, char *))) { + break; + } + if (ftdm_true(val)) { + flags |= FTDM_ANALOG_ANSWER_POLARITY_REVERSE; + } else { + flags &= ~FTDM_ANALOG_ANSWER_POLARITY_REVERSE; + } + } else if (!strcasecmp(var, "hangup_polarity_reverse")) { + if (!(val = va_arg(ap, char *))) { + break; + } + if (ftdm_true(val)) { + flags |= FTDM_ANALOG_HANGUP_POLARITY_REVERSE; + } else { + flags &= ~FTDM_ANALOG_HANGUP_POLARITY_REVERSE; + } + } else if (!strcasecmp(var, "polarity_delay")) { + if (!(intval = va_arg(ap, int *))) { + break; + } + polarity_delay = *intval; } else if (!strcasecmp(var, "callwaiting")) { if (!(intval = va_arg(ap, int *))) { break; @@ -276,6 +300,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) analog_data->flags = flags; analog_data->digit_timeout = digit_timeout; analog_data->wait_dialtone_timeout = wait_dialtone_timeout; + analog_data->polarity_delay = polarity_delay; analog_data->max_dialstr = max_dialstr; span->signal_cb = sig_cb; strncpy(analog_data->hotline, hotline, sizeof(analog_data->hotline)); @@ -399,6 +424,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) ftdm_analog_data_t *analog_data = ftdmchan->span->signal_data; ftdm_channel_t *closed_chan; uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = analog_data->wait_dialtone_timeout; + uint32_t answer_on_polarity_counter = 0; ftdm_sigmsg_t sig; ftdm_status_t status; @@ -470,7 +496,12 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) if (ftdmchan->needed_tones[FTDM_TONEMAP_DIAL]) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY); } else { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); + /* do not go up if we're waiting for polarity reversal */ + if (ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) { + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + } else { + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); + } } } } @@ -561,8 +592,30 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) } case FTDM_CHANNEL_STATE_UP: case FTDM_CHANNEL_STATE_RING: + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: { - ftdm_sleep(interval); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && + ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA && + ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Answering on polarity reverse\n"); + ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE); + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); + answer_on_polarity_counter = state_counter; + } else if (ftdmchan->state == FTDM_CHANNEL_STATE_UP + && ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)){ + /* if this polarity reverse is close to the answer polarity reverse, ignore it */ + if (answer_on_polarity_counter + && (state_counter - answer_on_polarity_counter) > analog_data->polarity_delay) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Hanging up on polarity reverse\n"); + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, + "Not hanging up on polarity reverse, too close to Answer reverse\n"); + } + ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE); + } else { + ftdm_sleep(interval); + } continue; } break; @@ -615,6 +668,18 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) sig.event_id = FTDM_SIGEVENT_UP; } + if (ftdmchan->type == FTDM_CHAN_TYPE_FXS && + !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && + ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) { + ftdm_polarity_t polarity = FTDM_POLARITY_REVERSE; + if (ftdmchan->polarity != FTDM_POLARITY_FORWARD) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Polarity is already reversed on answer??\n"); + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on answer\n"); + ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity); + } + } + ftdm_span_send_signal(ftdmchan->span, &sig); continue; } @@ -639,6 +704,22 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) continue; } break; + + case FTDM_CHANNEL_STATE_HANGUP: + /* this state is only used when the user hangup, if the device hang up (onhook) we currently + * go straight to DOWN. If we ever change this (as other signaling modules do) by using this + * state for both user and device hangup, we should check here for the type of hangup since + * some actions (polarity reverse) do not make sense if the device hung up */ + if (ftdmchan->type == FTDM_CHAN_TYPE_FXS && + ftdmchan->last_state == FTDM_CHANNEL_STATE_UP && + ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) { + ftdm_polarity_t polarity = ftdmchan->polarity == FTDM_POLARITY_REVERSE + ? FTDM_POLARITY_FORWARD : FTDM_POLARITY_REVERSE; + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on hangup\n"); + ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity); + } + break; + case FTDM_CHANNEL_STATE_DOWN: { sig.event_id = FTDM_SIGEVENT_STOP; @@ -847,6 +928,9 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) done: + closed_chan = ftdmchan; + + ftdm_channel_lock(closed_chan); if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) { ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL); @@ -857,7 +941,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) } - closed_chan = ftdmchan; + ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE); + ftdm_channel_close(&ftdmchan); ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL); @@ -875,8 +960,11 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) } ftdm_log_chan(closed_chan, FTDM_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id); + ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD); + ftdm_channel_unlock(closed_chan); + return NULL; } @@ -903,6 +991,19 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e ftdm_mutex_lock(event->channel->mutex); locked++; + /* MAINTENANCE WARNING: + * 1. Be aware you are working on the locked channel + * 2. We should not be calling ftdm_span_send_signal or ftdm_set_state when there is already a channel thread running + * however, since this is old code I am not changing it now, but new code should adhere to that convention + * otherwise, we have possible races where we compete with the user for state changes, ie, the user requests + * a state change and then we process an event, the state change from the user is pending so our ftdm_set_state + * operation will fail. In cases where we win the race, our state change will be accepted but if a user requests + * a state change before the state change we requested here is processed by the channel thread, we'll end up + * rejecting the user request. + * + * See docs/locking.txt for further information about what guarantees should signaling modules provide when + * locking/unlocking a channel + * */ switch(event->enum_id) { case FTDM_OOB_RING_START: { @@ -940,7 +1041,11 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e } ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN); } - + if (event->channel->type == FTDM_CHAN_TYPE_FXS) { + /* we always return to forward when the device goes onhook */ + ftdm_polarity_t forward_polarity = FTDM_POLARITY_FORWARD; + ftdm_channel_command(event->channel, FTDM_COMMAND_SET_POLARITY, &forward_polarity); + } } break; case FTDM_OOB_FLASH: @@ -1004,6 +1109,35 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e ftdm_span_send_signal(span, &sig); } break; + case FTDM_OOB_POLARITY_REVERSE: + { + if (event->channel->type != FTDM_CHAN_TYPE_FXO) { + ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING, + "Ignoring polarity reversal, this should not happen in non-FXO channels!\n"); + break; + } + if (!ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD) && + ftdm_test_flag(event->channel, FTDM_CHANNEL_OFFHOOK)) { + ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING, + "Forcing onhook in channel not in thread after polarity reversal\n"); + ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL); + break; + } + if (!ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE) + && !ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) { + ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG, + "Ignoring polarity reversal because this channel is not configured for it\n"); + break; + } + if (event->channel->state == FTDM_CHANNEL_STATE_DOWN) { + ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG, + "Ignoring polarity reversal because this channel is down\n"); + break; + } + /* we have a good channel, set the polarity flag and let the channel thread deal with it */ + ftdm_set_sflag(event->channel, AF_POLARITY_REVERSE); + } + break; default: { ftdm_log_chan(event->channel, FTDM_LOG_DEBUG, "Ignoring event [%s] in state [%s]\n", ftdm_oob_event2str(event->enum_id), ftdm_channel_state2str(event->channel->state)); diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index 2db4326847..5e9318f7e5 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -784,17 +784,27 @@ static FIO_COMMAND_FUNCTION(wanpipe_command) err = sangoma_set_tx_queue_sz(ftdmchan->sockfd, &tdm_api, queue_size); } break; + case FTDM_COMMAND_SET_POLARITY: + { + ftdm_polarity_t polarity = FTDM_COMMAND_OBJ_INT; + err = sangoma_tdm_set_polarity(ftdmchan->sockfd, &tdm_api, polarity); + if (!err) { + ftdmchan->polarity = polarity; + } + } + break; default: err = FTDM_NOTIMPL; break; }; if (err) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno)); + int myerrno = errno; + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to execute command %d: %s\n", command, strerror(myerrno)); + errno = myerrno; return err; } - return FTDM_SUCCESS; } @@ -1237,8 +1247,9 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) wanpipe_tdm_api_t tdm_api; ftdm_span_t *span = ftdmchan->span; - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) { ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT); + } memset(&tdm_api, 0, sizeof(tdm_api)); status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api); @@ -1251,7 +1262,7 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type); switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) { - case WP_TDMAPI_EVENT_LINK_STATUS: + case WP_API_EVENT_LINK_STATUS: { switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) { case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED: @@ -1264,7 +1275,7 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) } break; - case WP_TDMAPI_EVENT_RXHOOK: + case WP_API_EVENT_RXHOOK: { if (ftdmchan->type == FTDM_CHAN_TYPE_FXS) { event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK; @@ -1300,26 +1311,26 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) } } break; - case WP_TDMAPI_EVENT_RING_DETECT: + case WP_API_EVENT_RING_DETECT: { event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP; } break; /* disabled this ones when configuring, we don't need them, do we? - case WP_TDMAPI_EVENT_RING_TRIP_DETECT: + case WP_API_EVENT_RING_TRIP_DETECT: { event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK; } break; */ - case WP_TDMAPI_EVENT_RBS: + case WP_API_EVENT_RBS: { event_id = FTDM_OOB_CAS_BITS_CHANGE; ftdmchan->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits); } break; - case WP_TDMAPI_EVENT_DTMF: + case WP_API_EVENT_DTMF: { char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 }; event_id = FTDM_OOB_NOOP; @@ -1342,12 +1353,18 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) } } break; - case WP_TDMAPI_EVENT_ALARM: + case WP_API_EVENT_ALARM: { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm); event_id = FTDM_OOB_ALARM_TRAP; } break; + case WP_API_EVENT_POLARITY_REVERSE: + { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Got polarity reverse\n"); + event_id = FTDM_OOB_POLARITY_REVERSE; + } + break; default: { ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type); @@ -1423,7 +1440,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event) ftdm_log_chan(span->channels[i], FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type); switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) { - case WP_TDMAPI_EVENT_LINK_STATUS: + case WP_API_EVENT_LINK_STATUS: { switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) { case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED: @@ -1436,7 +1453,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event) } break; - case WP_TDMAPI_EVENT_RXHOOK: + case WP_API_EVENT_RXHOOK: { if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS) { event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK; @@ -1472,26 +1489,26 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event) } } break; - case WP_TDMAPI_EVENT_RING_DETECT: + case WP_API_EVENT_RING_DETECT: { event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP; } break; /* disabled this ones when configuring, we don't need them, do we? - case WP_TDMAPI_EVENT_RING_TRIP_DETECT: + case WP_API_EVENT_RING_TRIP_DETECT: { event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK; } break; */ - case WP_TDMAPI_EVENT_RBS: + case WP_API_EVENT_RBS: { event_id = FTDM_OOB_CAS_BITS_CHANGE; span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits); } break; - case WP_TDMAPI_EVENT_DTMF: + case WP_API_EVENT_DTMF: { char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 }; event_id = FTDM_OOB_NOOP; @@ -1514,12 +1531,18 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event) } } break; - case WP_TDMAPI_EVENT_ALARM: + case WP_API_EVENT_ALARM: { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm); event_id = FTDM_OOB_ALARM_TRAP; } break; + case WP_API_EVENT_POLARITY_REVERSE: + { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Got polarity reverse\n"); + event_id = FTDM_OOB_POLARITY_REVERSE; + } + break; default: { ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type); diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 79e873390e..dfb3f1fc02 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -557,8 +557,14 @@ typedef enum { FTDM_COMMAND_COUNT, FTDM_COMMAND_SET_RX_QUEUE_SIZE, FTDM_COMMAND_SET_TX_QUEUE_SIZE, + FTDM_COMMAND_SET_POLARITY, } ftdm_command_t; +typedef enum { + FTDM_POLARITY_FORWARD = 0, + FTDM_POLARITY_REVERSE = 1 +} ftdm_polarity_t; + /*! \brief Custom memory handler hooks. Not recommended to use unless you need memory allocation customizations */ typedef void *(*ftdm_malloc_func_t)(void *pool, ftdm_size_t len); typedef void *(*ftdm_calloc_func_t)(void *pool, ftdm_size_t elements, ftdm_size_t len); diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 606a89fc77..b90e98736a 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -143,7 +143,9 @@ extern "C" { \return true value if the object has the flags defined */ #define ftdm_test_flag(obj, flag) ((obj)->flags & flag) +/*!< Physical (IO) module specific flags */ #define ftdm_test_pflag(obj, flag) ((obj)->pflags & flag) +/*!< signaling module specific flags */ #define ftdm_test_sflag(obj, flag) ((obj)->sflags & flag) #define ftdm_set_alarm_flag(obj, flag) (obj)->alarm_flags |= (flag) @@ -456,6 +458,7 @@ struct ftdm_channel { ftdm_fsk_data_state_t fsk; uint8_t fsk_buf[80]; uint32_t ring_count; + ftdm_polarity_t polarity; /* Private I/O data. Do not touch unless you are an I/O module */ void *io_data; /* Private signaling data. Do not touch unless you are a signaling module */ diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 6c521e3481..db15b106c1 100644 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -123,6 +123,7 @@ typedef enum { FTDM_STR2ENUM_P(ftdm_str2ftdm_analog_start_type, ftdm_analog_start_type2str, ftdm_analog_start_type_t) typedef enum { + FTDM_OOB_NOOP, FTDM_OOB_ONHOOK, FTDM_OOB_OFFHOOK, FTDM_OOB_WINK, @@ -131,11 +132,11 @@ typedef enum { FTDM_OOB_RING_STOP, FTDM_OOB_ALARM_TRAP, FTDM_OOB_ALARM_CLEAR, - FTDM_OOB_NOOP, FTDM_OOB_CAS_BITS_CHANGE, + FTDM_OOB_POLARITY_REVERSE, FTDM_OOB_INVALID } ftdm_oob_event_t; -#define OOB_STRINGS "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "CAS_BITS_CHANGE", "INVALID" +#define OOB_STRINGS "NOOP", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "CAS_BITS_CHANGE", "POLARITY_REVERSE", "INVALID" FTDM_STR2ENUM_P(ftdm_str2ftdm_oob_event, ftdm_oob_event2str, ftdm_oob_event_t) /*! \brief Event types */