static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event);
static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
+static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan);
+static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *ftdmchan);
static ftdm_io_interface_t g_sngisdn_io_interface;
static sng_isdn_event_interface_t g_sngisdn_event_interface;
static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event)
{
-
- sngisdn_snd_event(span, event);
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
+ sngisdn_snd_event(signal_data->dchan, event);
+
switch (event) {
/* Check if the span woke up from power-saving mode */
case FTDM_OOB_ALARM_CLEAR:
sngisdn_chan_data_t *sngisdn_info;
ftdm_iterator_t *chaniter = NULL;
ftdm_iterator_t *curr = NULL;
- sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
-
+
chaniter = ftdm_span_get_chan_iterator(span, NULL);
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
if (ftdm_test_flag(sngisdn_info, FLAG_ACTIVATING)) {
ftdm_clear_flag(sngisdn_info, FLAG_ACTIVATING);
- ftdm_sched_timer(signal_data->sched, "delayed_setup", 1, sngisdn_delayed_setup, (void*) ftdmchan->call_data, NULL);
+ ftdm_sched_timer(signal_data->sched, "delayed_setup", 1000, sngisdn_delayed_setup, (void*) ftdmchan->call_data, NULL);
}
}
ftdm_iterator_free(chaniter);
static void ftdm_sangoma_isdn_poll_events(ftdm_span_t *span)
{
ftdm_status_t ret_status;
- ftdm_iterator_t *chaniter = NULL;
- ftdm_iterator_t *curr = NULL;
-
+
ret_status = ftdm_span_poll_event(span, 0, NULL);
switch(ret_status) {
case FTDM_SUCCESS:
}
}
+static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *dchan)
+{
+ ftdm_status_t ret_status;
+ uint32_t queue_size;
+
+ queue_size = SNGISDN_DCHAN_QUEUE_LEN;
+ ret_status = ftdm_channel_command(dchan, FTDM_COMMAND_SET_RX_QUEUE_SIZE, &queue_size);
+ ftdm_assert(ret_status == FTDM_SUCCESS, "Failed to set Rx Queue size");
+
+ queue_size = SNGISDN_DCHAN_QUEUE_LEN;
+ ret_status = ftdm_channel_command(dchan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &queue_size);
+ ftdm_assert(ret_status == FTDM_SUCCESS, "Failed to set Tx Queue size");
+
+ RETVOID;
+}
+
+static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan)
+{
+ ftdm_status_t ret_status;
+ ftdm_channel_hw_link_status_t status = FTDM_HW_LINK_CONNECTED;
+ ret_status = ftdm_channel_command(dchan, FTDM_COMMAND_SET_LINK_STATUS, &status);
+ if (ret_status != FTDM_SUCCESS) {
+ ftdm_log_chan_msg(dchan, FTDM_LOG_WARNING, "Failed to wake-up link\n");
+ }
+ return;
+}
+
static void *ftdm_sangoma_isdn_dchan_run(ftdm_thread_t *me, void *obj)
{
uint8_t data[1000];
ftdm_channel_t *dchan = ((sngisdn_span_data_t*)span->signal_data)->dchan;
ftdm_size_t len = 0;
-
+ ftdm_channel_set_feature(dchan, FTDM_CHANNEL_FEATURE_IO_STATS);
+ ftdm_sangoma_isdn_dchan_set_queue_size(dchan);
+
ftdm_assert(dchan, "Span does not have a dchannel");
ftdm_channel_open_chan(dchan);
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Requesting Line activation\n");
- sngisdn_set_flag(sngisdn_info, FLAG_ACTIVATING);
- sngisdn_wake_up_phy(ftdmchan->span);
+ sngisdn_set_flag(sngisdn_info, FLAG_ACTIVATING);
+ ftdm_sangoma_isdn_wakeup_phy(ftdmchan);
ftdm_sched_timer(signal_data->sched, "timer_t3", signal_data->timer_t3*1000, sngisdn_t3_timeout, (void*) sngisdn_info, NULL);
} else {
sngisdn_snd_setup(ftdmchan);
#define SNGISDN_EVENT_QUEUE_SIZE 100
#define SNGISDN_EVENT_POLL_RATE 100
#define SNGISDN_NUM_LOCAL_NUMBERS 8
+#define SNGISDN_DCHAN_QUEUE_LEN 200
/* TODO: rename all *_cc_* to *_an_* */
void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan);
void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan);
void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len);
-void sngisdn_snd_event(ftdm_channel_t *span, sng_isdn_l1_event_t l1_event);
+void sngisdn_snd_event(ftdm_channel_t *dchan, ftdm_oob_event_t event);
/* Inbound Call Control functions */
void sngisdn_rcv_con_ind(int16_t suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, int16_t dChan, uint8_t ces);
void sngisdn_rcv_srv_cfm(int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces);
void sngisdn_rcv_rst_cfm(int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evntType);
void sngisdn_rcv_rst_ind(int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evntType);
-int16_t sngisdn_rcv_l1_data_req(uint16_t spId, sng_isdn_l1_frame_t *l1_frame);
+int16_t sngisdn_rcv_l1_data_req(uint16_t spId, sng_l1_frame_t *l1_frame);
int16_t sngisdn_rcv_l1_cmd_req(uint16_t spId, sng_l1_cmd_t *l1_cmd);
/* We received an incoming frame on the d-channel, send data to the stack */
void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len)
{
- l1_frame_t l1_frame;
+ sng_l1_frame_t l1_frame;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) dchan->span->signal_data;
memset(&l1_frame, 0, sizeof(l1_frame));
memcpy(&l1_frame.data, data, len);
- if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_ERROR_CRC)) {
+ if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_CRC)) {
l1_frame.flags |= SNG_L1FRAME_ERROR_CRC;
}
- if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_ERROR_FRAME)) {
+ if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_FRAME)) {
l1_frame.flags |= SNG_L1FRAME_ERROR_FRAME;
}
- if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_ERROR_ABORT)) {
+ if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_ABORT)) {
l1_frame.flags |= SNG_L1FRAME_ERROR_ABORT;
}
- if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_ERROR_FIFO)) {
+ if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_FIFO)) {
l1_frame.flags |= SNG_L1FRAME_ERROR_FIFO;
}
- if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_ERROR_DMA)) {
+ if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_DMA)) {
l1_frame.flags |= SNG_L1FRAME_ERROR_DMA;
}
- if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_QUEUE_THRES)) {
+ if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)) {
/* Should we trigger congestion here? */
l1_frame.flags |= SNG_L1FRAME_QUEUE_THRES;
}
- if (ftdm_test_flag(&(dchan->iostats.s.rx), FTDM_IOSTATS_QUEUE_FULL)) {
+ if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL)) {
/* Should we trigger congestion here? */
l1_frame.flags |= SNG_L1FRAME_QUEUE_FULL;
}
}
void sngisdn_snd_event(ftdm_channel_t *dchan, ftdm_oob_event_t event)
-{
+{
+ sng_l1_event_t l1_event;
+ memset(&l1_event, 0, sizeof(l1_event));
+
+
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) dchan->span->signal_data;
switch(event) {
case FTDM_OOB_ALARM_CLEAR:
- sng_isdn_event_ind(signal_data->link_id, SNG_L1EVENT_ALARM_OFF);
+ l1_event.type = SNG_L1EVENT_ALARM_OFF;
+ sng_isdn_event_ind(signal_data->link_id, &l1_event);
break;
case FTDM_OOB_ALARM_TRAP:
- sng_isdn_event_ind(signal_data->link_id, SNG_L1EVENT_ALARM_ON);
+ l1_event.type = SNG_L1EVENT_ALARM_ON;
+ sng_isdn_event_ind(signal_data->link_id, &l1_event);
break;
default:
/* We do not care about the other OOB events for now */
return;
}
-int16_t sngisdn_rcv_data_req(uint16_t spId, uint8_t *buff, uint32_t length)
+/* The stacks is wants to transmit a frame */
+int16_t sngisdn_rcv_l1_data_req(uint16_t spId, sng_l1_frame_t *l1_frame)
{
ftdm_status_t status;
ftdm_wait_flag_t flags = FTDM_WRITE;
sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[spId];
ftdm_assert(signal_data, "Received Data request on unconfigured span\n");
-
+ ftdm_size_t length = l1_frame->len;
+
do {
flags = FTDM_WRITE;
status = signal_data->dchan->fio->wait(signal_data->dchan, &flags, 1000);
if ((flags & FTDM_WRITE)) {
- status = signal_data->dchan->fio->write(signal_data->dchan, buff, (ftdm_size_t*)&length);
+ status = signal_data->dchan->fio->write(signal_data->dchan, l1_frame->data, (ftdm_size_t*)&length);
if (status != FTDM_SUCCESS) {
ftdm_log_chan_msg(signal_data->dchan, FTDM_LOG_CRIT, "Failed to transmit frame\n");
return -1;
return 0;
}
+int16_t sngisdn_rcv_l1_cmd_req(uint16_t spId, sng_l1_cmd_t *l1_cmd)
+{
+ sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[spId];
+ ftdm_assert(signal_data, "Received Data request on unconfigured span\n");
+
+ switch(l1_cmd->type) {
+ case SNG_L1CMD_SET_LINK_STATUS:
+ {
+ ftdm_channel_hw_link_status_t status = FTDM_HW_LINK_CONNECTED;
+ ftdm_channel_command(signal_data->dchan, FTDM_COMMAND_SET_LINK_STATUS, &status);
+ }
+ break;
+ case SNG_L1CMD_GET_LINK_STATUS:
+ {
+ ftdm_channel_hw_link_status_t status = 0;
+ ftdm_channel_command(signal_data->dchan, FTDM_COMMAND_GET_LINK_STATUS, &status);
+ if (status == FTDM_HW_LINK_CONNECTED) {
+ l1_cmd->cmd.status = 1;
+ } else if (status == FTDM_HW_LINK_DISCONNECTED) {
+ l1_cmd->cmd.status = 0;
+ } else {
+ ftdm_log_chan(signal_data->dchan, FTDM_LOG_CRIT, "Invalid link status reported %d\n", status);
+ l1_cmd->cmd.status = 0;
+ }
+ }
+ break;
+ case SNG_L1CMD_FLUSH_STATS:
+ ftdm_channel_command(signal_data->dchan, FTDM_COMMAND_FLUSH_IOSTATS, NULL);
+ break;
+ case SNG_L1CMD_FLUSH_BUFFERS:
+ ftdm_channel_command(signal_data->dchan, FTDM_COMMAND_FLUSH_BUFFERS, NULL);
+ break;
+ default:
+ ftdm_log_chan(signal_data->dchan, FTDM_LOG_CRIT, "Unsupported channel command:%d\n", l1_cmd->type);
+ return -1;
+ }
+ return 0;
+}
+
void sngisdn_rcv_sng_assert(char *message)
{
ftdm_assert(0, message);
}
}
break;
+ case FTDM_COMMAND_FLUSH_BUFFERS:
+ {
+ err = sangoma_flush_bufs(ftdmchan->sockfd, &tdm_api);
+ }
+ break;
+ case FTDM_COMMAND_FLUSH_IOSTATS:
+ {
+ err = sangoma_flush_stats(ftdmchan->sockfd, &tdm_api);
+ }
+ break;
+ case FTDM_COMMAND_SET_RX_QUEUE_SIZE:
+ {
+ uint32_t queue_size = FTDM_COMMAND_OBJ_INT;
+ err = sangoma_set_rx_queue_sz(ftdmchan->sockfd, &tdm_api, queue_size);
+ }
+ break;
+ case FTDM_COMMAND_SET_TX_QUEUE_SIZE:
+ {
+ uint32_t queue_size = FTDM_COMMAND_OBJ_INT;
+ err = sangoma_set_tx_queue_sz(ftdmchan->sockfd, &tdm_api, queue_size);
+ }
+ break;
default:
break;
};
return FTDM_SUCCESS;
}
-static void wanpipe_read_stats(ftdmchan, wp_tdm_api_rx_hdr_t *rx_stats)
+static void wanpipe_read_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_rx_hdr_t *rx_stats)
{
- ftdmchan->iostats.s.rx.error_flags = 0;
- if (rx_stats->rx_hdr_errors) {
- wanpipe_reset_stats(ftdmchan);
- ftdm_log_chan_msg_throttle(ftdmchan, "IO errors\n");
- }
+ ftdmchan->iostats.stats.rx.flags = 0;
- ftdmchan->iostats.s.rx_queue_size = rx_stats->rx_h.rx_h.max_rx_queue_length;
- ftdmchan->iostats.s.rx_queue_len = rx_stats->rx_h.current_number_of_frames_in_rx_queue;
+ ftdmchan->iostats.stats.rx.errors = rx_stats->wp_api_rx_hdr_errors;
+ ftdmchan->iostats.stats.rx.rx_queue_size = rx_stats->wp_api_rx_hdr_max_queue_length;
+ ftdmchan->iostats.stats.rx.rx_queue_len = rx_stats->wp_api_rx_hdr_number_of_frames_in_queue;
- if (rx_stats->rx_h.wp_api_rx_hdr_error_map & (1<<WP_ABORT_ERROR_BIT)) {
- ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_ABORT);
+ if (rx_stats->wp_api_rx_hdr_error_map & (1<<WP_ABORT_ERROR_BIT)) {
+ ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_ABORT);
}
- if (rx_stats->rx_h.wp_api_rx_hdr_error_map & (1<<WP_DMA_ERROR_BIT)) {
- ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_DMA);
+ if (rx_stats->wp_api_rx_hdr_error_map & (1<<WP_DMA_ERROR_BIT)) {
+ ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_DMA);
}
- if (rx_stats->rx_h.wp_api_rx_hdr_error_map & (1<<WP_FIFO_ERROR_BIT)) {
- ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_FIFO);
+ if (rx_stats->wp_api_rx_hdr_error_map & (1<<WP_FIFO_ERROR_BIT)) {
+ ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_FIFO);
}
- if (rx_stats->rx_h.wp_api_rx_hdr_error_map & (1<<WP_CRC_ERROR_BIT)) {
- ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_CRC);
+ if (rx_stats->wp_api_rx_hdr_error_map & (1<<WP_CRC_ERROR_BIT)) {
+ ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_CRC);
}
- if (rx_stats->rx_h.wp_api_rx_hdr_error_map & (1<<WP_FRAME_ERROR_BIT)) {
- ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_FRAME);
+ if (rx_stats->wp_api_rx_hdr_error_map & (1<<WP_FRAME_ERROR_BIT)) {
+ ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_FRAME);
}
- if (ftdmchan->iostats.s.rx_queue_len >= (0.8*ftdmchan->iostats.s.rx_queue_size)) {
+ if (ftdmchan->iostats.stats.rx.rx_queue_len >= (0.8*ftdmchan->iostats.stats.rx.rx_queue_size)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Rx Queue length exceeded threshold (%d/%d)\n",
- ftdmchan->iostats.s.rx_queue_len, ftdmchan->iostats.s.rx_queue_size);
+ ftdmchan->iostats.stats.rx.rx_queue_len, ftdmchan->iostats.stats.rx.rx_queue_size);
- ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES);
+ ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES);
}
- if (ftdmchan->iostats.s.rx_queue_len >= ftdmchan->iostats.s.rx_queue_size) {
+ if (ftdmchan->iostats.stats.rx.rx_queue_len >= ftdmchan->iostats.stats.rx.rx_queue_size) {
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Rx Queue Full (%d/%d)\n",
- ftdmchan->iostats.s.rx_queue_len, ftdmchan->iostats.s.rx_queue_size);
+ ftdmchan->iostats.stats.rx.rx_queue_len, ftdmchan->iostats.stats.rx.rx_queue_size);
- ftdm_set_flag(&(ftdmchan->iostats.s.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL);
+ ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL);
}
return;
}
FTDM_COMMAND_FLUSH_TX_BUFFERS,
FTDM_COMMAND_FLUSH_RX_BUFFERS,
FTDM_COMMAND_FLUSH_BUFFERS,
+ FTDM_COMMAND_FLUSH_IOSTATS,
FTDM_COMMAND_SET_PRE_BUFFER_SIZE,
FTDM_COMMAND_SET_LINK_STATUS,
FTDM_COMMAND_GET_LINK_STATUS,
FTDM_COMMAND_ENABLE_LOOP,
FTDM_COMMAND_DISABLE_LOOP,
- FTDM_COMMAND_COUNT
+ FTDM_COMMAND_COUNT,
+ FTDM_COMMAND_SET_RX_QUEUE_SIZE,
+ FTDM_COMMAND_SET_TX_QUEUE_SIZE,
} ftdm_command_t;
/*! \brief Custom memory handler hooks. Not recommended to use unless you need memory allocation customizations */
uint8_t tx_queue_size; /* max queue size configured */
uint8_t tx_queue_len; /* Current number of elements in queue */
} tx;
- } s;
+ } stats;
} ftdm_channel_iostats_t;
/* 2^8 table size, one for each byte (sample) value */
FTDM_CHANNEL_FEATURE_CALLWAITING = (1 << 6), /*!< Channel will allow call waiting (ie: FXS devices) (read/write) */
FTDM_CHANNEL_FEATURE_HWEC = (1<<7), /*!< Channel has a hardware echo canceller */
FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE = (1<<8), /*!< hardware echo canceller is disabled when there are no calls on this channel */
+ FTDM_CHANNEL_FEATURE_IO_STATS = (1<<9), /*!< Channel supports IO statistics (HDLC channels only) */
} ftdm_channel_feature_t;
typedef enum {