mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-24 05:02:10 +00:00
Merge branch 'master' into gsm.merge
This commit is contained in:
@@ -255,7 +255,8 @@ FT_DECLARE (int) ftdm_config_get_cas_bits(char *strvalue, unsigned char *outbits
|
||||
if ('1' == cas_bits[x]) {
|
||||
*outbits |= bit;
|
||||
} else if ('0' != cas_bits[x]) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n");
|
||||
ftdm_log(FTDM_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n",
|
||||
strvalue);
|
||||
return -1;
|
||||
}
|
||||
bit >>= 1;
|
||||
|
||||
+42
-12
@@ -149,7 +149,7 @@ static void dump_chan_io_to_file(ftdm_channel_t *fchan, ftdm_io_dump_t *dump, FI
|
||||
if (dump->wrapped) {
|
||||
rc = fwrite(&dump->buffer[dump->windex], 1, towrite, file);
|
||||
if (rc != towrite) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in io dump buffer\n",
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %"FTDM_SIZE_FMT" out of %"FTDM_SIZE_FMT" bytes in io dump buffer: %s\n",
|
||||
rc, towrite, strerror(errno));
|
||||
}
|
||||
}
|
||||
@@ -157,7 +157,7 @@ static void dump_chan_io_to_file(ftdm_channel_t *fchan, ftdm_io_dump_t *dump, FI
|
||||
towrite = dump->windex;
|
||||
rc = fwrite(&dump->buffer[0], 1, towrite, file);
|
||||
if (rc != towrite) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in io dump buffer: %s\n",
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %"FTDM_SIZE_FMT" out of %"FTDM_SIZE_FMT" bytes in io dump buffer: %s\n",
|
||||
rc, towrite, strerror(errno));
|
||||
}
|
||||
}
|
||||
@@ -1174,7 +1174,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t *
|
||||
|
||||
status = ftdm_event_handle_oob(*event);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "failed to handle event %d\n", **event);
|
||||
ftdm_log(FTDM_LOG_ERROR, "failed to handle event %d\n", (*event)->e_type);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -1188,7 +1188,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
|
||||
if (!span->fio->channel_next_event) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "channel_next_event method not implemented in module %s!", span->fio->name);
|
||||
ftdm_log(FTDM_LOG_ERROR, "channel_next_event method not implemented in module %s!\n", span->fio->name);
|
||||
status = FTDM_NOTIMPL;
|
||||
goto done;
|
||||
}
|
||||
@@ -1204,7 +1204,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm
|
||||
|
||||
status = ftdm_event_handle_oob(*event);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "failed to handle event %d\n", **event);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "failed to handle event %d\n", (*event)->e_type);
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -2548,7 +2548,9 @@ FT_DECLARE(ftdm_status_t) _ftdm_call_place(const char *file, const char *func, i
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* let the user know which channel was picked and which call id was generated */
|
||||
caller_data->fchan = fchan;
|
||||
caller_data->call_id = fchan->caller_data.call_id;
|
||||
done:
|
||||
ftdm_channel_unlock(fchan);
|
||||
|
||||
@@ -2978,7 +2980,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
|
||||
GOTO_STATUS(done, FTDM_FAIL);
|
||||
}
|
||||
if (start_chan_io_dump(ftdmchan, &ftdmchan->txdump, size) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to enable output dump of size %d\n", size);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to enable output dump of size %"FTDM_SIZE_FMT"\n", size);
|
||||
GOTO_STATUS(done, FTDM_FAIL);
|
||||
}
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled output dump with size %"FTDM_SIZE_FMT"\n", size);
|
||||
@@ -3010,7 +3012,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
|
||||
GOTO_STATUS(done, FTDM_FAIL);
|
||||
}
|
||||
dump_chan_io_to_file(ftdmchan, &ftdmchan->rxdump, obj);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %d to file %p\n", ftdmchan->rxdump.size, obj);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %"FTDM_SIZE_FMT" to file %p\n", ftdmchan->rxdump.size, obj);
|
||||
GOTO_STATUS(done, FTDM_SUCCESS);
|
||||
}
|
||||
break;
|
||||
@@ -3633,7 +3635,7 @@ FT_DECLARE(ftdm_status_t) ftdm_raw_write (ftdm_channel_t *ftdmchan, void *data,
|
||||
}
|
||||
if (ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] > -1) {
|
||||
if ((write(ftdmchan->fds[FTDM_WRITE_TRACE_INDEX], data, dlen)) != dlen) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "Raw output trace failed to write all of the %"FTDM_SIZE_FMT" bytes\n", dlen);
|
||||
ftdm_log(FTDM_LOG_WARNING, "Raw output trace failed to write all of the %d bytes\n", dlen);
|
||||
}
|
||||
}
|
||||
write_chan_io_dump(&ftdmchan->txdump, data, dlen);
|
||||
@@ -3679,7 +3681,8 @@ FT_DECLARE(ftdm_status_t) ftdm_raw_read (ftdm_channel_t *ftdmchan, void *data, f
|
||||
if (ftdmchan->dtmfdbg.file) {
|
||||
rc = fwrite(data, 1, dlen, ftdmchan->dtmfdbg.file);
|
||||
if (rc != dlen) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "DTMF debugger wrote only %d out of %d bytes: %s\n", rc, datalen, strerror(errno));
|
||||
ftdm_log(FTDM_LOG_WARNING, "DTMF debugger wrote only %"FTDM_SIZE_FMT" out of %"FTDM_SIZE_FMT" bytes: %s\n",
|
||||
rc, *datalen, strerror(errno));
|
||||
}
|
||||
ftdmchan->dtmfdbg.closetimeout--;
|
||||
if (!ftdmchan->dtmfdbg.closetimeout) {
|
||||
@@ -3898,7 +3901,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_process_media(ftdm_channel_t *ftdmchan, v
|
||||
*(str+mlen) = '\0';
|
||||
ftdm_copy_string(str, sp, ++mlen);
|
||||
ftdm_clean_string(str);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "FSK: TYPE %s LEN %d VAL [%s]\n", ftdm_mdmf_type2str(type), mlen-1, str);
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "FSK: TYPE %s LEN %"FTDM_SIZE_FMT" VAL [%s]\n",
|
||||
ftdm_mdmf_type2str(type), mlen-1, str);
|
||||
|
||||
switch(type) {
|
||||
case MDMF_DDN:
|
||||
@@ -4574,7 +4579,7 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const
|
||||
ftdm_assert_return(span->fio != NULL, FTDM_EINVAL, "span with no I/O configured\n");
|
||||
ftdm_assert_return(span->fio->configure_span != NULL, FTDM_NOTIMPL, "span I/O with no channel configuration implemented\n");
|
||||
|
||||
currindex = span->chan_count;
|
||||
currindex = span->chan_count;
|
||||
*configured = 0;
|
||||
*configured = span->fio->configure_span(span, str, chan_config->type, chan_config->name, chan_config->number);
|
||||
if (!*configured) {
|
||||
@@ -4604,7 +4609,12 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const
|
||||
}
|
||||
|
||||
if (chan_config->debugdtmf) {
|
||||
span->channels[chan_index]->dtmfdbg.requested = 1;
|
||||
span->channels[chan_index]->dtmfdbg.requested = 1;
|
||||
}
|
||||
|
||||
span->channels[chan_index]->dtmfdetect.duration_ms = chan_config->dtmfdetect_ms;
|
||||
if (chan_config->dtmf_on_start) {
|
||||
span->channels[chan_index]->dtmfdetect.trigger_on_start = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4802,6 +4812,24 @@ static ftdm_status_t load_config(void)
|
||||
} else if (!strcasecmp(var, "debugdtmf")) {
|
||||
chan_config.debugdtmf = ftdm_true(val);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Setting debugdtmf to '%s'\n", chan_config.debugdtmf ? "yes" : "no");
|
||||
} else if (!strncasecmp(var, "dtmfdetect_ms", sizeof("dtmfdetect_ms")-1)) {
|
||||
if (chan_config.dtmf_on_start == FTDM_TRUE) {
|
||||
chan_config.dtmf_on_start = FTDM_FALSE;
|
||||
ftdm_log(FTDM_LOG_WARNING, "dtmf_on_start parameter disabled because dtmfdetect_ms specified\n");
|
||||
}
|
||||
if (sscanf(val, "%d", &(chan_config.dtmfdetect_ms)) != 1) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "invalid dtmfdetect_ms: '%s'\n", val);
|
||||
}
|
||||
} else if (!strncasecmp(var, "dtmf_on_start", sizeof("dtmf_on_start")-1)) {
|
||||
if (chan_config.dtmfdetect_ms) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "dtmf_on_start parameter ignored because dtmf_detect_ms specified\n");
|
||||
} else {
|
||||
if (ftdm_true(val)) {
|
||||
chan_config.dtmf_on_start = FTDM_TRUE;
|
||||
} else {
|
||||
chan_config.dtmf_on_start = FTDM_FALSE;
|
||||
}
|
||||
}
|
||||
} else if (!strncasecmp(var, "iostats", sizeof("iostats")-1)) {
|
||||
if (ftdm_true(val)) {
|
||||
chan_config.iostats = FTDM_TRUE;
|
||||
@@ -5801,6 +5829,8 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
|
||||
/* destroy signaling and io modules */
|
||||
ftdm_unload_modules();
|
||||
|
||||
ftdm_global_set_logger( NULL );
|
||||
|
||||
/* finally destroy the globals */
|
||||
ftdm_mutex_lock(globals.mutex);
|
||||
ftdm_sched_destroy(&globals.timingsched);
|
||||
|
||||
@@ -119,10 +119,15 @@ static void *run_main_schedule(ftdm_thread_t *thread, void *data)
|
||||
/* there are no free runs, wait a bit and check again (FIXME: use ftdm_interrupt_t for this) */
|
||||
ftdm_mutex_unlock(sched_globals.mutex);
|
||||
|
||||
ftdm_sleep(sleepms);
|
||||
if (ftdm_running()) {
|
||||
ftdm_sleep(sleepms);
|
||||
}
|
||||
}
|
||||
|
||||
for (current = sched_globals.freeruns; current; current = current->next) {
|
||||
if (!ftdm_running()) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* first run the schedule */
|
||||
ftdm_sched_run(current);
|
||||
@@ -142,7 +147,9 @@ static void *run_main_schedule(ftdm_thread_t *thread, void *data)
|
||||
|
||||
ftdm_mutex_unlock(sched_globals.mutex);
|
||||
|
||||
ftdm_sleep(sleepms);
|
||||
if (ftdm_running()) {
|
||||
ftdm_sleep(sleepms);
|
||||
}
|
||||
}
|
||||
ftdm_log(FTDM_LOG_NOTICE, "Main scheduling thread going out ...\n");
|
||||
sched_globals.running = 0;
|
||||
|
||||
@@ -486,7 +486,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_signal(ftdm_interrupt_t *interrupt)
|
||||
* otherwise users that never call interrupt wait eventually will
|
||||
* eventually have the pipe buffer filled */
|
||||
if ((err = write(interrupt->writefd, "w", 1)) != 1) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt: %s\n", errno, strerror(errno));
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt: %s\n", strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,15 @@
|
||||
* NOTE: This is intended as a Layer 1 interface only, signaling
|
||||
* is handled by other modules (e.g. ftmod_libpri or ftmod_isdn).
|
||||
*/
|
||||
/*
|
||||
* TODO:
|
||||
* - Use a fifo and PH_DATA_CNF for b-channel write polling (drop timerfd)
|
||||
*
|
||||
* - Disable L1 idle deactivation on BRI PTMP with IMGL1HOLD ioctl(? optional)
|
||||
*
|
||||
* - Add hfcsusb specific state + flag defines and try to do something useful with
|
||||
* it in misdn_handle_mph_information_ind().
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
@@ -67,6 +76,15 @@
|
||||
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#ifndef CLAMP
|
||||
#define CLAMP(val,min,max) (MIN(max,MAX(min,val)))
|
||||
#endif
|
||||
|
||||
|
||||
typedef enum {
|
||||
MISDN_CAPS_NONE = 0,
|
||||
|
||||
@@ -91,23 +109,33 @@ typedef enum {
|
||||
#define MISDN_IS_RAW(x) (x & MISDN_CAPS_RAW)
|
||||
#define MISDN_IS_HDLC(x) (x & MISDN_CAPS_HDLC)
|
||||
|
||||
#define MISDN_MSG_DATA(x) ((void *)((unsigned char *)(x) + MISDN_HEADER_LEN))
|
||||
|
||||
const static struct {
|
||||
const int id;
|
||||
const char *name;
|
||||
} misdn_event_types[] = {
|
||||
{ PH_DATA_REQ, "PH_DATA_REQ" },
|
||||
{ PH_DATA_IND, "PH_DATA_IND" },
|
||||
{ PH_DATA_CNF, "PH_DATA_CNF" },
|
||||
{ PH_CONTROL_REQ, "PH_CONTROL_REQ" },
|
||||
{ PH_CONTROL_IND, "PH_CONTROL_IND" },
|
||||
{ PH_CONTROL_CNF, "PH_CONTROL_CNF" },
|
||||
{ PH_ACTIVATE_REQ, "PH_ACTIVATE_REQ" },
|
||||
{ PH_ACTIVATE_IND, "PH_ACTIVATE_IND" },
|
||||
{ PH_ACTIVATE_CNF, "PH_ACTIVATE_CNF" },
|
||||
{ PH_DEACTIVATE_REQ, "PH_DEACTIVATE_REQ" },
|
||||
{ PH_DEACTIVATE_IND, "PH_DEACTIVATE_IND" },
|
||||
{ PH_DEACTIVATE_CNF, "PH_DEACTIVATE_CNF" },
|
||||
#define MISDN_EVENT_TYPE(x) { x, #x }
|
||||
MISDN_EVENT_TYPE(PH_DATA_REQ),
|
||||
MISDN_EVENT_TYPE(PH_DATA_IND),
|
||||
MISDN_EVENT_TYPE(PH_DATA_CNF),
|
||||
MISDN_EVENT_TYPE(PH_DATA_E_IND),
|
||||
MISDN_EVENT_TYPE(PH_CONTROL_REQ),
|
||||
MISDN_EVENT_TYPE(PH_CONTROL_IND),
|
||||
MISDN_EVENT_TYPE(PH_CONTROL_CNF),
|
||||
MISDN_EVENT_TYPE(PH_ACTIVATE_REQ),
|
||||
MISDN_EVENT_TYPE(PH_ACTIVATE_IND),
|
||||
MISDN_EVENT_TYPE(PH_ACTIVATE_CNF),
|
||||
MISDN_EVENT_TYPE(PH_DEACTIVATE_REQ),
|
||||
MISDN_EVENT_TYPE(PH_DEACTIVATE_IND),
|
||||
MISDN_EVENT_TYPE(PH_DEACTIVATE_CNF),
|
||||
MISDN_EVENT_TYPE(MPH_ACTIVATE_REQ),
|
||||
MISDN_EVENT_TYPE(MPH_ACTIVATE_IND),
|
||||
MISDN_EVENT_TYPE(MPH_DEACTIVATE_REQ),
|
||||
MISDN_EVENT_TYPE(MPH_DEACTIVATE_IND),
|
||||
MISDN_EVENT_TYPE(MPH_INFORMATION_REQ),
|
||||
MISDN_EVENT_TYPE(MPH_INFORMATION_IND),
|
||||
#undef MISDN_EVENT_TYPE
|
||||
};
|
||||
|
||||
static const char *misdn_event2str(const int event)
|
||||
@@ -128,6 +156,7 @@ const static struct {
|
||||
} misdn_control_types[] = {
|
||||
#define MISDN_CONTROL_TYPE(x) { x, #x }
|
||||
MISDN_CONTROL_TYPE(DTMF_HFC_COEF),
|
||||
#undef MISDN_CONTROL_TYPE
|
||||
};
|
||||
|
||||
#if 0 /* unused for now */
|
||||
@@ -143,6 +172,63 @@ static const char *misdn_control2str(const int ctrl)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************************
|
||||
* mISDN <-> FreeTDM audio conversion
|
||||
***********************************************************************************/
|
||||
|
||||
/*
|
||||
* Code used to generate table values taken from
|
||||
* Linux Call Router (LCR) http://www.linux-call-router.de/
|
||||
*
|
||||
* chan_lcr.c:3488 ff., load_module()
|
||||
*/
|
||||
static const unsigned char conv_audio_tbl[256] = {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
|
||||
};
|
||||
|
||||
/* Convert ISDN_P_B_RAW audio data to/from a-/u-law */
|
||||
static inline void misdn_convert_audio_bits(char *buf, int buflen)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < buflen; i++) {
|
||||
buf[i] = conv_audio_tbl[(unsigned char)buf[i]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************
|
||||
* mISDN <-> FreeTDM data structures
|
||||
***********************************************************************************/
|
||||
@@ -171,10 +257,15 @@ struct misdn_chan_private {
|
||||
int state;
|
||||
int debugfd;
|
||||
int timerfd;
|
||||
int active;
|
||||
|
||||
/* hw addr of channel */
|
||||
struct sockaddr_mISDN addr;
|
||||
|
||||
/* audio tx pipe */
|
||||
int audio_pipe_in;
|
||||
int audio_pipe_out;
|
||||
|
||||
/* counters */
|
||||
unsigned long tx_cnt;
|
||||
unsigned long tx_ack_cnt;
|
||||
@@ -189,6 +280,12 @@ struct misdn_chan_private {
|
||||
#define ftdm_span_io_private(x) ((x)->io_data)
|
||||
|
||||
static ftdm_status_t misdn_handle_incoming(ftdm_channel_t *ftdmchan, const char *rbuf, const int size);
|
||||
static int misdn_handle_mph_information_ind(ftdm_channel_t *chan, const struct mISDNhead *hh, const void *data, const int data_len);
|
||||
|
||||
static const char *ftdm_channel_get_type_str(const ftdm_channel_t *chan)
|
||||
{
|
||||
return ftdm_chan_type2str(ftdm_channel_get_type(chan));
|
||||
}
|
||||
|
||||
/***********************************************************************************
|
||||
* mISDN interface functions
|
||||
@@ -378,12 +475,17 @@ static inline int ts_before(struct timespec *a, struct timespec *b)
|
||||
|
||||
static ftdm_status_t misdn_activate_channel(ftdm_channel_t *chan, int activate)
|
||||
{
|
||||
struct misdn_chan_private *priv = ftdm_chan_io_private(chan);
|
||||
char buf[MAX_DATA_MEM] = { 0 };
|
||||
struct mISDNhead *hh = (struct mISDNhead *) buf;
|
||||
struct timespec abstimeout;
|
||||
int req = 0, resp = 0, ms_left = MISDN_PH_ACTIVATE_TIMEOUT_MS;
|
||||
int retval;
|
||||
|
||||
/* NOTE: sending PH_DEACTIVATE_REQ to closed b-channels kills the d-channel (hfcsusb)... */
|
||||
if ((activate && priv->active) || (!activate && !priv->active))
|
||||
return FTDM_SUCCESS;
|
||||
|
||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "mISDN sending %s request\n",
|
||||
(activate) ? "activation" : "deactivation");
|
||||
|
||||
@@ -407,7 +509,7 @@ static ftdm_status_t misdn_activate_channel(ftdm_channel_t *chan, int activate)
|
||||
struct pollfd pfd;
|
||||
|
||||
pfd.fd = chan->sockfd;
|
||||
pfd.events = POLLIN /* | POLLPRI */;
|
||||
pfd.events = POLLIN | POLLPRI;
|
||||
pfd.revents = 0;
|
||||
|
||||
switch ((retval = poll(&pfd, 1, ms_left))) {
|
||||
@@ -432,28 +534,37 @@ static ftdm_status_t misdn_activate_channel(ftdm_channel_t *chan, int activate)
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
//#ifdef MISDN_DEBUG_EVENTS
|
||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "mISDN got event '%s' while waiting for %s confirmation\n",
|
||||
misdn_event2str(hh->prim), (activate) ? "activation" : "deactivation");
|
||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "mISDN got event '%s (%#x)', id %#x, while waiting for %s confirmation on %c-channel\n",
|
||||
misdn_event2str(hh->prim), hh->prim, hh->id, (activate) ? "activation" : "deactivation",
|
||||
ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_B ? 'B' : 'D');
|
||||
//#endif
|
||||
switch (hh->prim) {
|
||||
case PH_ACTIVATE_IND: /* success (or not): save last response, */
|
||||
case PH_DEACTIVATE_IND: /* stop looping if it's the one we've been waiting for */
|
||||
resp = hh->prim;
|
||||
if (hh->prim == (activate) ? PH_ACTIVATE_IND : PH_DEACTIVATE_IND) goto out;
|
||||
break;
|
||||
case PH_ACTIVATE_IND:
|
||||
case PH_ACTIVATE_CNF:
|
||||
case PH_DEACTIVATE_CNF:
|
||||
resp = hh->prim;
|
||||
if (hh->prim == (activate) ? PH_ACTIVATE_CNF : PH_DEACTIVATE_CNF) goto out;
|
||||
priv->active = 1;
|
||||
if (activate) goto out;
|
||||
break;
|
||||
case PH_DEACTIVATE_CNF:
|
||||
case PH_DEACTIVATE_IND:
|
||||
resp = hh->prim;
|
||||
priv->active = 0;
|
||||
if (!activate) goto out;
|
||||
break;
|
||||
case PH_ACTIVATE_REQ: /* REQ echo, ignore */
|
||||
case PH_DEACTIVATE_REQ:
|
||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "mISDN got '%s' echo while waiting for %s confirmation (id: %#x)\n",
|
||||
misdn_event2str(hh->prim), (activate) ? "activation" : "deactivation", hh->id);
|
||||
break;
|
||||
case MPH_INFORMATION_IND:
|
||||
misdn_handle_mph_information_ind(chan, hh, MISDN_MSG_DATA(buf), retval - MISDN_HEADER_LEN);
|
||||
break;
|
||||
case PH_DATA_IND: /* ignore */
|
||||
case PH_DATA_CNF: /* ignore */
|
||||
break;
|
||||
default: /* other messages, ignore */
|
||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "mISDN ignoring event '%s' while waiting for %s confirmation\n",
|
||||
misdn_event2str(hh->prim), (activate) ? "activation" : "deactivation");
|
||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "mISDN ignoring event '%s (%#x)', id %#x, while waiting for %s confirmation\n",
|
||||
misdn_event2str(hh->prim), hh->prim, hh->id, (activate) ? "activation" : "deactivation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -470,8 +581,8 @@ out:
|
||||
(activate) ? "activation" : "deactivation");
|
||||
return FTDM_TIMEOUT;
|
||||
}
|
||||
if ((req == PH_ACTIVATE_IND && !(resp == PH_ACTIVATE_CNF || resp == PH_ACTIVATE_IND)) ||
|
||||
(req == PH_DEACTIVATE_IND && !(resp == PH_DEACTIVATE_CNF || resp == PH_DEACTIVATE_CNF))) {
|
||||
if ((req == PH_ACTIVATE_REQ && !(resp == PH_ACTIVATE_CNF || resp == PH_ACTIVATE_IND)) ||
|
||||
(req == PH_DEACTIVATE_REQ && !(resp == PH_DEACTIVATE_CNF || resp == PH_DEACTIVATE_IND))) {
|
||||
ftdm_log_chan(chan, FTDM_LOG_ERROR, "mISDN received '%s' while waiting for %s\n",
|
||||
misdn_event2str(resp), (activate) ? "activation" : "deactivation");
|
||||
return FTDM_FAIL;
|
||||
@@ -602,53 +713,188 @@ static int misdn_handle_ph_control_ind(ftdm_channel_t *chan, const struct mISDNh
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* TE/NT state names
|
||||
* taken from linux-3.2.1/drivers/isdn/hardware/mISDN/hfcsusb.h
|
||||
*/
|
||||
static const char *misdn_layer1_te_states[] = {
|
||||
"TE F0 - Reset",
|
||||
"TE F1 - Reset",
|
||||
"TE F2 - Sensing",
|
||||
"TE F3 - Deactivated",
|
||||
"TE F4 - Awaiting signal",
|
||||
"TE F5 - Identifying input",
|
||||
"TE F6 - Synchronized",
|
||||
"TE F7 - Activated",
|
||||
"TE F8 - Lost framing",
|
||||
};
|
||||
|
||||
static const char *misdn_layer1_nt_states[] = {
|
||||
"NT G0 - Reset",
|
||||
"NT G1 - Deactive",
|
||||
"NT G2 - Pending activation",
|
||||
"NT G3 - Active",
|
||||
"NT G4 - Pending deactivation",
|
||||
};
|
||||
|
||||
static const char *misdn_hw_state_name(const int proto, const int id)
|
||||
{
|
||||
if (IS_ISDN_P_TE(proto)) {
|
||||
if (id < 0 || id >= ftdm_array_len(misdn_layer1_te_states))
|
||||
return NULL;
|
||||
return misdn_layer1_te_states[id];
|
||||
}
|
||||
else if (IS_ISDN_P_NT(proto)) {
|
||||
if (id < 0 || id >= ftdm_array_len(misdn_layer1_nt_states))
|
||||
return NULL;
|
||||
return misdn_layer1_nt_states[id];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const struct misdn_hw_flag {
|
||||
const unsigned int flag;
|
||||
const char *name;
|
||||
} misdn_hw_flags[] = {
|
||||
#define MISDN_HW_FLAG(v,n) { v, #n }
|
||||
MISDN_HW_FLAG(0, FLG_TX_BUSY),
|
||||
MISDN_HW_FLAG(1, FLG_TX_NEXT),
|
||||
MISDN_HW_FLAG(2, FLG_L1_BUSY),
|
||||
MISDN_HW_FLAG(3, FLG_L2_ACTIVATED),
|
||||
MISDN_HW_FLAG(5, FLG_OPEN),
|
||||
MISDN_HW_FLAG(6, FLG_ACTIVE),
|
||||
MISDN_HW_FLAG(7, FLG_BUSY_TIMER),
|
||||
MISDN_HW_FLAG(8, FLG_DCHANNEL),
|
||||
MISDN_HW_FLAG(9, FLG_BCHANNEL),
|
||||
MISDN_HW_FLAG(10, FLG_ECHANNEL),
|
||||
MISDN_HW_FLAG(12, FLG_TRANSPARENT),
|
||||
MISDN_HW_FLAG(13, FLG_HDLC),
|
||||
MISDN_HW_FLAG(14, FLG_L2DATA),
|
||||
MISDN_HW_FLAG(15, FLG_ORIGIN),
|
||||
MISDN_HW_FLAG(16, FLG_FILLEMPTY),
|
||||
MISDN_HW_FLAG(17, FLG_ARCOFI_TIMER),
|
||||
MISDN_HW_FLAG(18, FLG_ARCOFI_ERROR),
|
||||
MISDN_HW_FLAG(17, FLG_INITIALIZED),
|
||||
MISDN_HW_FLAG(18, FLG_DLEETX),
|
||||
MISDN_HW_FLAG(19, FLG_LASTDLE),
|
||||
MISDN_HW_FLAG(20, FLG_FIRST),
|
||||
MISDN_HW_FLAG(21, FLG_LASTDATA),
|
||||
MISDN_HW_FLAG(22, FLG_NMD_DATA),
|
||||
MISDN_HW_FLAG(23, FLG_FTI_RUN),
|
||||
MISDN_HW_FLAG(24, FLG_LL_OK),
|
||||
MISDN_HW_FLAG(25, FLG_LL_CONN),
|
||||
MISDN_HW_FLAG(26, FLG_DTMFSEND),
|
||||
MISDN_HW_FLAG(30, FLG_RECVQUEUE),
|
||||
MISDN_HW_FLAG(31, FLG_PHCHANGE),
|
||||
#undef MISDN_HW_FLAG
|
||||
};
|
||||
|
||||
static const char *misdn_hw_print_flags(unsigned int flags, char *buf, int buflen)
|
||||
{
|
||||
int i;
|
||||
|
||||
buf[0] = '\0';
|
||||
for (i = 0; i < ftdm_array_len(misdn_hw_flags); i++) {
|
||||
if ((1 << misdn_hw_flags[i].flag) & flags) {
|
||||
strncat(buf, misdn_hw_flags[i].name, buflen);
|
||||
flags &= ~(1 << misdn_hw_flags[i].flag);
|
||||
if (!flags) break;
|
||||
strncat(buf, ",", buflen);
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int misdn_handle_mph_information_ind(ftdm_channel_t *chan, const struct mISDNhead *hh, const void *data, const int data_len)
|
||||
{
|
||||
struct misdn_chan_private *priv = ftdm_chan_io_private(chan);
|
||||
int alarm_flags, value;
|
||||
|
||||
if (data_len < sizeof(value)) {
|
||||
ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "mISDN MPH_INFORMATION_IND message is too short\n");
|
||||
/*
|
||||
* mISDN has some inconsistency issues here.
|
||||
*
|
||||
* There are only two drivers that emit MPH_INFORMATION_IND messages,
|
||||
* hfcsusb and hfcmulti. The former sends a set of ph_info and ph_info_ch structures,
|
||||
* while the latter just sends an int containing the current L1_SIGNAL_* event id.
|
||||
*
|
||||
* The flags and state information in the ph_info and ph_info_ch structures
|
||||
* are defined in kernel internal hw-specific headers (mISDNhw.h).
|
||||
*
|
||||
* Use the payload size to guess the type of message.
|
||||
*/
|
||||
if (data_len >= sizeof(struct ph_info)) {
|
||||
/* complete port status, hfcsusb sends this */
|
||||
struct ph_info *info = (struct ph_info *)data;
|
||||
struct ph_info_ch *bch_info = NULL;
|
||||
char tmp[1024] = { 0 };
|
||||
|
||||
if (data_len < (sizeof(*info) + info->dch.num_bch * sizeof(*bch_info))) {
|
||||
ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "mISDN MPH_INFORMATION_IND message is too short\n");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
bch_info = &info->bch[0];
|
||||
|
||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "mISDN port state:\n\tD-Chan proto:\t%hu\n\tD-Chan state:\t%s (%hu)\n\tD-Chan flags:\t%#lx\n\t\t\t%-70s\n",
|
||||
info->dch.ch.protocol,
|
||||
misdn_hw_state_name(info->dch.ch.protocol, info->dch.state), info->dch.state,
|
||||
info->dch.ch.Flags,
|
||||
misdn_hw_print_flags(info->dch.ch.Flags, tmp, sizeof(tmp) - 1));
|
||||
|
||||
/* TODO: try to translate this to a usable set of alarm flags */
|
||||
|
||||
} else if (data_len == sizeof(int)) {
|
||||
/* alarm info, sent by hfcmulti */
|
||||
int value = *(int *)data;
|
||||
int alarm_flags = chan->alarm_flags;
|
||||
|
||||
if (data_len < sizeof(value)) {
|
||||
ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "mISDN MPH_INFORMATION_IND message is too short\n");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case L1_SIGNAL_LOS_ON:
|
||||
alarm_flags |= FTDM_ALARM_RED;
|
||||
break;
|
||||
case L1_SIGNAL_LOS_OFF:
|
||||
alarm_flags &= ~FTDM_ALARM_RED;
|
||||
break;
|
||||
case L1_SIGNAL_AIS_ON:
|
||||
alarm_flags |= FTDM_ALARM_AIS;
|
||||
break;
|
||||
case L1_SIGNAL_AIS_OFF:
|
||||
alarm_flags &= ~FTDM_ALARM_AIS;
|
||||
break;
|
||||
case L1_SIGNAL_RDI_ON:
|
||||
alarm_flags |= FTDM_ALARM_YELLOW;
|
||||
break;
|
||||
case L1_SIGNAL_RDI_OFF:
|
||||
alarm_flags &= ~FTDM_ALARM_YELLOW;
|
||||
break;
|
||||
case L1_SIGNAL_SLIP_RX:
|
||||
priv->slip_rx_cnt++;
|
||||
break;
|
||||
case L1_SIGNAL_SLIP_TX:
|
||||
priv->slip_tx_cnt++;
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan(chan, FTDM_LOG_ERROR, "mISDN unknown MPH_INFORMATION_IND signal: %#04x\n",
|
||||
value);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
/* check whether alarm status has changed, update channel flags if it has */
|
||||
if ((value = (alarm_flags ^ chan->alarm_flags))) {
|
||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "mISDN alarm flags have changed %#x -> %#x\n",
|
||||
chan->alarm_flags, alarm_flags);
|
||||
chan->alarm_flags ^= value;
|
||||
}
|
||||
} else {
|
||||
ftdm_log_chan(chan, FTDM_LOG_ERROR, "mISDN sent MPH_INFORMATION_IND message with unknown size %d\n",
|
||||
data_len);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
value = *(int *)data;
|
||||
alarm_flags = chan->alarm_flags;
|
||||
|
||||
switch (value) {
|
||||
case L1_SIGNAL_LOS_ON:
|
||||
alarm_flags |= FTDM_ALARM_RED;
|
||||
break;
|
||||
case L1_SIGNAL_LOS_OFF:
|
||||
alarm_flags &= ~FTDM_ALARM_RED;
|
||||
break;
|
||||
case L1_SIGNAL_AIS_ON:
|
||||
alarm_flags |= FTDM_ALARM_AIS;
|
||||
break;
|
||||
case L1_SIGNAL_AIS_OFF:
|
||||
alarm_flags &= ~FTDM_ALARM_AIS;
|
||||
break;
|
||||
case L1_SIGNAL_RDI_ON:
|
||||
alarm_flags |= FTDM_ALARM_YELLOW;
|
||||
break;
|
||||
case L1_SIGNAL_RDI_OFF:
|
||||
alarm_flags &= ~FTDM_ALARM_YELLOW;
|
||||
break;
|
||||
case L1_SIGNAL_SLIP_RX:
|
||||
priv->slip_rx_cnt++;
|
||||
break;
|
||||
case L1_SIGNAL_SLIP_TX:
|
||||
priv->slip_tx_cnt++;
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan(chan, FTDM_LOG_ERROR, "mISDN unknown MPH_INFORMATION_IND message: %d\n",
|
||||
value);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
if ((value = (alarm_flags ^ chan->alarm_flags))) {
|
||||
ftdm_log_chan(chan, FTDM_LOG_DEBUG, "mISDN alarm flags have changed %#x -> %#x\n",
|
||||
chan->alarm_flags, alarm_flags);
|
||||
chan->alarm_flags ^= value;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -696,6 +942,7 @@ static FIO_OPEN_FUNCTION(misdn_open)
|
||||
|
||||
switch (ftdmchan->type) {
|
||||
case FTDM_CHAN_TYPE_B: {
|
||||
#if 0
|
||||
struct itimerspec its = {
|
||||
.it_interval = { 0, 0 },
|
||||
.it_value = { 0, 0 },
|
||||
@@ -722,13 +969,14 @@ static FIO_OPEN_FUNCTION(misdn_open)
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "mISDN created tx interval (%d ms) timer\n",
|
||||
ftdmchan->effective_interval);
|
||||
#endif
|
||||
}
|
||||
case FTDM_CHAN_TYPE_DQ921:
|
||||
chan_priv->state = MISDN_CHAN_STATE_OPEN;
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "mISDN invalid channel type '%s'\n",
|
||||
ftdm_channel_get_type(ftdmchan));
|
||||
ftdm_channel_get_type_str(ftdmchan));
|
||||
break;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
@@ -745,8 +993,12 @@ static FIO_CLOSE_FUNCTION(misdn_close)
|
||||
|
||||
assert(chan_priv);
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "mISDN trying to close %c-channel\n",
|
||||
ftdm_channel_get_type(ftdmchan) == FTDM_CHAN_TYPE_B ? 'B' : 'D');
|
||||
|
||||
/* deactivate b-channels on close */
|
||||
if (ftdm_channel_get_type(ftdmchan) == FTDM_CHAN_TYPE_B) {
|
||||
#if 0
|
||||
/*
|
||||
* Stop tx timerfd
|
||||
*/
|
||||
@@ -754,17 +1006,19 @@ static FIO_CLOSE_FUNCTION(misdn_close)
|
||||
close(chan_priv->timerfd);
|
||||
chan_priv->timerfd = -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Send deactivation request (don't wait for answer)
|
||||
*/
|
||||
ret = misdn_activate_channel(ftdmchan, 0);
|
||||
if (ret != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to deactivate channel\n");
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to deactivate %c-channel\n",
|
||||
ftdm_channel_get_type(ftdmchan) == FTDM_CHAN_TYPE_B ? 'B' : 'D');
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "mISDN channel deactivated\n");
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "mISDN %c-channel deactivated\n",
|
||||
ftdm_channel_get_type(ftdmchan) == FTDM_CHAN_TYPE_B ? 'B' : 'D');
|
||||
chan_priv->state = MISDN_CHAN_STATE_CLOSED;
|
||||
}
|
||||
|
||||
@@ -823,8 +1077,8 @@ static FIO_COMMAND_FUNCTION(misdn_command)
|
||||
|
||||
case FTDM_COMMAND_GET_INTERVAL:
|
||||
FTDM_COMMAND_OBJ_INT = ftdm_channel_get_io_interval(ftdmchan);
|
||||
ftdm_log(FTDM_LOG_NOTICE, "Interval %d ms [%d:%d]\n",
|
||||
ftdm_channel_get_io_interval(ftdmchan), ftdm_channel_get_span_id(ftdmchan), ftdm_channel_get_id(ftdmchan));
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Interval %d ms\n",
|
||||
ftdm_channel_get_io_interval(ftdmchan));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -852,8 +1106,8 @@ static FIO_WAIT_FUNCTION(misdn_wait)
|
||||
switch (ftdm_channel_get_type(ftdmchan)) {
|
||||
case FTDM_CHAN_TYPE_B:
|
||||
if (*flags & FTDM_WRITE) {
|
||||
pfds[nr_fds].fd = chan_priv->timerfd;
|
||||
pfds[nr_fds].events = POLLIN;
|
||||
pfds[nr_fds].fd = chan_priv->audio_pipe_in;
|
||||
pfds[nr_fds].events = POLLOUT;
|
||||
nr_fds++;
|
||||
}
|
||||
if (*flags & (FTDM_READ | FTDM_EVENTS)) {
|
||||
@@ -877,8 +1131,11 @@ static FIO_WAIT_FUNCTION(misdn_wait)
|
||||
|
||||
*flags = FTDM_NO_FLAGS;
|
||||
|
||||
if (!(pfds[0].events || pfds[1].events))
|
||||
if (!(pfds[0].events || pfds[1].events)) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "mISDN poll(): no flags set!\n");
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
if ((retval = poll(pfds, nr_fds, to)) < 0) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "mISDN poll() failed: %s\n",
|
||||
strerror(errno));
|
||||
@@ -889,18 +1146,13 @@ static FIO_WAIT_FUNCTION(misdn_wait)
|
||||
|
||||
switch (ftdm_channel_get_type(ftdmchan)) {
|
||||
case FTDM_CHAN_TYPE_B:
|
||||
if (pfds[0].fd == chan_priv->timerfd) {
|
||||
if (pfds[0].revents & POLLIN) {
|
||||
uint64_t tmp = 0; /* clear pending events on timerfd */
|
||||
retval = read(pfds[0].fd, &tmp, sizeof(tmp));
|
||||
*flags |= FTDM_WRITE;
|
||||
}
|
||||
if (pfds[1].revents & POLLIN)
|
||||
*flags |= FTDM_READ;
|
||||
if (pfds[1].revents & POLLPRI)
|
||||
*flags |= FTDM_EVENTS;
|
||||
break;
|
||||
}
|
||||
if (pfds[0].revents & POLLOUT)
|
||||
*flags |= FTDM_WRITE;
|
||||
if ((pfds[0].revents & POLLIN) || (pfds[1].revents & POLLIN))
|
||||
*flags |= FTDM_READ;
|
||||
if ((pfds[0].revents & POLLPRI) || (pfds[1].revents & POLLPRI))
|
||||
*flags |= FTDM_EVENTS;
|
||||
break;
|
||||
default:
|
||||
if (pfds[0].revents & POLLIN)
|
||||
*flags |= FTDM_READ;
|
||||
@@ -913,6 +1165,81 @@ static FIO_WAIT_FUNCTION(misdn_wait)
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle incoming mISDN message on d-channel
|
||||
* @param[in] ftdmchan
|
||||
* @param[in] msg_buf
|
||||
* @param[in] msg_len
|
||||
* @internal
|
||||
*/
|
||||
static ftdm_status_t misdn_handle_incoming(ftdm_channel_t *ftdmchan, const char *msg_buf, const int msg_len)
|
||||
{
|
||||
struct misdn_chan_private *priv = ftdm_chan_io_private(ftdmchan);
|
||||
struct mISDNhead *hh = (struct mISDNhead *)msg_buf;
|
||||
const char *data = msg_buf + sizeof(*hh);
|
||||
int data_len = msg_len - sizeof(*hh);
|
||||
|
||||
assert(msg_buf);
|
||||
assert(priv);
|
||||
|
||||
if (msg_len < sizeof(*hh)) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "mISDN message to small (%d < %d bytes)\n",
|
||||
msg_len, sizeof(*hh));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
#ifdef MISDN_DEBUG_EVENTS
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "mISDN %c-channel received '%s' message (id: 0x%x, additional data: %d bytes)\n",
|
||||
ftdm_channel_get_type(ftdmchan) == FTDM_CHAN_TYPE_B ? 'B' : 'D', misdn_event2str(hh->prim), hh->id, data_len);
|
||||
#endif
|
||||
|
||||
switch (hh->prim) {
|
||||
/* data events */
|
||||
case PH_DATA_CNF: /* TX: ack */
|
||||
priv->tx_ack_cnt++;
|
||||
break;
|
||||
case PH_DATA_REQ: /* TX: request echo (ignore) */
|
||||
break;
|
||||
case PH_DATA_E_IND: /* RX: e-channel data received (monitoring?) */
|
||||
break;
|
||||
|
||||
/* control requests */
|
||||
case PH_CONTROL_IND:
|
||||
return misdn_handle_ph_control_ind(ftdmchan, hh, data, data_len);
|
||||
case PH_CONTROL_REQ:
|
||||
case PH_CONTROL_CNF:
|
||||
break;
|
||||
|
||||
/* information */
|
||||
case MPH_INFORMATION_IND:
|
||||
return misdn_handle_mph_information_ind(ftdmchan, hh, data, data_len);
|
||||
|
||||
/* channel de-/activation */
|
||||
case PH_ACTIVATE_REQ: /* Echoed requests, ignore */
|
||||
case PH_DEACTIVATE_REQ:
|
||||
break;
|
||||
case PH_ACTIVATE_IND:
|
||||
case PH_DEACTIVATE_IND: {
|
||||
/* other events, enqueue and let misdn_event_next handle it */
|
||||
struct misdn_span_private *span_priv = ftdm_span_io_private(ftdmchan->span);
|
||||
struct misdn_event evt = { 0 };
|
||||
evt.id = hh->prim;
|
||||
|
||||
misdn_event_queue_push(priv->events, &evt);
|
||||
|
||||
/* wake possible readers */
|
||||
pthread_cond_signal(&span_priv->event_cond);
|
||||
break;
|
||||
}
|
||||
default: /* error? */
|
||||
ftdm_log(FTDM_LOG_DEBUG, "mISDN channel %d:%d received unknown event %d\n",
|
||||
ftdm_channel_get_span_id(ftdmchan), ftdm_channel_get_id(ftdmchan), hh->prim);
|
||||
break;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Read data
|
||||
* \param ftdmchan FreeTDM channel
|
||||
@@ -926,22 +1253,29 @@ static FIO_READ_FUNCTION(misdn_read)
|
||||
struct mISDNhead *hh = (struct mISDNhead *)rbuf;
|
||||
int bytes = *datalen;
|
||||
int retval;
|
||||
int maxretry = 10;
|
||||
|
||||
if (priv->state == MISDN_CHAN_STATE_CLOSED) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "mISDN ignoring read on closed channel\n");
|
||||
/* ignore */
|
||||
*datalen = 0;
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/* nothing read yet */
|
||||
*datalen = 0;
|
||||
|
||||
/*
|
||||
* try to read all messages, as long as we haven't received a PH_DATA_IND one
|
||||
* we'll get a lot of "mISDN_send: error -12" message in dmesg otherwise
|
||||
* (= b-channel receive queue overflowing)
|
||||
*/
|
||||
while (1) {
|
||||
if ((retval = recvfrom(ftdmchan->sockfd, rbuf, sizeof(rbuf), 0, NULL, NULL)) < 0) {
|
||||
if (errno == EWOULDBLOCK) break;
|
||||
if (errno == EAGAIN) continue;
|
||||
while (maxretry--) {
|
||||
struct sockaddr_mISDN addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
|
||||
if ((retval = recvfrom(ftdmchan->sockfd, rbuf, sizeof(rbuf), 0, (struct sockaddr *)&addr, &addrlen)) < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) break;
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "mISDN failed to receive incoming message: %s\n",
|
||||
strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
@@ -953,22 +1287,94 @@ static FIO_READ_FUNCTION(misdn_read)
|
||||
}
|
||||
|
||||
if (hh->prim == PH_DATA_IND) {
|
||||
*datalen = MIN(bytes, retval - MISDN_HEADER_LEN);
|
||||
memcpy(data, rbuf + MISDN_HEADER_LEN, *datalen);
|
||||
*datalen = CLAMP(retval - MISDN_HEADER_LEN, 0, bytes);
|
||||
#ifdef MISDN_DEBUG_IO
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "misdn_read() received '%s', id: %#x, with %d bytes from channel socket %d [dev.ch: %d.%d]\n",
|
||||
misdn_event2str(hh->prim), hh->id, retval - MISDN_HEADER_LEN, ftdmchan->sockfd, addr.dev, addr.channel);
|
||||
|
||||
if (*datalen > 0) {
|
||||
char hbuf[MAX_DATA_MEM] = { 0 };
|
||||
print_hex_bytes(data, *datalen, hbuf, sizeof(hbuf));
|
||||
ftdm_log(FTDM_LOG_DEBUG, "mISDN read data: %s\n", hbuf);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "mISDN read data: %s\n", hbuf);
|
||||
}
|
||||
#endif
|
||||
if (*datalen <= 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Copy data into ouput buffer (excluding the mISDN message header)
|
||||
* NOTE: audio data needs to be converted to a-law / u-law!
|
||||
*/
|
||||
memcpy(data, rbuf + MISDN_HEADER_LEN, *datalen);
|
||||
|
||||
switch (ftdm_channel_get_type(ftdmchan)) {
|
||||
case FTDM_CHAN_TYPE_B:
|
||||
hh->prim = PH_DATA_REQ;
|
||||
hh->id = MISDN_ID_ANY;
|
||||
bytes = *datalen;
|
||||
|
||||
/* Convert incoming audio data to *-law */
|
||||
misdn_convert_audio_bits(data, *datalen);
|
||||
|
||||
/*
|
||||
* Fetch required amount of audio from tx pipe, using the amount
|
||||
* of received bytes as an indicator for how much free space the
|
||||
* b-channel tx buffer has available.
|
||||
*
|
||||
* (see misdn_write() for the part that fills the tx pipe)
|
||||
*
|
||||
* NOTE: can't use blocking I/O here since both parts are serviced
|
||||
* from the same thread
|
||||
*/
|
||||
if ((retval = read(priv->audio_pipe_out, rbuf + MISDN_HEADER_LEN, bytes)) < 0) {
|
||||
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "mISDN failed to read %d bytes of audio data: %s\n",
|
||||
bytes, strerror(errno));
|
||||
break;
|
||||
}
|
||||
/* Tx pipe is empty, completely fill buffer up to "bytes" with silence value */
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a-law / u-law silence to fill missing bytes,
|
||||
* in case there was not enough audio data available in the
|
||||
* tx pipe to satisfy the request.
|
||||
*/
|
||||
if (retval < bytes) {
|
||||
memset(&rbuf[MISDN_HEADER_LEN + retval],
|
||||
(ftdm_channel_get_codec(ftdmchan) == FTDM_CODEC_ALAW) ? 0x2a : 0xff,
|
||||
bytes - retval);
|
||||
}
|
||||
|
||||
/* Convert outgoing audio data to wire format */
|
||||
misdn_convert_audio_bits(rbuf + MISDN_HEADER_LEN, bytes);
|
||||
bytes += MISDN_HEADER_LEN;
|
||||
|
||||
/* Send converted audio to b-channel */
|
||||
if ((retval = sendto(ftdmchan->sockfd, rbuf, bytes, 0, (struct sockaddr *)&priv->addr, sizeof(priv->addr))) < bytes) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "mISDN failed to send %d bytes of audio data: (%d) %s\n",
|
||||
bytes, retval, strerror(errno));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
} else {
|
||||
*datalen = 0;
|
||||
#ifdef MISDN_DEBUG_IO
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "misdn_read() received '%s', id: %#x, with %d bytes from channel socket %d [dev.ch: %d.%d]\n",
|
||||
misdn_event2str(hh->prim), hh->id, retval - MISDN_HEADER_LEN, ftdmchan->sockfd, addr.dev, addr.channel);
|
||||
#endif
|
||||
/* event */
|
||||
misdn_handle_incoming(ftdmchan, rbuf, retval);
|
||||
}
|
||||
}
|
||||
#ifdef MISDN_DEBUG_IO
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "mISDN nothing received on %c-channel\n",
|
||||
ftdm_channel_get_type(ftdmchan) == FTDM_CHAN_TYPE_B ? 'B' : 'D');
|
||||
#endif
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -985,6 +1391,7 @@ static FIO_WRITE_FUNCTION(misdn_write)
|
||||
struct mISDNhead *hh = (struct mISDNhead *)wbuf;
|
||||
int size = *datalen;
|
||||
int retval = 0;
|
||||
ftdm_wait_flag_t wflags;
|
||||
|
||||
assert(priv);
|
||||
|
||||
@@ -999,30 +1406,56 @@ static FIO_WRITE_FUNCTION(misdn_write)
|
||||
ftdm_log(FTDM_LOG_DEBUG, "mISDN write data: %s\n", hbuf);
|
||||
}
|
||||
#endif
|
||||
hh->prim = PH_DATA_REQ;
|
||||
hh->id = MISDN_ID_ANY;
|
||||
*datalen = 0;
|
||||
|
||||
/* avoid buffer overflow */
|
||||
size = MIN(size, MAX_DATA_MEM);
|
||||
switch (ftdm_channel_get_type(ftdmchan)) {
|
||||
case FTDM_CHAN_TYPE_B:
|
||||
/*
|
||||
* Write to audio pipe, misdn_read() will pull
|
||||
* from there as needed and send it to the b-channel
|
||||
*
|
||||
* NOTE: can't use blocking I/O here since both parts are serviced
|
||||
* from the same thread
|
||||
*/
|
||||
if ((retval = write(priv->audio_pipe_in, data, size)) < size) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "mISDN channel audio pipe write error: %s\n",
|
||||
strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
*datalen = retval;
|
||||
break;
|
||||
default:
|
||||
hh->prim = PH_DATA_REQ;
|
||||
hh->id = MISDN_ID_ANY;
|
||||
|
||||
memcpy(wbuf + MISDN_HEADER_LEN, data, size);
|
||||
size += MISDN_HEADER_LEN;
|
||||
/* Avoid buffer overflow */
|
||||
size = MIN(size, MAX_DATA_MEM - MISDN_HEADER_LEN);
|
||||
|
||||
memcpy(wbuf + MISDN_HEADER_LEN, data, size);
|
||||
size += MISDN_HEADER_LEN;
|
||||
|
||||
/* wait for channel to get ready */
|
||||
wflags = FTDM_WRITE;
|
||||
retval = misdn_wait(ftdmchan, &wflags, 20);
|
||||
if (retval) {
|
||||
/* timeout, io error */
|
||||
*datalen = 0;
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
#ifdef MISDN_DEBUG_IO
|
||||
ftdm_log(FTDM_LOG_DEBUG, "mISDN writing %d bytes to channel %d:%d socket %d\n",
|
||||
size, ftdm_channel_get_span_id(ftdmchan), ftdm_channel_get_id(ftdmchan), ftdmchan->sockfd);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "mISDN writing %d bytes to channel socket %d [dev.ch: %d.%d]\n",
|
||||
size, ftdmchan->sockfd, priv->addr.dev, priv->addr.channel);
|
||||
#endif
|
||||
if ((retval = sendto(ftdmchan->sockfd, wbuf, size, 0, NULL, 0)) != size) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "mISDN channel %d:%d socket write error: %s\n",
|
||||
ftdm_channel_get_span_id(ftdmchan), ftdm_channel_get_id(ftdmchan),
|
||||
strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
*datalen = retval;
|
||||
|
||||
// if (priv->debugfd >= 0) {
|
||||
// write(priv->debugfd, wbuf + MISDN_HEADER_LEN, size - MISDN_HEADER_LEN);
|
||||
// }
|
||||
if ((retval = sendto(ftdmchan->sockfd, wbuf, size, 0, NULL, 0)) < size) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "mISDN channel socket write error: %s\n",
|
||||
strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
*datalen = retval;
|
||||
break;
|
||||
}
|
||||
|
||||
priv->tx_cnt++;
|
||||
return FTDM_SUCCESS;
|
||||
@@ -1149,12 +1582,30 @@ static ftdm_status_t misdn_open_range(ftdm_span_t *span, ftdm_chan_type_t type,
|
||||
ftdmchan->physical_chan_id = x;
|
||||
|
||||
if (ftdmchan->type == FTDM_CHAN_TYPE_B) {
|
||||
int pipefd[2] = { -1, -1 };
|
||||
|
||||
ftdmchan->packet_len = 10 /* ms */ * (ftdmchan->rate / 1000);
|
||||
ftdmchan->effective_interval = ftdmchan->native_interval = ftdmchan->packet_len / 8;
|
||||
ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_ALAW;
|
||||
|
||||
ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL);
|
||||
|
||||
/*
|
||||
* Create audio tx pipe, use non-blocking I/O to avoid deadlock since both ends
|
||||
* are used from the same thread
|
||||
*/
|
||||
if (pipe2(pipefd, O_NONBLOCK) < 0) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to create mISDN audio write pipe [%d:%d]: %s\n",
|
||||
addr.dev, x, strerror(errno));
|
||||
close(sockfd);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
priv->audio_pipe_in = pipefd[1];
|
||||
priv->audio_pipe_out = pipefd[0];
|
||||
|
||||
} else {
|
||||
/* early activate D-Channel */
|
||||
misdn_activate_channel(ftdmchan, 1);
|
||||
ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE;
|
||||
}
|
||||
num_configured++;
|
||||
@@ -1589,71 +2040,6 @@ static FIO_SPAN_DESTROY_FUNCTION(misdn_span_destroy)
|
||||
}
|
||||
|
||||
|
||||
static ftdm_status_t misdn_handle_incoming(ftdm_channel_t *ftdmchan, const char *rbuf, const int size)
|
||||
{
|
||||
struct mISDNhead *hh = (struct mISDNhead *)rbuf;
|
||||
struct misdn_chan_private *priv = ftdm_chan_io_private(ftdmchan);
|
||||
const char *data = rbuf + sizeof(*hh);
|
||||
int data_len = size - sizeof(*hh);
|
||||
|
||||
assert(priv);
|
||||
|
||||
#ifdef MISDN_DEBUG_EVENTS
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "mISDN channel received '%s' message (additional data: %d bytes)\n",
|
||||
misdn_event2str(hh->prim), data_len);
|
||||
#endif
|
||||
|
||||
switch (hh->prim) {
|
||||
/* data events */
|
||||
case PH_DATA_CNF: /* TX ack */
|
||||
priv->tx_ack_cnt++;
|
||||
break;
|
||||
case PH_DATA_REQ: /* request echo? */
|
||||
break;
|
||||
case PH_DATA_E_IND: /* TX/RX ERR(?) */
|
||||
break;
|
||||
|
||||
/* control events */
|
||||
case PH_ACTIVATE_REQ:
|
||||
case PH_DEACTIVATE_REQ:
|
||||
/*
|
||||
* Echoed(?) L2->L1 requests, ignore...
|
||||
* (something broken in mISDN or the way we setup the channel?)
|
||||
*/
|
||||
break;
|
||||
case PH_CONTROL_IND:
|
||||
return misdn_handle_ph_control_ind(ftdmchan, hh, data, data_len);
|
||||
case PH_CONTROL_REQ:
|
||||
case PH_CONTROL_CNF:
|
||||
break;
|
||||
|
||||
case MPH_INFORMATION_IND:
|
||||
return misdn_handle_mph_information_ind(ftdmchan, hh, data, data_len);
|
||||
|
||||
case PH_ACTIVATE_IND:
|
||||
case PH_DEACTIVATE_IND:
|
||||
{
|
||||
/* other events, enqueue and let misdn_event_next handle it */
|
||||
struct misdn_span_private *span_priv = ftdm_span_io_private(ftdmchan->span);
|
||||
struct misdn_event evt = { 0 };
|
||||
evt.id = hh->prim;
|
||||
|
||||
misdn_event_queue_push(priv->events, &evt);
|
||||
|
||||
/* wake possible readers */
|
||||
pthread_cond_signal(&span_priv->event_cond);
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* error? */
|
||||
ftdm_log(FTDM_LOG_DEBUG, "mISDN channel %d:%d received unknown event %d\n",
|
||||
ftdm_channel_get_span_id(ftdmchan), ftdm_channel_get_id(ftdmchan), hh->prim);
|
||||
break;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief ftmod_misdn interface
|
||||
*/
|
||||
|
||||
@@ -391,7 +391,7 @@ static void *ftdm_sangoma_isdn_io_run(ftdm_thread_t *me, void *obj)
|
||||
case FTDM_SUCCESS:
|
||||
/* Check if there are any channels that have data available */
|
||||
for (citer = ftdm_span_get_chan_iterator(span, chaniter); citer; citer = ftdm_iterator_next(citer)) {
|
||||
len = 1000;
|
||||
len = sizeof(data);
|
||||
ftdmchan = ftdm_iterator_current(citer);
|
||||
if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED)) {
|
||||
@@ -682,16 +682,26 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_DIALING: /* outgoing call request */
|
||||
{
|
||||
if (FTDM_SPAN_IS_BRI(ftdmchan->span) &&
|
||||
ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM) &&
|
||||
ftdm_test_flag(ftdmchan->span, FTDM_SPAN_PWR_SAVING)) {
|
||||
|
||||
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);
|
||||
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);
|
||||
if (FTDM_SPAN_IS_BRI(ftdmchan->span) && ftdm_test_flag(ftdmchan->span, FTDM_SPAN_PWR_SAVING)) {
|
||||
ftdm_signaling_status_t sigstatus;
|
||||
ftdm_span_get_sig_status(ftdmchan->span, &sigstatus);
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)ftdmchan->span->signal_data;
|
||||
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Requesting Physical Line activation\n");
|
||||
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 if (sigstatus == FTDM_SIG_STATE_DOWN) {
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)ftdmchan->span->signal_data;
|
||||
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Requesting Q.921 Line activation\n");
|
||||
sngisdn_set_flag(sngisdn_info, FLAG_ACTIVATING);
|
||||
sngisdn_snd_info_req(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);
|
||||
}
|
||||
} else {
|
||||
sngisdn_snd_setup(ftdmchan);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,11 @@
|
||||
#include "private/ftdm_core.h"
|
||||
#include "ftmod_sangoma_isdn_user.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <sng_isdn.h>
|
||||
#else
|
||||
#include <sng_isdn/sng_isdn.h>
|
||||
#endif
|
||||
|
||||
/* Theoretical limit for MAX_SPANS_PER_NFAS_LINK is 31,
|
||||
but set to 8 for now to save some memory */
|
||||
@@ -67,8 +71,6 @@
|
||||
#define MI_NOTIFY 0x14
|
||||
#endif
|
||||
|
||||
/* TODO: rename all *_cc_* to *_an_* */
|
||||
|
||||
typedef enum {
|
||||
FLAG_RESET_RX = (1 << 0),
|
||||
FLAG_RESET_TX = (1 << 1),
|
||||
@@ -258,7 +260,7 @@ typedef struct sngisdn_span_data {
|
||||
uint8_t setup_arb;
|
||||
uint8_t facility_ie_decode;
|
||||
uint8_t facility;
|
||||
int8_t facility_timeout;
|
||||
int32_t facility_timeout;
|
||||
uint8_t att_remove_dtmf;
|
||||
int32_t transfer_timeout;
|
||||
uint8_t num_local_numbers;
|
||||
@@ -273,6 +275,24 @@ typedef struct sngisdn_span_data {
|
||||
uint8_t force_sending_complete;
|
||||
uint8_t cid_name_method;
|
||||
uint8_t send_cid_name;
|
||||
|
||||
int32_t timer_t301;
|
||||
int32_t timer_t302;
|
||||
int32_t timer_t303;
|
||||
int32_t timer_t304;
|
||||
int32_t timer_t305;
|
||||
int32_t timer_t306;
|
||||
int32_t timer_t307;
|
||||
int32_t timer_t308;
|
||||
int32_t timer_t310;
|
||||
int32_t timer_t312;
|
||||
int32_t timer_t313;
|
||||
int32_t timer_t314;
|
||||
int32_t timer_t316;
|
||||
int32_t timer_t318;
|
||||
int32_t timer_t319;
|
||||
int32_t timer_t322;
|
||||
|
||||
char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS];
|
||||
ftdm_timer_id_t timers[SNGISDN_NUM_SPAN_TIMERS];
|
||||
ftdm_sched_t *sched;
|
||||
@@ -479,6 +499,7 @@ ftdm_status_t get_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad);
|
||||
ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd);
|
||||
ftdm_status_t get_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr);
|
||||
ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t data_len);
|
||||
ftdm_status_t get_network_specific_fac(ftdm_channel_t *ftdmchan, NetFac *netFac);
|
||||
|
||||
ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb);
|
||||
ftdm_status_t set_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb);
|
||||
@@ -488,6 +509,7 @@ ftdm_status_t set_calling_name(ftdm_channel_t *ftdmchan, ConEvnt *conEvnt);
|
||||
ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad);
|
||||
ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_sngisdn_progind_t prog_ind);
|
||||
ftdm_status_t set_bear_cap_ie(ftdm_channel_t *ftdmchan, BearCap *bearCap);
|
||||
ftdm_status_t set_network_specific_fac(ftdm_channel_t *ftdmchan, NetFac *netFac);
|
||||
ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId);
|
||||
ftdm_status_t set_restart_ind_ie(ftdm_channel_t *ftdmchan, RstInd *rstInd);
|
||||
ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr);
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "ftmod_sangoma_isdn.h"
|
||||
|
||||
static ftdm_status_t parse_timer(const char* val, int32_t *target);
|
||||
static ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span);
|
||||
static ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span);
|
||||
static ftdm_status_t add_local_number(const char* val, ftdm_span_t *span);
|
||||
@@ -42,6 +43,16 @@ static ftdm_status_t set_switchtype_defaults(ftdm_span_t *span);
|
||||
|
||||
extern ftdm_sngisdn_data_t g_sngisdn_data;
|
||||
|
||||
|
||||
static ftdm_status_t parse_timer(const char* val, int32_t *target)
|
||||
{
|
||||
*target = atoi(val);
|
||||
if (*target < 0) {
|
||||
*target = 0;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
static ftdm_status_t parse_yesno(const char* var, const char* val, uint8_t *target)
|
||||
{
|
||||
if (ftdm_true(val)) {
|
||||
@@ -369,15 +380,9 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
} else if (!strcasecmp(var, "facility-timeout")) {
|
||||
signal_data->facility_timeout = atoi(val);
|
||||
if (signal_data->facility_timeout < 0) {
|
||||
signal_data->facility_timeout = 0;
|
||||
}
|
||||
parse_timer(val, &signal_data->facility_timeout);
|
||||
} else if (!strcasecmp(var, "transfer-timeout")) {
|
||||
signal_data->transfer_timeout = atoi(val);
|
||||
if (signal_data->transfer_timeout < 0) {
|
||||
signal_data->transfer_timeout = 0;
|
||||
}
|
||||
parse_timer(val, &signal_data->transfer_timeout);
|
||||
} else if (!strcasecmp(var, "att-remove-dtmf")) {
|
||||
parse_yesno(var, val, &signal_data->att_remove_dtmf);
|
||||
} else if (!strcasecmp(var, "facility-ie-decode")) {
|
||||
@@ -428,6 +433,38 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
|
||||
ftdm_log(FTDM_LOG_WARNING, "Invalid option %s for parameter %s\n", val, var);
|
||||
signal_data->send_cid_name = SNGISDN_OPT_DEFAULT;
|
||||
}
|
||||
} else if (!strcasecmp(var, "timer-t301")) {
|
||||
parse_timer(val, &signal_data->timer_t301);
|
||||
} else if (!strcasecmp(var, "timer-t302")) {
|
||||
parse_timer(val, &signal_data->timer_t302);
|
||||
} else if (!strcasecmp(var, "timer-t303")) {
|
||||
parse_timer(val, &signal_data->timer_t303);
|
||||
} else if (!strcasecmp(var, "timer-t304")) {
|
||||
parse_timer(val, &signal_data->timer_t304);
|
||||
} else if (!strcasecmp(var, "timer-t305")) {
|
||||
parse_timer(val, &signal_data->timer_t305);
|
||||
} else if (!strcasecmp(var, "timer-t306")) {
|
||||
parse_timer(val, &signal_data->timer_t306);
|
||||
} else if (!strcasecmp(var, "timer-t307")) {
|
||||
parse_timer(val, &signal_data->timer_t307);
|
||||
} else if (!strcasecmp(var, "timer-t308")) {
|
||||
parse_timer(val, &signal_data->timer_t308);
|
||||
} else if (!strcasecmp(var, "timer-t310")) {
|
||||
parse_timer(val, &signal_data->timer_t310);
|
||||
} else if (!strcasecmp(var, "timer-t312")) {
|
||||
parse_timer(val, &signal_data->timer_t312);
|
||||
} else if (!strcasecmp(var, "timer-t313")) {
|
||||
parse_timer(val, &signal_data->timer_t313);
|
||||
} else if (!strcasecmp(var, "timer-t314")) {
|
||||
parse_timer(val, &signal_data->timer_t314);
|
||||
} else if (!strcasecmp(var, "timer-t316")) {
|
||||
parse_timer(val, &signal_data->timer_t316);
|
||||
} else if (!strcasecmp(var, "timer-t318")) {
|
||||
parse_timer(val, &signal_data->timer_t318);
|
||||
} else if (!strcasecmp(var, "timer-t319")) {
|
||||
parse_timer(val, &signal_data->timer_t319);
|
||||
} else if (!strcasecmp(var, "timer-t322")) {
|
||||
parse_timer(val, &signal_data->timer_t322);
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,16 @@ void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status
|
||||
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
|
||||
sig.ev_data.sigstatus.status = status;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sig);
|
||||
|
||||
if (FTDM_SPAN_IS_BRI(ftdmchan->span)) {
|
||||
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)ftdmchan->span->signal_data;
|
||||
if (ftdm_test_flag(sngisdn_info, FLAG_ACTIVATING)) {
|
||||
ftdm_clear_flag(sngisdn_info, FLAG_ACTIVATING);
|
||||
|
||||
ftdm_sched_timer(signal_data->sched, "delayed_setup", 1000, sngisdn_delayed_setup, (void*) sngisdn_info, NULL);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -750,10 +750,12 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
|
||||
cfg.t.cfg.s.inDLSAP.redirAdr.eh.pres = NOTPRSNT; /* redirAdr Numbering Plan */
|
||||
cfg.t.cfg.s.inDLSAP.forwSubsc = FALSE; /* programmed forwarding subscription */
|
||||
cfg.t.cfg.s.inDLSAP.cndSubsc = TRUE; /* calling adddress delivery service subscription */
|
||||
|
||||
/* TODO: Fill in these timers with proper values - eventually pass them */
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t301.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t301.val = 180;
|
||||
if (signal_data->timer_t301 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t301.val = signal_data->timer_t301;
|
||||
}
|
||||
|
||||
/* It looks like ETSI is the only variant that supports Overlap */
|
||||
if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN) {
|
||||
@@ -764,21 +766,54 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t302.val = 0;
|
||||
}
|
||||
|
||||
if (signal_data->timer_t302 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t302.val = signal_data->timer_t302;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t303.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t303.val = 4;
|
||||
|
||||
if (signal_data->timer_t303 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t303.val = signal_data->timer_t303;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t304.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t304.val = 30;
|
||||
|
||||
if (signal_data->timer_t304 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t304.val = signal_data->timer_t304;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t305.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t305.val = 30;
|
||||
|
||||
if (signal_data->timer_t305 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t305.val = signal_data->timer_t305;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t306.enb = FALSE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t306.val = 35;
|
||||
|
||||
if (signal_data->timer_t306 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t306.val = signal_data->timer_t306;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t307.enb = FALSE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t307.val = 35;
|
||||
|
||||
if (signal_data->timer_t307 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t307.val = signal_data->timer_t307;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t308.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t308.val = 4;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t310.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t310.val = 120;
|
||||
|
||||
if (signal_data->timer_t308 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t308.val = signal_data->timer_t308;
|
||||
}
|
||||
|
||||
if (signal_data->signalling == SNGISDN_SIGNALING_NET) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t312.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t312.val = cfg.t.cfg.s.inDLSAP.tmr.t303.val+2;
|
||||
@@ -786,18 +821,52 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t312.enb = FALSE;
|
||||
}
|
||||
|
||||
if (signal_data->timer_t310 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t310.val = signal_data->timer_t310;
|
||||
}
|
||||
|
||||
if (signal_data->timer_t312 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t312.val = signal_data->timer_t312;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t313.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t313.val = 4;
|
||||
|
||||
if (signal_data->timer_t313 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t313.val = signal_data->timer_t313;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t316.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t316.val = 120;
|
||||
|
||||
if (signal_data->timer_t316 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t316.val = signal_data->timer_t316;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t316c.enb = FALSE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t316c.val = 35;
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t318.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t318.val = 4;
|
||||
|
||||
if (signal_data->timer_t318 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t318.val = signal_data->timer_t318;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t319.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t319.val = 4;
|
||||
|
||||
if (signal_data->timer_t319 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t319.val = signal_data->timer_t319;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t322.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t322.val = 4;
|
||||
|
||||
if (signal_data->timer_t322 > 0) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t322.val = signal_data->timer_t322;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t332.enb = FALSE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t332.val = 35;
|
||||
|
||||
@@ -912,8 +981,18 @@ ftdm_status_t sngisdn_stack_cfg_q931_lce(ftdm_span_t *span)
|
||||
cfg.t.cfg.s.inLCe.lnkUpDwnInd = TRUE;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inLCe.tCon.enb = TRUE;
|
||||
cfg.t.cfg.s.inLCe.tCon.val = 35;
|
||||
if (FTDM_SPAN_IS_BRI(span)) {
|
||||
/* tCon Timer causes unwanted hangup on BRI links
|
||||
where the Q.921 link goes into disconnected
|
||||
state when idle. */
|
||||
|
||||
cfg.t.cfg.s.inLCe.tCon.enb = FALSE;
|
||||
cfg.t.cfg.s.inLCe.tCon.val = 0;
|
||||
} else {
|
||||
cfg.t.cfg.s.inLCe.tCon.enb = TRUE;
|
||||
cfg.t.cfg.s.inLCe.tCon.val = 35;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inLCe.tDisc.enb = TRUE;
|
||||
cfg.t.cfg.s.inLCe.tDisc.val = 35;
|
||||
cfg.t.cfg.s.inLCe.t314.enb = FALSE; /* if segmentation enabled, set to TRUE */
|
||||
|
||||
@@ -133,8 +133,9 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
|
||||
get_redir_num(ftdmchan, &conEvnt->redirNmb);
|
||||
get_calling_subaddr(ftdmchan, &conEvnt->cgPtySad);
|
||||
get_prog_ind_ie(ftdmchan, &conEvnt->progInd);
|
||||
get_facility_ie(ftdmchan, &conEvnt->facilityStr);
|
||||
get_facility_ie(ftdmchan, &conEvnt->facilityStr);
|
||||
get_calling_name(ftdmchan, conEvnt);
|
||||
get_network_specific_fac(ftdmchan, &conEvnt->netFac[0]);
|
||||
|
||||
ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Incoming call: Called No:[%s] Calling No:[%s]\n", ftdmchan->caller_data.dnis.digits, ftdmchan->caller_data.cid_num.digits);
|
||||
|
||||
@@ -445,7 +446,12 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
|
||||
/* Do nothing */
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_RESET:
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n");
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring ALERT/PROCEED/PROGRESS because channel is in RESET state\n");
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_HANGUP:
|
||||
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
|
||||
/* Ignore this message as we already started the hangup process */
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring ALERT/PROCEED/PROGRESS because we are already hanging up\n");
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing ALERT/PROCEED/PROGRESS in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
@@ -945,14 +951,8 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2: /* overlap sending/receiving */
|
||||
case 2: /* overlap sending */
|
||||
switch (ftdmchan->state) {
|
||||
case FTDM_CHANNEL_STATE_COLLECT:
|
||||
/* T302 Timeout reached */
|
||||
/* Send the call to user, and see if they accept it */
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T302 Timer expired, proceeding with call\n");
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_PROCEED:
|
||||
case FTDM_CHANNEL_STATE_PROGRESS:
|
||||
case FTDM_CHANNEL_STATE_RINGING:
|
||||
@@ -1069,7 +1069,10 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event)
|
||||
case 25: /* Overlap receiving */
|
||||
switch (ftdmchan->state) {
|
||||
case FTDM_CHANNEL_STATE_COLLECT:
|
||||
/* do nothing */
|
||||
/* T302 Timeout reached */
|
||||
/* Send the call to user, and see if they accept it */
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T302 Timer expired, proceeding with call\n");
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state));
|
||||
@@ -1166,12 +1169,13 @@ static ftdm_status_t sngisdn_bring_down(ftdm_channel_t *ftdmchan)
|
||||
|
||||
void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
|
||||
{
|
||||
ftdm_signaling_status_t sigstatus;
|
||||
int16_t suId = sngisdn_event->suId;
|
||||
int16_t dChan = sngisdn_event->dChan;
|
||||
uint8_t ces = sngisdn_event->ces;
|
||||
uint8_t evntType = sngisdn_event->evntType;
|
||||
uint8_t chan_no = 0;
|
||||
Rst *rstEvnt = &sngisdn_event->event.rstEvnt;
|
||||
Rst *rstEvnt = &sngisdn_event->event.rstEvnt;
|
||||
|
||||
sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[dChan].spans[1];
|
||||
if (!signal_data) {
|
||||
@@ -1219,33 +1223,26 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan_no) { /* For a single channel */
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *curr = NULL;
|
||||
|
||||
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
|
||||
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
|
||||
ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
|
||||
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
|
||||
if (sngisdn_info->ces == ces && ftdmchan->physical_chan_id == chan_no) {
|
||||
|
||||
ftdm_span_get_sig_status(signal_data->ftdm_span, &sigstatus);
|
||||
if (sigstatus == FTDM_SIG_STATE_DOWN) {
|
||||
if (chan_no) { /* For a single channel */
|
||||
if (chan_no > ftdm_span_get_chan_count(signal_data->ftdm_span)) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Received RESTART on invalid channel:%d\n", chan_no);
|
||||
} else {
|
||||
ftdm_channel_t *ftdmchan = ftdm_span_get_channel(signal_data->ftdm_span, chan_no);
|
||||
sngisdn_bring_down(ftdmchan);
|
||||
}
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
} else { /* for all channels */
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *curr = NULL;
|
||||
} else { /* for all channels */
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *curr = NULL;
|
||||
|
||||
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
|
||||
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
|
||||
ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
|
||||
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
|
||||
if (sngisdn_info->ces == ces) {
|
||||
sngisdn_bring_down(ftdmchan);
|
||||
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
|
||||
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
|
||||
sngisdn_bring_down((ftdm_channel_t*)ftdm_iterator_current(curr));
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
}
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Processing RESTART CFM (suId:%u dChan:%d ces:%d type:%d)\n", suId, dChan, ces, evntType);
|
||||
|
||||
@@ -69,6 +69,7 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
|
||||
set_calling_subaddr(ftdmchan, &conEvnt.cgPtySad);
|
||||
set_redir_num(ftdmchan, &conEvnt.redirNmb);
|
||||
set_calling_name(ftdmchan, &conEvnt);
|
||||
set_network_specific_fac(ftdmchan, &conEvnt.netFac[0]);
|
||||
|
||||
/* set_facility_ie will overwrite Calling Name for NI-2 if user specifies custom Facility IE */
|
||||
set_facility_ie(ftdmchan, &conEvnt.facilityStr);
|
||||
@@ -304,6 +305,7 @@ void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan)
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is used to request Q.921 to initiate link establishment */
|
||||
void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
CnStEvnt cnStEvnt;
|
||||
@@ -481,6 +483,12 @@ void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len)
|
||||
sng_l1_frame_t l1_frame;
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) dchan->span->signal_data;
|
||||
|
||||
if (len > sizeof(l1_frame.data)) {
|
||||
ftdm_log_chan(dchan, FTDM_LOG_ERROR, "Received frame of %"FTDM_SIZE_FMT" bytes, exceeding max size of %"FTDM_SIZE_FMT" bytes\n",
|
||||
len, sizeof(l1_frame.data));
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&l1_frame, 0, sizeof(l1_frame));
|
||||
l1_frame.len = len;
|
||||
|
||||
|
||||
@@ -689,6 +689,17 @@ void sngisdn_rcv_q921_ind(BdMngmt *status)
|
||||
DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
|
||||
DECODE_LLD_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
|
||||
DECODE_LLD_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
|
||||
|
||||
if (FTDM_SPAN_IS_BRI(ftdmspan) && (status->t.usta.alarm.event == PROT_ST_DN)) {
|
||||
/* Q.921 link is down - This is a line where the Q.921 stops transmitting
|
||||
after the line goes idle.
|
||||
|
||||
Do not drop current calls, but set sigstatus do down so that we
|
||||
can try to re-initialize link before trying new outbound calls */
|
||||
|
||||
sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_DOWN);
|
||||
sngisdn_set_span_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n",
|
||||
|
||||
@@ -43,8 +43,21 @@ SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_progind_descr, ftdm_sngisdn_progind_descr
|
||||
SNGISDN_ENUM_NAMES(SNGISDN_PROGIND_LOC_NAMES, SNGISDN_PROGIND_LOC_STRINGS)
|
||||
SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_progind_loc, ftdm_sngisdn_progind_loc2str, ftdm_sngisdn_progind_loc_t, SNGISDN_PROGIND_LOC_NAMES, SNGISDN_PROGIND_LOC_INVALID)
|
||||
|
||||
static uint8_t get_trillium_val(ftdm2trillium_t *vals, uint8_t ftdm_val, uint8_t default_val);
|
||||
static uint8_t get_ftdm_val(ftdm2trillium_t *vals, uint8_t trillium_val, uint8_t default_val);
|
||||
SNGISDN_ENUM_NAMES(SNGISDN_NETSPECFAC_TYPE_NAMES, SNGISDN_NETSPECFAC_TYPE_STRINGS)
|
||||
SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_netspecfac_type, ftdm_sngisdn_netspecfac_type2str, ftdm_sngisdn_netspecfac_type_t, SNGISDN_NETSPECFAC_TYPE_NAMES, SNGISDN_NETSPECFAC_TYPE_INVALID)
|
||||
|
||||
SNGISDN_ENUM_NAMES(SNGISDN_NETSPECFAC_PLAN_NAMES, SNGISDN_NETSPECFAC_PLAN_STRINGS)
|
||||
SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_netspecfac_plan, ftdm_sngisdn_netspecfac_plan2str, ftdm_sngisdn_netspecfac_plan_t, SNGISDN_NETSPECFAC_PLAN_NAMES, SNGISDN_NETSPECFAC_PLAN_INVALID)
|
||||
|
||||
SNGISDN_ENUM_NAMES(SNGISDN_NETSPECFAC_SPEC_NAMES, SNGISDN_NETSPECFAC_SPEC_STRINGS)
|
||||
SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_netspecfac_spec, ftdm_sngisdn_netspecfac_spec2str, ftdm_sngisdn_netspecfac_spec_t, SNGISDN_NETSPECFAC_SPEC_NAMES, SNGISDN_NETSPECFAC_SPEC_INVALID)
|
||||
|
||||
static uint8_t _get_trillium_val(ftdm2trillium_t *vals, unsigned int num_vals, uint8_t ftdm_val, uint8_t default_val);
|
||||
static uint8_t _get_ftdm_val(ftdm2trillium_t *vals, unsigned int num_vals, uint8_t trillium_val, uint8_t default_val);
|
||||
|
||||
#define get_trillium_val(vals, ftdm_val, default_val) _get_trillium_val(vals, ftdm_array_len(vals), ftdm_val, default_val)
|
||||
#define get_ftdm_val(vals, trillium_val, default_val) _get_ftdm_val(vals, ftdm_array_len(vals), trillium_val, default_val)
|
||||
|
||||
ftdm_status_t get_calling_name_from_usr_usr(ftdm_channel_t *ftdmchan, UsrUsr *usrUsr);
|
||||
ftdm_status_t get_calling_name_from_display(ftdm_channel_t *ftdmchan, Display *display);
|
||||
ftdm_status_t get_calling_name_from_ntDisplay(ftdm_channel_t *ftdmchan, NtDisplay *display);
|
||||
@@ -71,29 +84,51 @@ ftdm2trillium_t ton_codes[] = {
|
||||
{FTDM_TON_RESERVED, IN_TON_EXT},
|
||||
};
|
||||
|
||||
static uint8_t get_trillium_val(ftdm2trillium_t *vals, uint8_t ftdm_val, uint8_t default_val)
|
||||
ftdm2trillium_t nsf_spec_codes[] = {
|
||||
{SNGISDN_NETSPECFAC_SPEC_ACCUNET, 0xe6},
|
||||
{SNGISDN_NETSPECFAC_SPEC_MEGACOM, 0xe3},
|
||||
{SNGISDN_NETSPECFAC_SPEC_MEGACOM_800, 0xe2},
|
||||
{SNGISDN_NETSPECFAC_SPEC_SDDN, 0xe1},
|
||||
{SNGISDN_NETSPECFAC_SPEC_INVALID, 0x00},
|
||||
};
|
||||
|
||||
ftdm2trillium_t nsf_type_codes[] = {
|
||||
{SNGISDN_NETSPECFAC_TYPE_USER_SPEC, 0x00},
|
||||
{SNGISDN_NETSPECFAC_TYPE_NATIONAL_NETWORK_IDENT, 0x02},
|
||||
{SNGISDN_NETSPECFAC_TYPE_INTERNATIONAL_NETWORK_IDENT, 0x03},
|
||||
{SNGISDN_NETSPECFAC_TYPE_INVALID, 0x00},
|
||||
};
|
||||
|
||||
ftdm2trillium_t nsf_plan_codes[] = {
|
||||
{SNGISDN_NETSPECFAC_PLAN_UNKNOWN, 0x00},
|
||||
{SNGISDN_NETSPECFAC_PLAN_CARRIER_IDENT, 0x01},
|
||||
{SNGISDN_NETSPECFAC_PLAN_DATA_NETWORK_IDENT, 0x03},
|
||||
{SNGISDN_NETSPECFAC_PLAN_INVALID, 0x00},
|
||||
};
|
||||
|
||||
static uint8_t _get_trillium_val(ftdm2trillium_t *vals, unsigned int num_vals, uint8_t ftdm_val, uint8_t default_val)
|
||||
{
|
||||
ftdm2trillium_t *val = vals;
|
||||
while(val++) {
|
||||
if (val->ftdm_val == ftdm_val) {
|
||||
return val->trillium_val;
|
||||
int i;
|
||||
for (i = 0; i < num_vals; i++) {
|
||||
if (vals[i].ftdm_val == ftdm_val) {
|
||||
return vals[i].trillium_val;
|
||||
}
|
||||
}
|
||||
|
||||
return default_val;
|
||||
}
|
||||
|
||||
static uint8_t _get_ftdm_val(ftdm2trillium_t *vals, unsigned int num_vals, uint8_t trillium_val, uint8_t default_val)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < num_vals; i++) {
|
||||
if (vals[i].trillium_val == trillium_val) {
|
||||
return vals[i].ftdm_val;
|
||||
}
|
||||
}
|
||||
return default_val;
|
||||
}
|
||||
|
||||
static uint8_t get_ftdm_val(ftdm2trillium_t *vals, uint8_t trillium_val, uint8_t default_val)
|
||||
{
|
||||
ftdm2trillium_t *val = vals;
|
||||
while(val++) {
|
||||
if (val->trillium_val == trillium_val) {
|
||||
return val->ftdm_val;
|
||||
}
|
||||
}
|
||||
return default_val;
|
||||
}
|
||||
|
||||
|
||||
void clear_call_data(sngisdn_chan_data_t *sngisdn_info)
|
||||
{
|
||||
uint32_t cc_id = ((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->cc_id;
|
||||
@@ -530,6 +565,29 @@ ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd)
|
||||
}
|
||||
|
||||
|
||||
ftdm_status_t get_network_specific_fac(ftdm_channel_t *ftdmchan, NetFac *netFac)
|
||||
{
|
||||
if (!netFac->eh.pres) {
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
if (netFac->netFacSpec.pres == PRSNT_NODEF) {
|
||||
char digits_string [32];
|
||||
memcpy(digits_string, (const char*)netFac->netFacSpec.val, netFac->netFacSpec.len);
|
||||
digits_string[netFac->netFacSpec.len] = '\0';
|
||||
sngisdn_add_var((sngisdn_chan_data_t*)ftdmchan->call_data, "isdn.netFac.spec", digits_string);
|
||||
}
|
||||
|
||||
if (netFac->typeNetId.pres == PRSNT_NODEF) {
|
||||
sngisdn_add_var((sngisdn_chan_data_t*)ftdmchan->call_data, "isdn.netFac.type", ftdm_sngisdn_netspecfac_type2str(get_ftdm_val(nsf_type_codes, netFac->typeNetId.val, 0x00)));
|
||||
}
|
||||
|
||||
if (netFac->netIdPlan.pres == PRSNT_NODEF) {
|
||||
sngisdn_add_var((sngisdn_chan_data_t*)ftdmchan->call_data, "isdn.netFac.plan", ftdm_sngisdn_netspecfac_type2str(get_ftdm_val(nsf_plan_codes, netFac->netIdPlan.val, 0x00)));
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
|
||||
{
|
||||
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
|
||||
@@ -537,6 +595,11 @@ ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
|
||||
if (!len) {
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
if (!strncasecmp(caller_data->cid_num.digits, "0000000000", strlen("0000000000"))) {
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
cgPtyNmb->eh.pres = PRSNT_NODEF;
|
||||
|
||||
cgPtyNmb->screenInd.pres = PRSNT_NODEF;
|
||||
@@ -900,6 +963,67 @@ ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_s
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
ftdm_status_t set_network_specific_fac(ftdm_channel_t *ftdmchan, NetFac *netFac)
|
||||
{
|
||||
const char *str = NULL;
|
||||
|
||||
str = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.netFac.spec");
|
||||
if (ftdm_strlen_zero(str)) {
|
||||
/* Network-specific facility specification is mandatory, cannot send IE
|
||||
without it */
|
||||
return FTDM_SUCCESS;
|
||||
} else {
|
||||
ftdm_sngisdn_netspecfac_spec_t spec = ftdm_str2ftdm_sngisdn_netspecfac_spec(str);
|
||||
|
||||
netFac->eh.pres = PRSNT_NODEF;
|
||||
netFac->netFacSpec.pres = PRSNT_NODEF;
|
||||
|
||||
if (spec == SNGISDN_NETSPECFAC_SPEC_INVALID) {
|
||||
int byte = 0;
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Non-standard NSF specified:%s\n", str);
|
||||
|
||||
if (sscanf(str, "%x", &byte) == 1) {
|
||||
netFac->netFacSpec.val[0] = byte & 0xFF;
|
||||
}
|
||||
|
||||
netFac->netFacSpec.len = 1;
|
||||
} else {
|
||||
/* User is using one of the pre-specified NSF's */
|
||||
netFac->netFacSpec.val[0] = get_trillium_val(nsf_spec_codes, spec, 0x00);
|
||||
netFac->netFacSpec.len = 1;
|
||||
}
|
||||
}
|
||||
|
||||
netFac->lenNetId.pres = PRSNT_NODEF;
|
||||
netFac->lenNetId.val = 0;
|
||||
|
||||
str = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.netFac.type");
|
||||
if (!ftdm_strlen_zero(str)) {
|
||||
netFac->typeNetId.pres = PRSNT_NODEF;
|
||||
netFac->typeNetId.val = ftdm_str2ftdm_sngisdn_netspecfac_type(str);
|
||||
}
|
||||
|
||||
str = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.netFac.plan");
|
||||
if (!ftdm_strlen_zero(str)) {
|
||||
netFac->netIdPlan.pres = PRSNT_NODEF;
|
||||
netFac->netIdPlan.val = ftdm_str2ftdm_sngisdn_netspecfac_plan(str);
|
||||
}
|
||||
|
||||
if (netFac->netIdPlan.pres == PRSNT_NODEF || netFac->typeNetId.pres == PRSNT_NODEF) {
|
||||
netFac->lenNetId.val++;
|
||||
}
|
||||
|
||||
str = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.netFac.ident");
|
||||
if (!ftdm_strlen_zero(str)) {
|
||||
netFac->lenNetId.val++;
|
||||
|
||||
netFac->netId.pres = PRSNT_NODEF;
|
||||
memcpy(netFac->netId.val, str, strlen(str));
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
ftdm_status_t set_user_to_user_ie(ftdm_channel_t *ftdmchan, UsrUsr *usrUsr)
|
||||
{
|
||||
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
|
||||
|
||||
@@ -112,7 +112,7 @@ uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi)
|
||||
|
||||
void sngisdn_trace_interpreted_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
char *data_str = ftdm_calloc(1,200); /* TODO Find a proper size */
|
||||
char *data_str = ftdm_calloc(1,500); /* TODO Find a proper size */
|
||||
sngisdn_decode_q921(data_str, data, data_len);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "[SNGISDN Q921] %s FRAME %s:\n%s\n", signal_data->ftdm_span->name, ftdm_trace_dir2str(dir), data_str);
|
||||
ftdm_safe_free(data_str);
|
||||
@@ -771,7 +771,7 @@ uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset
|
||||
default:
|
||||
{
|
||||
*str_len += sprintf(&str[*str_len], "Undecoded");
|
||||
print_hex_dump((char*)str, str_len, data, index_start, index_end);
|
||||
print_hex_dump((char*)str, str_len, data, index_start, index_end + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,42 @@ typedef enum {
|
||||
#define SNGISDN_PROGIND_LOC_STRINGS "user", "private-net-local-user", "public-net-local-user", "transit-network", "public-net-remote-user", "private-net-remote-user", "beyond-interworking", "invalid"
|
||||
SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_progind_loc, ftdm_sngisdn_progind_loc2str, ftdm_sngisdn_progind_loc_t);
|
||||
|
||||
typedef enum {
|
||||
/* User Specified */
|
||||
SNGISDN_NETSPECFAC_TYPE_USER_SPEC,
|
||||
/* National network identification */
|
||||
SNGISDN_NETSPECFAC_TYPE_NATIONAL_NETWORK_IDENT,
|
||||
/* International network identification */
|
||||
SNGISDN_NETSPECFAC_TYPE_INTERNATIONAL_NETWORK_IDENT,
|
||||
/* Invalid */
|
||||
SNGISDN_NETSPECFAC_TYPE_INVALID,
|
||||
} ftdm_sngisdn_netspecfac_type_t;
|
||||
#define SNGISDN_NETSPECFAC_TYPE_STRINGS "user-specified", "national-network-identification", "national-network-identification", "invalid"
|
||||
SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_netspecfac_type, ftdm_sngisdn_netspecfac_type2str, ftdm_sngisdn_netspecfac_type_t);
|
||||
|
||||
typedef enum {
|
||||
/* Unknown */
|
||||
SNGISDN_NETSPECFAC_PLAN_UNKNOWN,
|
||||
/* Carrier Identification Code */
|
||||
SNGISDN_NETSPECFAC_PLAN_CARRIER_IDENT,
|
||||
/* Data network identification code */
|
||||
SNGISDN_NETSPECFAC_PLAN_DATA_NETWORK_IDENT,
|
||||
/* Invalid */
|
||||
SNGISDN_NETSPECFAC_PLAN_INVALID,
|
||||
} ftdm_sngisdn_netspecfac_plan_t;
|
||||
#define SNGISDN_NETSPECFAC_PLAN_STRINGS "unknown", "carrier-identification", "data-network-identification", "invalid"
|
||||
SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_netspecfac_plan, ftdm_sngisdn_netspecfac_plan2str, ftdm_sngisdn_netspecfac_plan_t);
|
||||
|
||||
typedef enum {
|
||||
/* Unknown */
|
||||
SNGISDN_NETSPECFAC_SPEC_ACCUNET,
|
||||
SNGISDN_NETSPECFAC_SPEC_MEGACOM,
|
||||
SNGISDN_NETSPECFAC_SPEC_MEGACOM_800,
|
||||
SNGISDN_NETSPECFAC_SPEC_SDDN,
|
||||
SNGISDN_NETSPECFAC_SPEC_INVALID,
|
||||
} ftdm_sngisdn_netspecfac_spec_t;
|
||||
#define SNGISDN_NETSPECFAC_SPEC_STRINGS "accunet", "megacom", "megacom-800", "sddn", "invalid"
|
||||
SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_netspecfac_spec, ftdm_sngisdn_netspecfac_spec2str, ftdm_sngisdn_netspecfac_spec_t);
|
||||
|
||||
#endif /* __FTMOD_SANGOMA_ISDN_USER_H__*/
|
||||
|
||||
|
||||
@@ -233,11 +233,11 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa
|
||||
|
||||
if (!strcasecmp(var, "dialplan")) {
|
||||
/**********************************************************************/
|
||||
/* do i give a shit about this??? */
|
||||
/* don't care for now */
|
||||
/**********************************************************************/
|
||||
} else if (!strcasecmp(var, "context")) {
|
||||
/**********************************************************************/
|
||||
/* do i give a shit about this??? */
|
||||
/* don't care for now */
|
||||
/**********************************************************************/
|
||||
} else if (!strcasecmp(var, "ccSpanId")) {
|
||||
/**********************************************************************/
|
||||
|
||||
@@ -471,6 +471,7 @@ static FIO_CONFIGURE_FUNCTION(wanpipe_configure)
|
||||
wp_globals.ring_off_ms = num;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
@@ -1010,7 +1011,7 @@ static FIO_READ_FUNCTION(wanpipe_read)
|
||||
|
||||
memset(&hdrframe, 0, sizeof(hdrframe));
|
||||
rx_len = sangoma_readmsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen, 0);
|
||||
*datalen = rx_len;
|
||||
*datalen = 0;
|
||||
|
||||
if (rx_len == 0) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Read 0 bytes\n");
|
||||
@@ -1027,6 +1028,7 @@ static FIO_READ_FUNCTION(wanpipe_read)
|
||||
#endif
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
*datalen = rx_len;
|
||||
|
||||
if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS)) {
|
||||
wanpipe_read_stats(ftdmchan, &hdrframe);
|
||||
@@ -1468,13 +1470,29 @@ static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fc
|
||||
|
||||
if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
|
||||
ftdm_set_flag(fchan, FTDM_CHANNEL_MUTE);
|
||||
if (fchan->dtmfdetect.duration_ms) {
|
||||
fchan->dtmfdetect.start_time = ftdm_current_time_in_ms();
|
||||
} else if (fchan->dtmfdetect.trigger_on_start) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
|
||||
ftdm_channel_queue_dtmf(fchan, tmp_dtmf);
|
||||
}
|
||||
}
|
||||
|
||||
if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
|
||||
ftdm_clear_flag(fchan, FTDM_CHANNEL_MUTE);
|
||||
if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
|
||||
ftdm_channel_queue_dtmf(fchan, tmp_dtmf);
|
||||
if (fchan->dtmfdetect.duration_ms) {
|
||||
ftdm_time_t diff = ftdm_current_time_in_ms() - fchan->dtmfdetect.start_time;
|
||||
if (diff > fchan->dtmfdetect.duration_ms) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c (duration:%d min:%d)\n", tmp_dtmf[0], diff, fchan->dtmfdetect.duration_ms);
|
||||
ftdm_channel_queue_dtmf(fchan, tmp_dtmf);
|
||||
} else {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c (duration:%d min:%d)\n", tmp_dtmf[0], diff, fchan->dtmfdetect.duration_ms);
|
||||
}
|
||||
} else if (!fchan->dtmfdetect.trigger_on_start) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
|
||||
ftdm_channel_queue_dtmf(fchan, tmp_dtmf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
*
|
||||
* Moises Silva <moy@sangoma.com>
|
||||
* W McRoberts <fs@whmcr.com>
|
||||
* Puskás Zsolt <errotan@gmail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -877,10 +878,13 @@ static FIO_COMMAND_FUNCTION(zt_command)
|
||||
static FIO_GET_ALARMS_FUNCTION(zt_get_alarms)
|
||||
{
|
||||
struct zt_spaninfo info;
|
||||
zt_params_t params;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.span_no = ftdmchan->physical_span_id;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
if (ioctl(CONTROL_FD, codes.SPANSTAT, &info)) {
|
||||
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
|
||||
snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
|
||||
@@ -889,6 +893,27 @@ static FIO_GET_ALARMS_FUNCTION(zt_get_alarms)
|
||||
|
||||
ftdmchan->alarm_flags = info.alarms;
|
||||
|
||||
/* get channel alarms if span has no alarms */
|
||||
if (info.alarms == FTDM_ALARM_NONE) {
|
||||
if (ioctl(ftdmchan->sockfd, codes.GET_PARAMS, ¶ms)) {
|
||||
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
|
||||
snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
if (params.chan_alarms > 0) {
|
||||
if (params.chan_alarms == DAHDI_ALARM_YELLOW) {
|
||||
ftdmchan->alarm_flags = FTDM_ALARM_YELLOW;
|
||||
}
|
||||
else if (params.chan_alarms == DAHDI_ALARM_BLUE) {
|
||||
ftdmchan->alarm_flags = FTDM_ALARM_BLUE;
|
||||
}
|
||||
else {
|
||||
ftdmchan->alarm_flags = FTDM_ALARM_RED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1027,12 +1052,14 @@ static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan,
|
||||
switch(zt_event_id) {
|
||||
case ZT_EVENT_RINGEROFF:
|
||||
{
|
||||
return FTDM_FAIL;
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "ZT RINGER OFF\n");
|
||||
*event_id = FTDM_OOB_NOOP;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGERON:
|
||||
{
|
||||
return FTDM_FAIL;
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "ZT RINGER ON\n");
|
||||
*event_id = FTDM_OOB_NOOP;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGBEGIN:
|
||||
@@ -1151,7 +1178,7 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event)
|
||||
|
||||
/* the core already locked the channel for us, so it's safe to call zt_channel_process_event() here */
|
||||
if ((zt_channel_process_event(ftdmchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to process DAHDI event %d from channel\n", zt_event_id);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
@@ -1185,7 +1212,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
|
||||
|
||||
ftdm_channel_lock(fchan);
|
||||
if ((zt_channel_process_event(fchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to process DAHDI event %d from channel\n", zt_event_id);
|
||||
ftdm_channel_unlock(fchan);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
@@ -1350,6 +1377,7 @@ static FIO_IO_LOAD_FUNCTION(zt_init)
|
||||
zt_interface.write = zt_write;
|
||||
zt_interface.poll_event = zt_poll_event;
|
||||
zt_interface.next_event = zt_next_event;
|
||||
zt_interface.channel_next_event = zt_channel_next_event;
|
||||
zt_interface.channel_destroy = zt_channel_destroy;
|
||||
zt_interface.get_alarms = zt_get_alarms;
|
||||
*fio = &zt_interface;
|
||||
|
||||
@@ -339,6 +339,10 @@ ZT_ABIT = 8
|
||||
#define DAHDI_HDLCRAWMODE _IOW (DAHDI_CODE, 36, int) /* Set a clear channel into HDLC w/out FCS checking/calculation mode */
|
||||
#define DAHDI_HDLCFCSMODE _IOW (DAHDI_CODE, 37, int) /* Set a clear channel into HDLC w/ FCS mode */
|
||||
|
||||
/* Dahdi channel alarms */
|
||||
#define DAHDI_ALARM_YELLOW (1 << 2) /* Yellow Alarm */
|
||||
#define DAHDI_ALARM_BLUE (1 << 4) /* Blue Alarm */
|
||||
|
||||
/* Specify a channel on /dev/dahdi/chan -- must be done before any other ioctl's and is only valid on /dev/dahdi/chan */
|
||||
#define DAHDI_SPECIFY _IOW (DAHDI_CODE, 38, int)
|
||||
|
||||
|
||||
@@ -484,7 +484,7 @@ typedef enum {
|
||||
FTDM_STR2ENUM_P(ftdm_str2ftdm_trunk_type, ftdm_trunk_type2str, ftdm_trunk_type_t)
|
||||
|
||||
/*! \brief Basic channel configuration provided to ftdm_configure_span_channels */
|
||||
typedef struct ftdm_channel_config {
|
||||
typedef struct ftdm_channel_config {
|
||||
char name[FTDM_MAX_NAME_STR_SZ];
|
||||
char number[FTDM_MAX_NUMBER_STR_SZ];
|
||||
char group_name[FTDM_MAX_NAME_STR_SZ];
|
||||
@@ -492,6 +492,8 @@ typedef struct ftdm_channel_config {
|
||||
float rxgain;
|
||||
float txgain;
|
||||
uint8_t debugdtmf;
|
||||
uint8_t dtmf_on_start;
|
||||
uint32_t dtmfdetect_ms;
|
||||
uint8_t iostats;
|
||||
} ftdm_channel_config_t;
|
||||
|
||||
|
||||
@@ -384,6 +384,13 @@ typedef struct {
|
||||
ftdm_mutex_t *mutex;
|
||||
} ftdm_dtmf_debug_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t duration_ms;
|
||||
ftdm_time_t start_time;
|
||||
/* If set to 1, we will send DTMF event the the tone starts, instead of waiting for end */
|
||||
uint8_t trigger_on_start;
|
||||
} ftdm_dtmf_detect_t;
|
||||
|
||||
/* 2^8 table size, one for each byte (sample) value */
|
||||
#define FTDM_GAINS_TABLE_SIZE 256
|
||||
struct ftdm_channel {
|
||||
@@ -463,6 +470,7 @@ struct ftdm_channel {
|
||||
ftdm_timer_id_t hangup_timer;
|
||||
ftdm_channel_iostats_t iostats;
|
||||
ftdm_dtmf_debug_t dtmfdbg;
|
||||
ftdm_dtmf_detect_t dtmfdetect;
|
||||
ftdm_io_dump_t rxdump;
|
||||
ftdm_io_dump_t txdump;
|
||||
ftdm_interrupt_t *state_completed_interrupt; /*!< Notify when a state change is completed */
|
||||
|
||||
@@ -10,7 +10,7 @@ static ftdm_channel_indication_t indication = FTDM_CHANNEL_INDICATE_NONE;
|
||||
static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
|
||||
{
|
||||
int chanid = ftdm_channel_get_ph_id(sigmsg->channel);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel %d\n", ftdm_signal_event2str(sigmsg->event_id), chanid);
|
||||
switch (sigmsg->event_id) {
|
||||
case FTDM_SIGEVENT_START:
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user