mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-28 14:14:16 +00:00
dyna won't you blow your horn
git-svn-id: http://svn.openzap.org/svn/openzap/trunk@517 a93c3328-9c30-0410-af19-c9cd2b2d52af
This commit is contained in:
1 parent
2973d68f37
commit
bc1ccab19c
34 files changed
+706
-354
No files matched your search
@@ -0,0 +1,856 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "openzap.h"
|
||||
#include "zap_analog.h"
|
||||
|
||||
#ifndef localtime_r
|
||||
struct tm * localtime_r(const time_t *clock, struct tm *result);
|
||||
#endif
|
||||
|
||||
static void *zap_analog_channel_run(zap_thread_t *me, void *obj);
|
||||
|
||||
static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxo_outgoing_call)
|
||||
{
|
||||
if (!zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
|
||||
zap_channel_clear_needed_tones(zchan);
|
||||
zap_channel_clear_detected_tones(zchan);
|
||||
|
||||
zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
|
||||
zap_channel_command(zchan, ZAP_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
|
||||
zchan->needed_tones[ZAP_TONEMAP_DIAL] = 1;
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
|
||||
zap_thread_create_detached(zap_analog_channel_run, zchan);
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
|
||||
{
|
||||
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_CALLWAITING);
|
||||
} else {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_GENRING);
|
||||
zap_thread_create_detached(zap_analog_channel_run, zchan);
|
||||
}
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static zap_status_t zap_analog_start(zap_span_t *span)
|
||||
{
|
||||
zap_analog_data_t *analog_data = span->signal_data;
|
||||
zap_set_flag(analog_data, ZAP_ANALOG_RUNNING);
|
||||
return zap_thread_create_detached(zap_analog_run, span);
|
||||
}
|
||||
|
||||
static ZIO_SIG_CONFIGURE_FUNCTION(zap_analog_configure_span)
|
||||
//zap_status_t zap_analog_configure_span(zap_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, zio_signal_cb_t sig_cb)
|
||||
{
|
||||
zap_analog_data_t *analog_data;
|
||||
char *tonemap = "us";
|
||||
uint32_t digit_timeout = 10;
|
||||
uint32_t max_dialstr = 11;
|
||||
char *var, *val;
|
||||
int *intval;
|
||||
|
||||
assert(sig_cb != NULL);
|
||||
|
||||
if (span->signal_type) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
if (digit_timeout < 2000 || digit_timeout > 10000) {
|
||||
digit_timeout = 2000;
|
||||
}
|
||||
|
||||
if (max_dialstr < 2 || max_dialstr > 20) {
|
||||
max_dialstr = 11;
|
||||
}
|
||||
|
||||
analog_data = malloc(sizeof(*analog_data));
|
||||
memset(analog_data, 0, sizeof(*analog_data));
|
||||
assert(analog_data != NULL);
|
||||
|
||||
|
||||
while(var = va_arg(ap, char *)) {
|
||||
if (!strcasecmp(var, "tonemap")) {
|
||||
if (!(val = va_arg(ap, char *))) {
|
||||
break;
|
||||
}
|
||||
tonemap = val;
|
||||
} else if (!strcasecmp(var, "digit_timeout")) {
|
||||
if (!(intval = va_arg(ap, int *))) {
|
||||
break;
|
||||
}
|
||||
digit_timeout = *intval;
|
||||
} else if (!strcasecmp(var, "max_dialstr")) {
|
||||
if (!(intval = va_arg(ap, int *))) {
|
||||
break;
|
||||
}
|
||||
max_dialstr = *intval;
|
||||
}
|
||||
}
|
||||
|
||||
span->start = zap_analog_start;
|
||||
analog_data->digit_timeout = digit_timeout;
|
||||
analog_data->max_dialstr = max_dialstr;
|
||||
analog_data->sig_cb = sig_cb;
|
||||
span->signal_type = ZAP_SIGTYPE_ANALOG;
|
||||
span->signal_data = analog_data;
|
||||
span->outgoing_call = span->trunk_type == ZAP_TRUNK_FXS ? analog_fxs_outgoing_call : analog_fxo_outgoing_call;
|
||||
zap_span_load_tones(span, tonemap);
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
|
||||
{
|
||||
zap_buffer_t *dt_buffer = ts->user_data;
|
||||
int wrote;
|
||||
|
||||
if (!dt_buffer) {
|
||||
return -1;
|
||||
}
|
||||
wrote = teletone_mux_tones(ts, map);
|
||||
zap_buffer_write(dt_buffer, ts->buffer, wrote * 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_caller_id(zap_channel_t *zchan)
|
||||
{
|
||||
zap_fsk_data_state_t fsk_data;
|
||||
uint8_t databuf[1024] = "";
|
||||
char time_str[9];
|
||||
struct tm tm;
|
||||
time_t now;
|
||||
zap_mdmf_type_t mt = MDMF_INVALID;
|
||||
|
||||
time(&now);
|
||||
#ifdef WIN32
|
||||
_tzset();
|
||||
_localtime64_s(&tm, &now);
|
||||
#else
|
||||
localtime_r(&now, &tm);
|
||||
#endif
|
||||
strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
|
||||
|
||||
zap_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
|
||||
zap_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *) time_str, 8);
|
||||
|
||||
if (zap_strlen_zero(zchan->caller_data.cid_num.digits)) {
|
||||
mt = MDMF_NO_NUM;
|
||||
zap_set_string(zchan->caller_data.cid_num.digits, "O");
|
||||
} else if (!strcasecmp(zchan->caller_data.cid_num.digits, "P") || !strcasecmp(zchan->caller_data.cid_num.digits, "O")) {
|
||||
mt = MDMF_NO_NUM;
|
||||
} else {
|
||||
mt = MDMF_PHONE_NUM;
|
||||
}
|
||||
zap_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) zchan->caller_data.cid_num.digits, (uint8_t)strlen(zchan->caller_data.cid_num.digits));
|
||||
|
||||
if (zap_strlen_zero(zchan->caller_data.cid_name)) {
|
||||
mt = MDMF_NO_NAME;
|
||||
zap_set_string(zchan->caller_data.cid_name, "O");
|
||||
} else if (!strcasecmp(zchan->caller_data.cid_name, "P") || !strcasecmp(zchan->caller_data.cid_name, "O")) {
|
||||
mt = MDMF_NO_NAME;
|
||||
} else {
|
||||
mt = MDMF_PHONE_NAME;
|
||||
}
|
||||
zap_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) zchan->caller_data.cid_name, (uint8_t)strlen(zchan->caller_data.cid_name));
|
||||
|
||||
zap_fsk_data_add_checksum(&fsk_data);
|
||||
zap_channel_send_fsk_data(zchan, &fsk_data, -14);
|
||||
}
|
||||
|
||||
static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
|
||||
{
|
||||
zap_channel_t *zchan = (zap_channel_t *) obj;
|
||||
zap_buffer_t *dt_buffer = NULL;
|
||||
teletone_generation_session_t ts;
|
||||
uint8_t frame[1024];
|
||||
zap_size_t len, rlen;
|
||||
zap_tone_type_t tt = ZAP_TONE_DTMF;
|
||||
char dtmf[128] = "";
|
||||
zap_size_t dtmf_offset = 0;
|
||||
zap_analog_data_t *analog_data = zchan->span->signal_data;
|
||||
zap_channel_t *closed_chan;
|
||||
uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
|
||||
zap_sigmsg_t sig;
|
||||
zap_status_t status;
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n");
|
||||
|
||||
ts.buffer = NULL;
|
||||
|
||||
if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (zap_buffer_create(&dt_buffer, 1024, 3192, 0) != ZAP_SUCCESS) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "memory error!");
|
||||
zap_log(ZAP_LOG_ERROR, "MEM ERROR\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (zap_channel_command(zchan, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "error initilizing tone detector!");
|
||||
zap_log(ZAP_LOG_ERROR, "TONE ERROR\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
zap_set_flag_locked(zchan, ZAP_CHANNEL_INTHREAD);
|
||||
teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
|
||||
ts.rate = 8000;
|
||||
#if 0
|
||||
ts.debug = 1;
|
||||
ts.debug_stream = stdout;
|
||||
#endif
|
||||
zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval);
|
||||
zap_buffer_set_loops(dt_buffer, -1);
|
||||
|
||||
memset(&sig, 0, sizeof(sig));
|
||||
sig.chan_id = zchan->chan_id;
|
||||
sig.span_id = zchan->span_id;
|
||||
sig.channel = zchan;
|
||||
|
||||
assert(interval != 0);
|
||||
|
||||
while (zap_running() && zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
|
||||
zap_wait_flag_t flags = ZAP_READ;
|
||||
zap_size_t dlen = 0;
|
||||
|
||||
len = sizeof(frame);
|
||||
|
||||
elapsed += interval;
|
||||
state_counter += interval;
|
||||
|
||||
if (!zap_test_flag(zchan, ZAP_CHANNEL_STATE_CHANGE)) {
|
||||
switch(zchan->state) {
|
||||
case ZAP_CHANNEL_STATE_GET_CALLERID:
|
||||
{
|
||||
if (state_counter > 5000 || !zap_test_flag(zchan, ZAP_CHANNEL_CALLERID_DETECT)) {
|
||||
zap_channel_command(zchan, ZAP_COMMAND_DISABLE_CALLERID_DETECT, NULL);
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DIALING:
|
||||
{
|
||||
if (state_counter > dial_timeout) {
|
||||
if (zchan->needed_tones[ZAP_TONEMAP_DIAL]) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
} else {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_GENRING:
|
||||
{
|
||||
if (state_counter > 60000) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
|
||||
} else if (!zchan->fsk_buffer || !zap_buffer_inuse(zchan->fsk_buffer)) {
|
||||
zap_sleep(interval);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DIALTONE:
|
||||
{
|
||||
if (!zap_test_flag(zchan, ZAP_CHANNEL_HOLD) && state_counter > 10000) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_BUSY:
|
||||
{
|
||||
if (state_counter > 20000) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_ATTN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_ATTN:
|
||||
{
|
||||
if (state_counter > 20000) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_HANGUP:
|
||||
{
|
||||
if (state_counter > 500) {
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
|
||||
zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
|
||||
}
|
||||
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) &&
|
||||
(zchan->last_state == ZAP_CHANNEL_STATE_RING || zchan->last_state == ZAP_CHANNEL_STATE_DIALTONE
|
||||
|| zchan->last_state >= ZAP_CHANNEL_STATE_IDLE)) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
} else {
|
||||
zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CLEARING;
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_CALLWAITING:
|
||||
{
|
||||
int done = 0;
|
||||
|
||||
if (zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] == 1) {
|
||||
send_caller_id(zchan);
|
||||
zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
|
||||
} else if (state_counter > 600 && !zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]) {
|
||||
send_caller_id(zchan);
|
||||
zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
|
||||
} else if (state_counter > 1000 && !zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]) {
|
||||
done = 1;
|
||||
} else if (state_counter > 10000) {
|
||||
if (zchan->fsk_buffer) {
|
||||
zap_buffer_zero(zchan->fsk_buffer);
|
||||
} else {
|
||||
zap_buffer_create(&zchan->fsk_buffer, 128, 128, 0);
|
||||
}
|
||||
|
||||
ts.user_data = zchan->fsk_buffer;
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_CALLWAITING_SAS]);
|
||||
ts.user_data = dt_buffer;
|
||||
done = 1;
|
||||
}
|
||||
|
||||
if (done) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
|
||||
zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
|
||||
zap_clear_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
|
||||
zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
|
||||
}
|
||||
}
|
||||
case ZAP_CHANNEL_STATE_UP:
|
||||
case ZAP_CHANNEL_STATE_IDLE:
|
||||
{
|
||||
zap_sleep(interval);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
|
||||
zap_clear_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
|
||||
zap_channel_complete_state(zchan);
|
||||
indicate = 0;
|
||||
state_counter = 0;
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "Executing state handler on %d:%d for %s\n",
|
||||
zchan->span_id, zchan->chan_id,
|
||||
zap_channel_state2str(zchan->state));
|
||||
switch(zchan->state) {
|
||||
case ZAP_CHANNEL_STATE_UP:
|
||||
{
|
||||
zap_channel_use(zchan);
|
||||
zap_channel_clear_needed_tones(zchan);
|
||||
zap_channel_flush_dtmf(zchan);
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_FXO && !zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
|
||||
zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
|
||||
}
|
||||
|
||||
if (zchan->fsk_buffer && zap_buffer_inuse(zchan->fsk_buffer)) {
|
||||
zap_log(ZAP_LOG_DEBUG, "Cancel FSK transmit due to early answer.\n");
|
||||
zap_buffer_zero(zchan->fsk_buffer);
|
||||
}
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_FXS && zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
|
||||
zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
|
||||
}
|
||||
|
||||
if (zchan->token_count == 1) {
|
||||
zap_clear_flag(zchan, ZAP_CHANNEL_HOLD);
|
||||
}
|
||||
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_HOLD)) {
|
||||
zap_clear_flag(zchan, ZAP_CHANNEL_HOLD);
|
||||
sig.event_id = ZAP_SIGEVENT_ADD_CALL;
|
||||
} else {
|
||||
sig.event_id = ZAP_SIGEVENT_UP;
|
||||
}
|
||||
|
||||
analog_data->sig_cb(&sig);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DIALING:
|
||||
{
|
||||
zap_channel_use(zchan);
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_IDLE:
|
||||
{
|
||||
zap_channel_use(zchan);
|
||||
sig.event_id = ZAP_SIGEVENT_START;
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_FXO) {
|
||||
zap_set_string(zchan->caller_data.dnis.digits, zchan->chan_number);
|
||||
} else {
|
||||
zap_set_string(zchan->caller_data.dnis.digits, dtmf);
|
||||
}
|
||||
|
||||
analog_data->sig_cb(&sig);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
sig.event_id = ZAP_SIGEVENT_STOP;
|
||||
analog_data->sig_cb(&sig);
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DIALTONE:
|
||||
{
|
||||
memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
|
||||
*dtmf = '\0';
|
||||
dtmf_offset = 0;
|
||||
zap_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_DIAL]);
|
||||
indicate = 1;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_CALLWAITING:
|
||||
{
|
||||
zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
|
||||
if (zchan->fsk_buffer) {
|
||||
zap_buffer_zero(zchan->fsk_buffer);
|
||||
} else {
|
||||
zap_buffer_create(&zchan->fsk_buffer, 128, 128, 0);
|
||||
}
|
||||
|
||||
ts.user_data = zchan->fsk_buffer;
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_CALLWAITING_SAS]);
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_CALLWAITING_CAS]);
|
||||
ts.user_data = dt_buffer;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_GENRING:
|
||||
{
|
||||
send_caller_id(zchan);
|
||||
zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_ON, NULL);
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_GET_CALLERID:
|
||||
{
|
||||
memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
|
||||
zap_channel_command(zchan, ZAP_COMMAND_ENABLE_CALLERID_DETECT, NULL);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_RING:
|
||||
{
|
||||
zap_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_RING]);
|
||||
indicate = 1;
|
||||
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_BUSY:
|
||||
{
|
||||
zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CIRCUIT_CONGESTION;
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
|
||||
zap_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_BUSY]);
|
||||
indicate = 1;
|
||||
} else {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_ATTN:
|
||||
{
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
|
||||
zap_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_ATTN]);
|
||||
indicate = 1;
|
||||
} else {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE || zchan->state == ZAP_CHANNEL_STATE_COLLECT) {
|
||||
if ((dlen = zap_channel_dequeue_dtmf(zchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
|
||||
|
||||
if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_COLLECT);
|
||||
collecting = 1;
|
||||
}
|
||||
dtmf_offset = strlen(dtmf);
|
||||
last_digit = elapsed;
|
||||
sig.event_id = ZAP_SIGEVENT_COLLECTED_DIGIT;
|
||||
sig.raw_data = dtmf;
|
||||
if (analog_data->sig_cb(&sig) == ZAP_BREAK) {
|
||||
collecting = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) > analog_data->max_dialstr))) {
|
||||
zap_log(ZAP_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
|
||||
last_digit = 0;
|
||||
collecting = 0;
|
||||
}
|
||||
|
||||
if (zap_channel_wait(zchan, &flags, interval * 2) != ZAP_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(flags & ZAP_READ)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zap_channel_read(zchan, frame, &len) != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "READ ERROR [%s]\n", zchan->last_error);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_FXO && zchan->detected_tones[0]) {
|
||||
zap_sigmsg_t sig;
|
||||
int i;
|
||||
memset(&sig, 0, sizeof(sig));
|
||||
sig.chan_id = zchan->chan_id;
|
||||
sig.span_id = zchan->span_id;
|
||||
sig.channel = zchan;
|
||||
sig.event_id = ZAP_SIGEVENT_TONE_DETECTED;
|
||||
|
||||
for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
|
||||
if (zchan->detected_tones[i]) {
|
||||
zap_log(ZAP_LOG_DEBUG, "Detected tone %s on %d:%d\n", zap_tonemap2str(i), zchan->span_id, zchan->chan_id);
|
||||
sig.raw_data = &i;
|
||||
if (analog_data->sig_cb) {
|
||||
analog_data->sig_cb(&sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zchan->detected_tones[ZAP_TONEMAP_BUSY] ||
|
||||
zchan->detected_tones[ZAP_TONEMAP_FAIL1] ||
|
||||
zchan->detected_tones[ZAP_TONEMAP_FAIL2] ||
|
||||
zchan->detected_tones[ZAP_TONEMAP_FAIL3] ||
|
||||
zchan->detected_tones[ZAP_TONEMAP_ATTN]
|
||||
) {
|
||||
zap_log(ZAP_LOG_ERROR, "Failure indication detected!\n");
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
} else if (zchan->detected_tones[ZAP_TONEMAP_DIAL]) {
|
||||
if (zap_strlen_zero(zchan->caller_data.ani.digits)) {
|
||||
zap_log(ZAP_LOG_ERROR, "No Digits to send!\n");
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
} else {
|
||||
if (zap_channel_command(zchan, ZAP_COMMAND_SEND_DTMF, zchan->caller_data.ani.digits) != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "Send Digits Failed [%s]\n", zchan->last_error);
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
} else {
|
||||
state_counter = 0;
|
||||
zchan->needed_tones[ZAP_TONEMAP_RING] = 1;
|
||||
zchan->needed_tones[ZAP_TONEMAP_BUSY] = 1;
|
||||
zchan->needed_tones[ZAP_TONEMAP_FAIL1] = 1;
|
||||
zchan->needed_tones[ZAP_TONEMAP_FAIL2] = 1;
|
||||
zchan->needed_tones[ZAP_TONEMAP_FAIL3] = 1;
|
||||
dial_timeout = ((zchan->dtmf_on + zchan->dtmf_off) * strlen(zchan->caller_data.ani.digits)) + 2000;
|
||||
}
|
||||
}
|
||||
} else if (zchan->detected_tones[ZAP_TONEMAP_RING]) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
|
||||
}
|
||||
|
||||
zap_channel_clear_detected_tones(zchan);
|
||||
}
|
||||
|
||||
if ((zchan->dtmf_buffer && zap_buffer_inuse(zchan->dtmf_buffer)) || (zchan->fsk_buffer && zap_buffer_inuse(zchan->fsk_buffer))) {
|
||||
rlen = len;
|
||||
memset(frame, 0, len);
|
||||
zap_channel_write(zchan, frame, sizeof(frame), &rlen);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!indicate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_FXO && !zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
|
||||
zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
|
||||
}
|
||||
|
||||
if (zchan->effective_codec != ZAP_CODEC_SLIN) {
|
||||
len *= 2;
|
||||
}
|
||||
|
||||
rlen = zap_buffer_read_loop(dt_buffer, frame, len);
|
||||
|
||||
if (zchan->effective_codec != ZAP_CODEC_SLIN) {
|
||||
zio_codec_t codec_func = NULL;
|
||||
|
||||
if (zchan->native_codec == ZAP_CODEC_ULAW) {
|
||||
codec_func = zio_slin2ulaw;
|
||||
} else if (zchan->native_codec == ZAP_CODEC_ALAW) {
|
||||
codec_func = zio_slin2alaw;
|
||||
}
|
||||
|
||||
if (codec_func) {
|
||||
status = codec_func(frame, sizeof(frame), &rlen);
|
||||
} else {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
zap_channel_write(zchan, frame, sizeof(frame), &rlen);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_FXO && zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
|
||||
zap_channel_command(zchan, ZAP_COMMAND_ONHOOK, NULL);
|
||||
}
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_FXS && zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
|
||||
zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
|
||||
}
|
||||
|
||||
|
||||
closed_chan = zchan;
|
||||
zap_channel_close(&zchan);
|
||||
|
||||
zap_channel_command(closed_chan, ZAP_COMMAND_SET_NATIVE_CODEC, NULL);
|
||||
|
||||
if (ts.buffer) {
|
||||
teletone_destroy_session(&ts);
|
||||
}
|
||||
|
||||
if (dt_buffer) {
|
||||
zap_buffer_destroy(&dt_buffer);
|
||||
}
|
||||
|
||||
zap_clear_flag(closed_chan, ZAP_CHANNEL_INTHREAD);
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "ANALOG CHANNEL thread ended.\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *event)
|
||||
{
|
||||
zap_sigmsg_t sig;
|
||||
zap_analog_data_t *analog_data = event->channel->span->signal_data;
|
||||
int locked = 0;
|
||||
|
||||
memset(&sig, 0, sizeof(sig));
|
||||
sig.chan_id = event->channel->chan_id;
|
||||
sig.span_id = event->channel->span_id;
|
||||
sig.channel = event->channel;
|
||||
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n",
|
||||
zap_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, zap_channel_state2str(event->channel->state));
|
||||
|
||||
zap_mutex_lock(event->channel->mutex);
|
||||
locked++;
|
||||
|
||||
switch(event->enum_id) {
|
||||
case ZAP_OOB_RING_START:
|
||||
{
|
||||
if (!event->channel->ring_count && (event->channel->state == ZAP_CHANNEL_STATE_DOWN && !zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD))) {
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_GET_CALLERID);
|
||||
event->channel->ring_count = 1;
|
||||
zap_mutex_unlock(event->channel->mutex);
|
||||
locked = 0;
|
||||
zap_thread_create_detached(zap_analog_channel_run, event->channel);
|
||||
} else {
|
||||
event->channel->ring_count++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_OOB_ONHOOK:
|
||||
{
|
||||
if (zap_test_flag(event->channel, ZAP_CHANNEL_RINGING)) {
|
||||
zap_channel_command(event->channel, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
|
||||
}
|
||||
|
||||
if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case ZAP_OOB_FLASH:
|
||||
{
|
||||
if (event->channel->state == ZAP_CHANNEL_STATE_CALLWAITING) {
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
|
||||
zap_clear_flag_locked(event->channel, ZAP_CHANNEL_STATE_CHANGE);
|
||||
zap_clear_flag_locked(event->channel->span, ZAP_SPAN_STATE_CHANGE);
|
||||
event->channel->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
|
||||
}
|
||||
|
||||
zap_channel_rotate_tokens(event->channel);
|
||||
|
||||
if (zap_test_flag(event->channel, ZAP_CHANNEL_HOLD) && event->channel->token_count != 1) {
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
|
||||
} else {
|
||||
sig.event_id = ZAP_SIGEVENT_FLASH;
|
||||
analog_data->sig_cb(&sig);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_OOB_OFFHOOK:
|
||||
{
|
||||
if (event->channel->type == ZAP_CHAN_TYPE_FXS) {
|
||||
if (zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
|
||||
if (zap_test_flag(event->channel, ZAP_CHANNEL_RINGING)) {
|
||||
zap_channel_command(event->channel, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
|
||||
}
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
|
||||
} else {
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DIALTONE);
|
||||
zap_mutex_unlock(event->channel->mutex);
|
||||
locked = 0;
|
||||
zap_thread_create_detached(zap_analog_channel_run, event->channel);
|
||||
}
|
||||
} else {
|
||||
if (!zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
|
||||
if (zap_test_flag(event->channel, ZAP_CHANNEL_OFFHOOK)) {
|
||||
zap_channel_command(event->channel, ZAP_COMMAND_ONHOOK, NULL);
|
||||
}
|
||||
}
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (locked) {
|
||||
zap_mutex_unlock(event->channel->mutex);
|
||||
}
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static void *zap_analog_run(zap_thread_t *me, void *obj)
|
||||
{
|
||||
zap_span_t *span = (zap_span_t *) obj;
|
||||
zap_analog_data_t *analog_data = span->signal_data;
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "ANALOG thread starting.\n");
|
||||
|
||||
while(zap_running() && zap_test_flag(analog_data, ZAP_ANALOG_RUNNING)) {
|
||||
int waitms = 10;
|
||||
zap_status_t status;
|
||||
|
||||
status = zap_span_poll_event(span, waitms);
|
||||
|
||||
switch(status) {
|
||||
case ZAP_SUCCESS:
|
||||
{
|
||||
zap_event_t *event;
|
||||
while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
|
||||
if (event->enum_id == ZAP_OOB_NOOP) {
|
||||
continue;
|
||||
}
|
||||
if (process_event(span, event) != ZAP_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_FAIL:
|
||||
{
|
||||
zap_log(ZAP_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
zap_clear_flag(analog_data, ZAP_ANALOG_RUNNING);
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "ANALOG thread ending.\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static ZIO_SIG_LOAD_FUNCTION(zap_analog_init)
|
||||
{
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
zap_module_t zap_module = {
|
||||
"analog",
|
||||
NULL,
|
||||
NULL,
|
||||
zap_analog_init,
|
||||
zap_analog_configure_span,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ZAP_ANALOG_H
|
||||
#define ZAP_ANALOG_H
|
||||
#include "openzap.h"
|
||||
|
||||
typedef enum {
|
||||
ZAP_ANALOG_RUNNING = (1 << 0)
|
||||
} zap_analog_flag_t;
|
||||
|
||||
static void *zap_analog_run(zap_thread_t *me, void *obj);
|
||||
typedef struct zap_analog_data zap_analog_data_t;
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ZAP_ISDN_H
|
||||
#define ZAP_ISDN_H
|
||||
#include "openzap.h"
|
||||
|
||||
typedef enum {
|
||||
ZAP_ISDN_OPT_NONE = 0,
|
||||
ZAP_ISDN_OPT_SUGGEST_CHANNEL = (1 << 0)
|
||||
} zap_isdn_opts_t;
|
||||
|
||||
typedef enum {
|
||||
ZAP_ISDN_RUNNING = (1 << 0)
|
||||
} zap_isdn_flag_t;
|
||||
|
||||
|
||||
struct zap_isdn_data {
|
||||
Q921Data_t q921;
|
||||
Q931_TrunkInfo_t q931;
|
||||
zap_channel_t *dchan;
|
||||
zap_channel_t *dchans[2];
|
||||
struct zap_sigmsg sigmsg;
|
||||
zio_signal_cb_t sig_cb;
|
||||
uint32_t flags;
|
||||
int32_t mode;
|
||||
zap_isdn_opts_t opts;
|
||||
zap_caller_data_t *outbound_crv[32768];
|
||||
zap_channel_t *channels_local_crv[32768];
|
||||
zap_channel_t *channels_remote_crv[32768];
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef struct zap_isdn_data zap_isdn_data_t;
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ZAP_PIKA_H
|
||||
#define ZAP_PIKA_H
|
||||
#include "openzap.h"
|
||||
#include "pikahmpapi.h"
|
||||
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
PIKA_SPAN_FRAMING_T1_D4,
|
||||
PIKA_SPAN_FRAMING_T1_ESF,
|
||||
PIKA_SPAN_FRAMING_E1_BASIC,
|
||||
PIKA_SPAN_FRAMING_E1_CRC4,
|
||||
PIKA_SPAN_INVALID
|
||||
} PIKA_TSpanFraming;
|
||||
#define PIKA_SPAN_STRINGS "T1_D4", "T1_ESF", "E1_BASIC", "E1_CRC4"
|
||||
ZAP_STR2ENUM_P(pika_str2span, pika_span2str, PIKA_TSpanFraming)
|
||||
|
||||
typedef enum {
|
||||
PIKA_SPAN_ENCODING_T1_AMI_ZS_NONE,
|
||||
PIKA_SPAN_ENCODING_T1_AMI_ZS_GTE,
|
||||
PIKA_SPAN_ENCODING_T1_AMI_ZS_BELL,
|
||||
PIKA_SPAN_ENCODING_T1_AMI_ZS_JAM8,
|
||||
PIKA_SPAN_ENCODING_T1_B8ZS,
|
||||
PIKA_SPAN_ENCODING_E1_AMI,
|
||||
PIKA_SPAN_ENCODING_E1_HDB3,
|
||||
PIKA_SPAN_ENCODING_INVALID
|
||||
} PIKA_TSpanEncoding;
|
||||
#define PIKA_SPAN_ENCODING_STRINGS "T1_AMI_ZS_NONE", "T1_AMI_ZS_GTE", "T1_AMI_ZS_BELL", "T1_AMI_ZS_JAM8", "T1_B8ZS", "E1_AMI", "E1_HDB3"
|
||||
ZAP_STR2ENUM_P(pika_str2span_encoding, pika_span_encoding2str, PIKA_TSpanEncoding)
|
||||
|
||||
typedef enum {
|
||||
PIKA_SPAN_LOOP_LENGTH_SHORT_HAUL,
|
||||
PIKA_SPAN_LOOP_LENGTH_LONG_HAUL,
|
||||
PIKA_SPAN_LOOP_INVALID
|
||||
} PIKA_TSpanLoopLength;
|
||||
#define PIKA_LL_STRINGS "SHORT_HAUL", "LONG_HAUL"
|
||||
ZAP_STR2ENUM_P(pika_str2loop_length, pika_loop_length2str, PIKA_TSpanLoopLength)
|
||||
|
||||
typedef enum {
|
||||
PIKA_SPAN_LBO_T1_LONG_0_DB,
|
||||
PIKA_SPAN_LBO_T1_LONG_7_DB,
|
||||
PIKA_SPAN_LBO_T1_LONG_15_DB,
|
||||
PIKA_SPAN_LBO_T1_LONG_22_DB,
|
||||
PIKA_SPAN_LBO_T1_SHORT_133_FT,
|
||||
PIKA_SPAN_LBO_T1_SHORT_266_FT,
|
||||
PIKA_SPAN_LBO_T1_SHORT_399_FT,
|
||||
PIKA_SPAN_LBO_T1_SHORT_533_FT,
|
||||
PIKA_SPAN_LBO_T1_SHORT_655_FT,
|
||||
PIKA_SPAN_LBO_E1_WAVEFORM_120_OHM,
|
||||
PIKA_SPAN_LBO_INVALID
|
||||
} PIKA_TSpanBuildOut;
|
||||
#define PIKA_LBO_STRINGS "T1_LONG_0_DB", "T1_LONG_7_DB", "T1_LONG_15_DB", "T1_LONG_22_DB", "T1_SHORT_133_FT", "T1_SHORT_266_FT", "T1_SHORT_399_FT", "T1_SHORT_533_FT", "T1_SHORT_655_FT", "E1_WAVEFORM_120_OHM"
|
||||
ZAP_STR2ENUM_P(pika_str2lbo, pika_lbo2str, PIKA_TSpanBuildOut)
|
||||
|
||||
typedef enum {
|
||||
PIKA_SPAN_COMPAND_MODE_MU_LAW = 1,
|
||||
PIKA_SPAN_COMPAND_MODE_A_LAW,
|
||||
PIKA_SPAN_COMPAND_MODE_INVALID
|
||||
} PIKA_TSpanCompandMode;
|
||||
#define PIKA_SPAN_COMPAND_MODE_STRINGS "MU_LAW", "A_LAW"
|
||||
ZAP_STR2ENUM_P(pika_str2compand_mode, pika_compand_mode2str, PIKA_TSpanCompandMode)
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "openzap.h"
|
||||
//#include "zap_skel.h"
|
||||
|
||||
static ZIO_CONFIGURE_FUNCTION(skel_configure)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_CONFIGURE_SPAN_FUNCTION(skel_configure_span)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_OPEN_FUNCTION(skel_open)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_CLOSE_FUNCTION(skel_close)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_WAIT_FUNCTION(skel_wait)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_READ_FUNCTION(skel_read)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_WRITE_FUNCTION(skel_write)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_COMMAND_FUNCTION(skel_command)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_SPAN_POLL_EVENT_FUNCTION(skel_poll_event)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_SPAN_NEXT_EVENT_FUNCTION(skel_next_event)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_CHANNEL_DESTROY_FUNCTION(skel_channel_destroy)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_SPAN_DESTROY_FUNCTION(skel_span_destroy)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_GET_ALARMS_FUNCTION(skel_get_alarms)
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static zap_io_interface_t skel_interface;
|
||||
|
||||
static ZIO_IO_LOAD_FUNCTION(skel_init)
|
||||
{
|
||||
assert(zio != NULL);
|
||||
memset(&skel_interface, 0, sizeof(skel_interface));
|
||||
|
||||
skel_interface.name = "skel";
|
||||
skel_interface.configure = skel_configure;
|
||||
skel_interface.configure_span = skel_configure_span;
|
||||
skel_interface.open = skel_open;
|
||||
skel_interface.close = skel_close;
|
||||
skel_interface.wait = skel_wait;
|
||||
skel_interface.read = skel_read;
|
||||
skel_interface.write = skel_write;
|
||||
skel_interface.command = skel_command;
|
||||
skel_interface.poll_event = skel_poll_event;
|
||||
skel_interface.next_event = skel_next_event;
|
||||
skel_interface.channel_destroy = skel_channel_destroy;
|
||||
skel_interface.span_destroy = skel_span_destroy;
|
||||
skel_interface.get_alarms = skel_get_alarms;
|
||||
*zio = &skel_interface;
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_IO_UNLOAD_FUNCTION(skel_destroy)
|
||||
{
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
zap_module_t zap_module = {
|
||||
"skel",
|
||||
skel_init,
|
||||
skel_destroy,
|
||||
};
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,129 @@
|
||||
/****************************************************************************
|
||||
* sigboost.h $Revision: 1.5 $
|
||||
*
|
||||
* Definitions for the sigboost interface.
|
||||
*
|
||||
* WARNING WARNING WARNING
|
||||
*
|
||||
* This file is used by sangoma_mgd and perhaps other programs. Any changes
|
||||
* to this file must be coordinated with other user programs,
|
||||
*
|
||||
* Copyright (C) 2005 Xygnada Technology, Inc.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _SIGBOOST_H_
|
||||
#define _SIGBOOST_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
enum e_sigboost_event_id_values
|
||||
{
|
||||
SIGBOOST_EVENT_CALL_START = 0x80, /*128*/
|
||||
SIGBOOST_EVENT_CALL_START_ACK = 0x81, /*129*/
|
||||
SIGBOOST_EVENT_CALL_START_NACK = 0x82, /*130*/
|
||||
SIGBOOST_EVENT_CALL_START_NACK_ACK = 0x83, /*131*/
|
||||
SIGBOOST_EVENT_CALL_ANSWERED = 0x84, /*132*/
|
||||
SIGBOOST_EVENT_CALL_STOPPED = 0x85, /*133*/
|
||||
SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/
|
||||
SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/
|
||||
SIGBOOST_EVENT_SYSTEM_RESTART_ACK = 0x88, /*136*/
|
||||
/* Following IDs are ss7boost to sangoma_mgd only. */
|
||||
SIGBOOST_EVENT_HEARTBEAT = 0x89, /*137*/
|
||||
SIGBOOST_EVENT_INSERT_CHECK_LOOP = 0x8a, /*138*/
|
||||
SIGBOOST_EVENT_REMOVE_CHECK_LOOP = 0x8b, /*139*/
|
||||
SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/
|
||||
SIGBOOST_EVENT_DIGIT_IN = 0x8d, /*141*/
|
||||
};
|
||||
enum e_sigboost_release_cause_values
|
||||
{
|
||||
SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0,
|
||||
SIGBOOST_RELEASE_CAUSE_NORMAL = 16,
|
||||
/* probable elimination */
|
||||
//SIGBOOST_RELEASE_CAUSE_BUSY = 0x91, /* 145 */
|
||||
//SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST = 0x92, /* 146 */
|
||||
//SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET = 0x93, /* 147 */
|
||||
//SIGBOOST_RELEASE_CAUSE_NOANSWER = 0x94, /* 148 */
|
||||
};
|
||||
|
||||
enum e_sigboost_call_setup_ack_nack_cause_values
|
||||
{
|
||||
SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 117, /* unused Q.850 value */
|
||||
SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY = 118, /* unused Q.850 value */
|
||||
SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER = 28,
|
||||
/* probable elimination */
|
||||
//SIGBOOST_CALL_SETUP_RESERVED = 0x00,
|
||||
//SIGBOOST_CALL_SETUP_CIRCUIT_RESET = 0x10,
|
||||
//SIGBOOST_CALL_SETUP_NACK_CKT_START_TIMEOUT = 0x11,
|
||||
//SIGBOOST_CALL_SETUP_NACK_AUTO_CALL_GAP = 0x17,
|
||||
};
|
||||
|
||||
#define MAX_DIALED_DIGITS 31
|
||||
|
||||
/* Next two defines are used to create the range of values for call_setup_id
|
||||
* in the t_sigboost structure.
|
||||
* 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
|
||||
#define CORE_MAX_SPANS 200
|
||||
#define CORE_MAX_CHAN_PER_SPAN 30
|
||||
#define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
|
||||
/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
|
||||
#define SIZE_RDNIS 128
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
uint32_t event_id;
|
||||
/* delete sequence numbers - SCTP does not need them */
|
||||
uint32_t fseqno;
|
||||
uint32_t bseqno;
|
||||
uint16_t call_setup_id;
|
||||
uint32_t trunk_group;
|
||||
uint8_t span;
|
||||
uint8_t chan;
|
||||
struct timeval tv;
|
||||
uint8_t called_number_digits_count;
|
||||
char called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
|
||||
uint8_t calling_number_digits_count; /* it's an array */
|
||||
char calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
|
||||
/* ref. Q.931 Table 4-11 and Q.951 Section 3 */
|
||||
uint8_t calling_number_screening_ind;
|
||||
uint8_t calling_number_presentation;
|
||||
char calling_name[MAX_DIALED_DIGITS + 1];
|
||||
uint16_t redirection_string_size;
|
||||
char redirection_string [SIZE_RDNIS]; /* it's a null terminated string */
|
||||
/* redir string format:
|
||||
* http://www.ss7box.com/wiki/tiki-index.php?page=Call+Redirection
|
||||
* */
|
||||
} t_sigboost_callstart;
|
||||
|
||||
#define MIN_SIZE_CALLSTART_MSG (sizeof(t_sigboost_callstart) - SIZE_RDNIS)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t event_id;
|
||||
/* delete sequence numbers - SCTP does not need them */
|
||||
uint32_t fseqno;
|
||||
uint32_t bseqno;
|
||||
uint16_t call_setup_id;
|
||||
uint32_t trunk_group;
|
||||
uint8_t span;
|
||||
uint8_t chan;
|
||||
struct timeval tv;
|
||||
uint8_t release_cause;
|
||||
} t_sigboost_short;
|
||||
#pragma pack()
|
||||
|
||||
static inline int boost_full_event(int event_id)
|
||||
{
|
||||
switch (event_id) {
|
||||
case SIGBOOST_EVENT_CALL_START:
|
||||
case SIGBOOST_EVENT_DIGIT_IN:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include "openzap.h"
|
||||
#include <ss7_boost_client.h>
|
||||
|
||||
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
extern int gethostbyname_r (const char *__name,
|
||||
struct hostent *__result_buf,
|
||||
char *__buf, size_t __buflen,
|
||||
struct hostent **__result,
|
||||
int *__h_errnop);
|
||||
#endif
|
||||
|
||||
struct ss7bc_map {
|
||||
uint32_t event_id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static struct ss7bc_map ss7bc_table[] = {
|
||||
{SIGBOOST_EVENT_CALL_START, "CALL_START"},
|
||||
{SIGBOOST_EVENT_CALL_START_ACK, "CALL_START_ACK"},
|
||||
{SIGBOOST_EVENT_CALL_START_NACK, "CALL_START_NACK"},
|
||||
{SIGBOOST_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"},
|
||||
{SIGBOOST_EVENT_CALL_ANSWERED, "CALL_ANSWERED"},
|
||||
{SIGBOOST_EVENT_CALL_STOPPED, "CALL_STOPPED"},
|
||||
{SIGBOOST_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"},
|
||||
{SIGBOOST_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"},
|
||||
{SIGBOOST_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"},
|
||||
{SIGBOOST_EVENT_HEARTBEAT, "HEARTBEAT"},
|
||||
{SIGBOOST_EVENT_INSERT_CHECK_LOOP, "LOOP START"},
|
||||
{SIGBOOST_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void ss7bc_print_event_call(ss7bc_connection_t *mcon, ss7bc_event_t *event, int priority, int dir, const char *file, const char *func, int line)
|
||||
{
|
||||
if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
|
||||
return;
|
||||
zap_log(file, func, line, ZAP_LOG_LEVEL_DEBUG, "%s EVENT: %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s]\n",
|
||||
dir ? "TX":"RX",
|
||||
ss7bc_event_id_name(event->event_id),
|
||||
event->event_id,
|
||||
event->span+1,
|
||||
event->chan+1,
|
||||
event->call_setup_id,
|
||||
event->fseqno,
|
||||
strlen(event->calling_name)?event->calling_name:"N/A",
|
||||
(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
|
||||
(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
|
||||
);
|
||||
|
||||
}
|
||||
static void ss7bc_print_event_short(ss7bc_connection_t *mcon, ss7bc_short_event_t *event, int priority, int dir, const char *file, const char *func, int line)
|
||||
{
|
||||
if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
|
||||
return;
|
||||
zap_log(file, func, line, ZAP_LOG_LEVEL_DEBUG, "%s EVENT (%s): %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i \n",
|
||||
dir ? "TX":"RX",
|
||||
priority ? "P":"N",
|
||||
ss7bc_event_id_name(event->event_id),
|
||||
event->event_id,
|
||||
event->span+1,
|
||||
event->chan+1,
|
||||
event->release_cause,
|
||||
event->call_setup_id,
|
||||
event->fseqno);
|
||||
}
|
||||
|
||||
|
||||
static int create_conn_socket(ss7bc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
|
||||
{
|
||||
int rc;
|
||||
struct hostent *result, *local_result;
|
||||
char buf[512], local_buf[512];
|
||||
int err = 0, local_err = 0;
|
||||
|
||||
memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
|
||||
memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
|
||||
#ifdef HAVE_NETINET_SCTP_H
|
||||
mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
|
||||
#else
|
||||
mcon->socket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
#endif
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "Creating L=%s:%d R=%s:%d\n",
|
||||
local_ip, local_port, ip, port);
|
||||
|
||||
if (mcon->socket >= 0) {
|
||||
int flag;
|
||||
|
||||
flag = 1;
|
||||
#ifdef HAVE_GETHOSTBYNAME_R_FIVE
|
||||
gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &err);
|
||||
gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_err);
|
||||
if (!err && !local_err) {
|
||||
#else
|
||||
gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
|
||||
gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &local_err);
|
||||
if (result && local_result) {
|
||||
#endif
|
||||
mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
|
||||
memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
|
||||
mcon->remote_addr.sin_port = htons(port);
|
||||
|
||||
mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
|
||||
memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
|
||||
mcon->local_addr.sin_port = htons(local_port);
|
||||
|
||||
#ifdef HAVE_NETINET_SCTP_H
|
||||
setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY,
|
||||
(char *)&flag, sizeof(int));
|
||||
#endif
|
||||
|
||||
if ((rc = bind(mcon->socket,
|
||||
(struct sockaddr *) &mcon->local_addr,
|
||||
sizeof(mcon->local_addr))) < 0) {
|
||||
close(mcon->socket);
|
||||
mcon->socket = -1;
|
||||
} else {
|
||||
#ifdef HAVE_NETINET_SCTP_H
|
||||
rc=listen(mcon->socket, 100);
|
||||
if (rc) {
|
||||
close(mcon->socket);
|
||||
mcon->socket = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zap_mutex_create(&mcon->mutex);
|
||||
|
||||
return mcon->socket;
|
||||
}
|
||||
|
||||
int ss7bc_connection_close(ss7bc_connection_t *mcon)
|
||||
{
|
||||
if (mcon->socket > -1) {
|
||||
close(mcon->socket);
|
||||
}
|
||||
|
||||
if (mcon->mutex) {
|
||||
zap_mutex_lock(mcon->mutex);
|
||||
zap_mutex_unlock(mcon->mutex);
|
||||
zap_mutex_destroy(&mcon->mutex);
|
||||
}
|
||||
memset(mcon, 0, sizeof(*mcon));
|
||||
mcon->socket = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ss7bc_connection_open(ss7bc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
|
||||
{
|
||||
create_conn_socket(mcon, local_ip, local_port, ip, port);
|
||||
return mcon->socket;
|
||||
}
|
||||
|
||||
|
||||
int ss7bc_exec_command(ss7bc_connection_t *mcon, int span, int chan, int id, int cmd, int cause)
|
||||
{
|
||||
ss7bc_short_event_t oevent;
|
||||
int retry = 5;
|
||||
|
||||
ss7bc_event_init(&oevent, cmd, chan, span);
|
||||
oevent.release_cause = cause;
|
||||
|
||||
if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART || cmd == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
|
||||
mcon->rxseq_reset = 1;
|
||||
mcon->txseq = 0;
|
||||
mcon->rxseq = 0;
|
||||
mcon->txwindow = 0;
|
||||
}
|
||||
|
||||
if (id >= 0) {
|
||||
oevent.call_setup_id = id;
|
||||
}
|
||||
|
||||
while (ss7bc_connection_write(mcon, (ss7bc_event_t*)&oevent) <= 0) {
|
||||
if (--retry <= 0) {
|
||||
zap_log(ZAP_LOG_CRIT, "Failed to tx on ISUP socket: %s\n", strerror(errno));
|
||||
return -1;
|
||||
} else {
|
||||
zap_log(ZAP_LOG_WARNING, "Failed to tx on ISUP socket: %s :retry %i\n", strerror(errno), retry);
|
||||
zap_sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ss7bc_exec_commandp(ss7bc_connection_t *pcon, int span, int chan, int id, int cmd, int cause)
|
||||
{
|
||||
ss7bc_short_event_t oevent;
|
||||
int retry = 5;
|
||||
|
||||
ss7bc_event_init(&oevent, cmd, chan, span);
|
||||
oevent.release_cause = cause;
|
||||
|
||||
if (id >= 0) {
|
||||
oevent.call_setup_id = id;
|
||||
}
|
||||
|
||||
while (ss7bc_connection_writep(pcon, (ss7bc_event_t*)&oevent) <= 0) {
|
||||
if (--retry <= 0) {
|
||||
zap_log(ZAP_LOG_CRIT, "Failed to tx on ISUP socket: %s\n", strerror(errno));
|
||||
return -1;
|
||||
} else {
|
||||
zap_log(ZAP_LOG_WARNING, "Failed to tx on ISUP socket: %s :retry %i\n", strerror(errno), retry);
|
||||
zap_sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ss7bc_event_t *__ss7bc_connection_read(ss7bc_connection_t *mcon, int iteration, const char *file, const char *func, int line)
|
||||
{
|
||||
unsigned int fromlen = sizeof(struct sockaddr_in);
|
||||
int bytes = 0;
|
||||
int msg_ok = 0;
|
||||
|
||||
bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT,
|
||||
(struct sockaddr *) &mcon->local_addr, &fromlen);
|
||||
|
||||
/* Must check for < 0 cannot rely on bytes > MIN_SIZE_... compiler issue */
|
||||
if (bytes < 0) {
|
||||
msg_ok=0;
|
||||
|
||||
} else if ((bytes >= MIN_SIZE_CALLSTART_MSG) && boost_full_event(mcon->event.event_id)) {
|
||||
msg_ok=1;
|
||||
|
||||
} else if (bytes == sizeof(ss7bc_short_event_t)) {
|
||||
msg_ok=1;
|
||||
|
||||
} else {
|
||||
msg_ok=0;
|
||||
}
|
||||
|
||||
if (msg_ok){
|
||||
|
||||
if (ss7bc_test_flag(mcon, MSU_FLAG_DOWN)) {
|
||||
if (mcon->event.event_id != SIGBOOST_EVENT_SYSTEM_RESTART &&
|
||||
mcon->event.event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK &&
|
||||
mcon->event.event_id != SIGBOOST_EVENT_HEARTBEAT) {
|
||||
zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "Not reading packets when connection is down. [%s]\n",
|
||||
ss7bc_event_id_name(mcon->event.event_id));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (boost_full_event(mcon->event.event_id)) {
|
||||
ss7bc_print_event_call(mcon, &mcon->event, 0, 0, file, func, line);
|
||||
} else {
|
||||
ss7bc_print_event_short(mcon, (ss7bc_short_event_t*)&mcon->event, 0, 0, file, func, line);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* NC: NOT USED ANY MORE */
|
||||
if (mcon->rxseq_reset) {
|
||||
//if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
|
||||
zap_log(ZAP_LOG_DEBUG, "Rx sync ok\n");
|
||||
mcon->rxseq = mcon->event.fseqno;
|
||||
return &mcon->event;
|
||||
//}
|
||||
errno=EAGAIN;
|
||||
zap_log(ZAP_LOG_DEBUG, "Waiting for rx sync...\n");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
mcon->txwindow = mcon->txseq - mcon->event.bseqno;
|
||||
mcon->rxseq++;
|
||||
|
||||
if (mcon->rxseq != mcon->event.fseqno) {
|
||||
zap_log(ZAP_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &mcon->event;
|
||||
} else {
|
||||
if (iteration == 0) {
|
||||
zap_log(ZAP_LOG_CRIT, "Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ss7bc_event_t *__ss7bc_connection_readp(ss7bc_connection_t *mcon, int iteration, const char *file, const char *func, int line)
|
||||
{
|
||||
unsigned int fromlen = sizeof(struct sockaddr_in);
|
||||
int bytes = 0;
|
||||
|
||||
bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
|
||||
|
||||
if (bytes == sizeof(ss7bc_short_event_t)) {
|
||||
|
||||
if (boost_full_event(mcon->event.event_id)) {
|
||||
ss7bc_print_event_call(mcon, &mcon->event, 1, 0, file, func, line);
|
||||
} else {
|
||||
ss7bc_print_event_short(mcon, (ss7bc_short_event_t*)&mcon->event, 1, 0, file, func, line);
|
||||
}
|
||||
|
||||
return &mcon->event;
|
||||
} else {
|
||||
if (iteration == 0) {
|
||||
zap_log(ZAP_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int __ss7bc_connection_write(ss7bc_connection_t *mcon, ss7bc_event_t *event, const char *file, const char *func, int line)
|
||||
{
|
||||
int err;
|
||||
int event_size=sizeof(ss7bc_event_t);
|
||||
|
||||
if (!event || mcon->socket < 0 || !mcon->mutex) {
|
||||
zap_log(file, func, line, ZAP_LOG_LEVEL_CRIT, "Critical Error: No Event Device\n");
|
||||
return -EINVAL;
|
||||
abort();
|
||||
}
|
||||
|
||||
if (event->span > 16 || event->chan > 31) {
|
||||
zap_log(file, func, line, ZAP_LOG_LEVEL_CRIT, "Critical Error: TX Cmd=%s Invalid Span=%i Chan=%i\n", ss7bc_event_id_name(event->event_id), event->span, event->chan);
|
||||
abort();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!boost_full_event(event->event_id)) {
|
||||
event_size=sizeof(ss7bc_short_event_t);
|
||||
}
|
||||
|
||||
if (ss7bc_test_flag(mcon, MSU_FLAG_DOWN)) {
|
||||
if (event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART &&
|
||||
event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK &&
|
||||
event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
|
||||
zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "Not writing packets when connection is down. [%s]\n",
|
||||
ss7bc_event_id_name(event->event_id));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday(&event->tv, NULL);
|
||||
|
||||
zap_mutex_lock(mcon->mutex);
|
||||
if (event->event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
|
||||
mcon->txseq=0;
|
||||
mcon->rxseq=0;
|
||||
event->fseqno=0;
|
||||
} else {
|
||||
event->fseqno = mcon->txseq++;
|
||||
}
|
||||
event->bseqno = mcon->rxseq;
|
||||
err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
|
||||
|
||||
zap_mutex_unlock(mcon->mutex);
|
||||
|
||||
if (err != event_size) {
|
||||
err = -1;
|
||||
abort();
|
||||
}
|
||||
|
||||
if (boost_full_event(event->event_id)) {
|
||||
ss7bc_print_event_call(mcon, event, 0, 1, file, func, line);
|
||||
} else {
|
||||
ss7bc_print_event_short(mcon, (ss7bc_short_event_t*)event, 0, 1, file, func, line);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int __ss7bc_connection_writep(ss7bc_connection_t *mcon, ss7bc_event_t *event, const char *file, const char *func, int line)
|
||||
{
|
||||
int err;
|
||||
int event_size=sizeof(ss7bc_event_t);
|
||||
|
||||
if (!event || mcon->socket < 0 || !mcon->mutex) {
|
||||
zap_log(file, func, line, ZAP_LOG_LEVEL_CRIT, "Critical Error: No Event Device\n");
|
||||
return -EINVAL;
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!boost_full_event(event->event_id)) {
|
||||
event_size=sizeof(ss7bc_short_event_t);
|
||||
}
|
||||
|
||||
gettimeofday(&event->tv, NULL);
|
||||
|
||||
zap_mutex_lock(mcon->mutex);
|
||||
err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
|
||||
zap_mutex_unlock(mcon->mutex);
|
||||
|
||||
if (err != event_size) {
|
||||
err = -1;
|
||||
abort();
|
||||
}
|
||||
|
||||
if (boost_full_event(event->event_id)) {
|
||||
ss7bc_print_event_call(mcon, event, 1, 1, file, func, line);
|
||||
} else {
|
||||
ss7bc_print_event_short(mcon, (ss7bc_short_event_t*)event, 1, 1, file, func, line);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void ss7bc_call_init(ss7bc_event_t *event, const char *calling, const char *called, int setup_id)
|
||||
{
|
||||
memset(event, 0, sizeof(ss7bc_event_t));
|
||||
event->event_id = SIGBOOST_EVENT_CALL_START;
|
||||
|
||||
if (calling) {
|
||||
strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
|
||||
event->calling_number_digits_count = strlen(calling);
|
||||
}
|
||||
|
||||
if (called) {
|
||||
strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
|
||||
event->called_number_digits_count = strlen(called);
|
||||
}
|
||||
|
||||
event->call_setup_id = setup_id;
|
||||
|
||||
}
|
||||
|
||||
void ss7bc_event_init(ss7bc_short_event_t *event, ss7bc_event_id_t event_id, int chan, int span)
|
||||
{
|
||||
memset(event, 0, sizeof(ss7bc_short_event_t));
|
||||
event->event_id = event_id;
|
||||
event->chan = chan;
|
||||
event->span = span;
|
||||
}
|
||||
|
||||
const char *ss7bc_event_id_name(uint32_t event_id)
|
||||
{
|
||||
unsigned int x;
|
||||
const char *ret = NULL;
|
||||
|
||||
for (x = 0 ; x < sizeof(ss7bc_table)/sizeof(struct ss7bc_map); x++) {
|
||||
if (ss7bc_table[x].event_id == event_id) {
|
||||
ret = ss7bc_table[x].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SS7BC_H
|
||||
#define _SS7BC_H
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#ifdef HAVE_NETINET_SCTP_H
|
||||
#include <netinet/sctp.h>
|
||||
#endif
|
||||
#include <arpa/inet.h>
|
||||
#include <stdarg.h>
|
||||
#include <netdb.h>
|
||||
#include <sigboost.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define ss7bc_test_flag(p,flag) ({ \
|
||||
((p)->flags & (flag)); \
|
||||
})
|
||||
|
||||
#define ss7bc_set_flag(p,flag) do { \
|
||||
((p)->flags |= (flag)); \
|
||||
} while (0)
|
||||
|
||||
#define ss7bc_clear_flag(p,flag) do { \
|
||||
((p)->flags &= ~(flag)); \
|
||||
} while (0)
|
||||
|
||||
#define ss7bc_copy_flags(dest,src,flagz) do { \
|
||||
(dest)->flags &= ~(flagz); \
|
||||
(dest)->flags |= ((src)->flags & (flagz)); \
|
||||
} while (0)
|
||||
|
||||
typedef t_sigboost_callstart ss7bc_event_t;
|
||||
typedef t_sigboost_short ss7bc_short_event_t;
|
||||
typedef uint32_t ss7bc_event_id_t;
|
||||
|
||||
typedef struct ss7bc_ip_cfg
|
||||
{
|
||||
char local_ip[25];
|
||||
int local_port;
|
||||
char remote_ip[25];
|
||||
int remote_port;
|
||||
}ss7bc_ip_cfg_t;
|
||||
|
||||
typedef enum {
|
||||
MSU_FLAG_EVENT = (1 << 0),
|
||||
MSU_FLAG_DOWN = (1 << 1)
|
||||
} ss7bc_flag_t;
|
||||
|
||||
|
||||
struct ss7bc_connection {
|
||||
zap_socket_t socket;
|
||||
struct sockaddr_in local_addr;
|
||||
struct sockaddr_in remote_addr;
|
||||
ss7bc_event_t event;
|
||||
struct hostent remote_hp;
|
||||
struct hostent local_hp;
|
||||
unsigned int flags;
|
||||
zap_mutex_t *mutex;
|
||||
FILE *log;
|
||||
unsigned int txseq;
|
||||
unsigned int rxseq;
|
||||
unsigned int txwindow;
|
||||
unsigned int rxseq_reset;
|
||||
ss7bc_ip_cfg_t cfg;
|
||||
uint32_t hb_elapsed;
|
||||
};
|
||||
|
||||
typedef struct ss7bc_connection ss7bc_connection_t;
|
||||
|
||||
/* disable nagle's algorythm */
|
||||
static inline void sctp_no_nagle(int socket)
|
||||
{
|
||||
#ifdef HAVE_NETINET_SCTP_H
|
||||
int flag = 1;
|
||||
setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
|
||||
#endif
|
||||
}
|
||||
|
||||
int ss7bc_connection_close(ss7bc_connection_t *mcon);
|
||||
int ss7bc_connection_open(ss7bc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
|
||||
ss7bc_event_t *__ss7bc_connection_read(ss7bc_connection_t *mcon, int iteration, const char *file, const char *func, int line);
|
||||
ss7bc_event_t *__ss7bc_connection_readp(ss7bc_connection_t *mcon, int iteration, const char *file, const char *func, int line);
|
||||
int __ss7bc_connection_write(ss7bc_connection_t *mcon, ss7bc_event_t *event, const char *file, const char *func, int line);
|
||||
int __ss7bc_connection_writep(ss7bc_connection_t *mcon, ss7bc_event_t *event, const char *file, const char *func, int line);
|
||||
#define ss7bc_connection_write(_m,_e) __ss7bc_connection_write(_m, _e, __FILE__, __func__, __LINE__)
|
||||
#define ss7bc_connection_writep(_m,_e) __ss7bc_connection_writep(_m, _e, __FILE__, __func__, __LINE__)
|
||||
#define ss7bc_connection_read(_m,_e) __ss7bc_connection_read(_m, _e, __FILE__, __func__, __LINE__)
|
||||
#define ss7bc_connection_readp(_m,_e) __ss7bc_connection_readp(_m, _e, __FILE__, __func__, __LINE__)
|
||||
void ss7bc_event_init(ss7bc_short_event_t *event, ss7bc_event_id_t event_id, int chan, int span);
|
||||
void ss7bc_call_init(ss7bc_event_t *event, const char *calling, const char *called, int setup_id);
|
||||
const char *ss7bc_event_id_name(uint32_t event_id);
|
||||
int ss7bc_exec_command(ss7bc_connection_t *mcon, int span, int chan, int id, int cmd, int cause);
|
||||
int ss7bc_exec_commandp(ss7bc_connection_t *pcon, int span, int chan, int id, int cmd, int cause);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ZAP_SS7_BOOST_H
|
||||
#define ZAP_SS7_BOOST_H
|
||||
#include "ss7_boost_client.h"
|
||||
#include "openzap.h"
|
||||
|
||||
typedef enum {
|
||||
ZAP_SS7_BOOST_RUNNING = (1 << 0),
|
||||
ZAP_SS7_BOOST_RESTARTING = (1 << 1)
|
||||
} zap_ss7_boost_flag_t;
|
||||
|
||||
typedef struct zap_ss7_boost_data {
|
||||
ss7bc_connection_t mcon;
|
||||
ss7bc_connection_t pcon;
|
||||
zio_signal_cb_t signal_cb;
|
||||
uint32_t flags;
|
||||
} zap_ss7_boost_data_t;
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,988 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef __sun
|
||||
#include <unistd.h>
|
||||
#include <stropts.h>
|
||||
#endif
|
||||
#include "openzap.h"
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include "wanpipe_tdm_api_iface.h"
|
||||
|
||||
typedef enum {
|
||||
WP_RINGING = (1 << 0)
|
||||
} wp_flag_t;
|
||||
|
||||
static struct {
|
||||
uint32_t codec_ms;
|
||||
uint32_t wink_ms;
|
||||
uint32_t flash_ms;
|
||||
uint32_t ring_on_ms;
|
||||
uint32_t ring_off_ms;
|
||||
} wp_globals;
|
||||
|
||||
/* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */
|
||||
|
||||
ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
|
||||
ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
|
||||
|
||||
#define WP_INVALID_SOCKET -1
|
||||
/* on windows right now, there is no way to specify if we want to read events here or not, we allways get them here */
|
||||
/* we need some what to select if we are reading regular tdm msgs or events */
|
||||
/* need to either have 2 functions, 1 for events, 1 for regural read, or a flag on this function to choose */
|
||||
/* 2 functions preferred. Need implementation for the event function for both nix and windows that is threadsafe */
|
||||
static __inline__ int tdmv_api_readmsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, int datalen)
|
||||
{
|
||||
/* What do we need to do here to avoid having to do all */
|
||||
/* the memcpy's on windows and still maintain api compat with nix */
|
||||
uint32_t rx_len=0;
|
||||
#if defined(__WINDOWS__)
|
||||
static RX_DATA_STRUCT rx_data;
|
||||
api_header_t *pri;
|
||||
wp_tdm_api_rx_hdr_t *tdm_api_rx_hdr;
|
||||
wp_tdm_api_rx_hdr_t *user_buf = (wp_tdm_api_rx_hdr_t*)hdrbuf;
|
||||
DWORD ln;
|
||||
|
||||
if (hdrlen != sizeof(wp_tdm_api_rx_hdr_t)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!DeviceIoControl(
|
||||
fd,
|
||||
IoctlReadCommand,
|
||||
(LPVOID)NULL,
|
||||
0L,
|
||||
(LPVOID)&rx_data,
|
||||
sizeof(RX_DATA_STRUCT),
|
||||
(LPDWORD)(&ln),
|
||||
(LPOVERLAPPED)NULL
|
||||
)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
pri = &rx_data.api_header;
|
||||
tdm_api_rx_hdr = (wp_tdm_api_rx_hdr_t*)rx_data.data;
|
||||
|
||||
user_buf->wp_tdm_api_event_type = pri->operation_status;
|
||||
|
||||
switch(pri->operation_status)
|
||||
{
|
||||
case SANG_STATUS_RX_DATA_AVAILABLE:
|
||||
if (pri->data_length > datalen){
|
||||
break;
|
||||
}
|
||||
memcpy(databuf, rx_data.data, pri->data_length);
|
||||
rx_len = pri->data_length;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#else
|
||||
struct msghdr msg;
|
||||
struct iovec iov[2];
|
||||
|
||||
memset(&msg,0,sizeof(struct msghdr));
|
||||
|
||||
iov[0].iov_len=hdrlen;
|
||||
iov[0].iov_base=hdrbuf;
|
||||
|
||||
iov[1].iov_len=datalen;
|
||||
iov[1].iov_base=databuf;
|
||||
|
||||
msg.msg_iovlen=2;
|
||||
msg.msg_iov=iov;
|
||||
|
||||
rx_len = read(fd,&msg,datalen+hdrlen);
|
||||
|
||||
if (rx_len <= sizeof(wp_tdm_api_rx_hdr_t)){
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rx_len-=sizeof(wp_tdm_api_rx_hdr_t);
|
||||
#endif
|
||||
return rx_len;
|
||||
}
|
||||
|
||||
static __inline__ int tdmv_api_writemsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, unsigned short datalen)
|
||||
{
|
||||
/* What do we need to do here to avoid having to do all */
|
||||
/* the memcpy's on windows and still maintain api compat with nix */
|
||||
int bsent = 0;
|
||||
#if defined(__WINDOWS__)
|
||||
static TX_DATA_STRUCT local_tx_data;
|
||||
api_header_t *pri;
|
||||
DWORD ln;
|
||||
|
||||
/* Are these really not needed or used??? What about for nix?? */
|
||||
(void)hdrbuf;
|
||||
(void)hdrlen;
|
||||
|
||||
pri = &local_tx_data.api_header;
|
||||
|
||||
pri->data_length = datalen;
|
||||
memcpy(local_tx_data.data, databuf, pri->data_length);
|
||||
|
||||
if (!DeviceIoControl(
|
||||
fd,
|
||||
IoctlWriteCommand,
|
||||
(LPVOID)&local_tx_data,
|
||||
(ULONG)sizeof(TX_DATA_STRUCT),
|
||||
(LPVOID)&local_tx_data,
|
||||
sizeof(TX_DATA_STRUCT),
|
||||
(LPDWORD)(&ln),
|
||||
(LPOVERLAPPED)NULL
|
||||
)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (local_tx_data.api_header.operation_status == SANG_STATUS_SUCCESS) {
|
||||
bsent = datalen;
|
||||
}
|
||||
#else
|
||||
struct msghdr msg;
|
||||
struct iovec iov[2];
|
||||
|
||||
memset(&msg,0,sizeof(struct msghdr));
|
||||
|
||||
iov[0].iov_len = hdrlen;
|
||||
iov[0].iov_base = hdrbuf;
|
||||
|
||||
iov[1].iov_len = datalen;
|
||||
iov[1].iov_base = databuf;
|
||||
|
||||
msg.msg_iovlen = 2;
|
||||
msg.msg_iov = iov;
|
||||
|
||||
bsent = write(fd, &msg, datalen + hdrlen);
|
||||
if (bsent > 0){
|
||||
bsent -= sizeof(wp_tdm_api_tx_hdr_t);
|
||||
}
|
||||
#endif
|
||||
return bsent;
|
||||
}
|
||||
|
||||
/* a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog */
|
||||
/* so we can have one analong handler thread that will deal with all the idle analog channels for events */
|
||||
/* the alternative would be for the driver to provide one socket for all of the oob events for all analog channels */
|
||||
static __inline__ int tdmv_api_wait_socket(sng_fd_t fd, int timeout, int *flags)
|
||||
{
|
||||
#if defined(__WINDOWS__)
|
||||
DWORD ln;
|
||||
API_POLL_STRUCT api_poll;
|
||||
|
||||
memset(&api_poll, 0x00, sizeof(API_POLL_STRUCT));
|
||||
|
||||
api_poll.user_flags_bitmap = *flags;
|
||||
api_poll.timeout = timeout;
|
||||
|
||||
if (!DeviceIoControl(
|
||||
fd,
|
||||
IoctlApiPoll,
|
||||
(LPVOID)NULL,
|
||||
0L,
|
||||
(LPVOID)&api_poll,
|
||||
sizeof(API_POLL_STRUCT),
|
||||
(LPDWORD)(&ln),
|
||||
(LPOVERLAPPED)NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*flags = 0;
|
||||
|
||||
switch(api_poll.operation_status)
|
||||
{
|
||||
case SANG_STATUS_RX_DATA_AVAILABLE:
|
||||
break;
|
||||
|
||||
case SANG_STATUS_RX_DATA_TIMEOUT:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (api_poll.poll_events_bitmap == 0){
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (api_poll.poll_events_bitmap & POLL_EVENT_TIMEOUT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*flags = api_poll.poll_events_bitmap;
|
||||
|
||||
return 1;
|
||||
#else
|
||||
struct pollfd pfds[1];
|
||||
int res;
|
||||
|
||||
memset(&pfds[0], 0, sizeof(pfds[0]));
|
||||
pfds[0].fd = fd;
|
||||
pfds[0].events = *flags;
|
||||
res = poll(pfds, 1, timeout);
|
||||
*flags = 0;
|
||||
|
||||
if (pfds[0].revents & POLLERR) {
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
*flags = pfds[0].revents;
|
||||
}
|
||||
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define FNAME_LEN 128
|
||||
static __inline__ sng_fd_t tdmv_api_open_span_chan(int span, int chan)
|
||||
{
|
||||
char fname[FNAME_LEN];
|
||||
sng_fd_t fd = WP_INVALID_SOCKET;
|
||||
#if defined(__WINDOWS__)
|
||||
DWORD ln;
|
||||
wan_udp_hdr_t wan_udp;
|
||||
|
||||
/* NOTE: under Windows Interfaces are zero based but 'chan' is 1 based. */
|
||||
/* Subtract 1 from 'chan'. */
|
||||
_snprintf(fname , FNAME_LEN, "\\\\.\\WANPIPE%d_IF%d", span, chan - 1);
|
||||
|
||||
fd = CreateFile( fname,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
(LPSECURITY_ATTRIBUTES)NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
|
||||
(HANDLE)NULL
|
||||
);
|
||||
|
||||
/* make sure that we are the only ones who have this chan open */
|
||||
/* is this a threadsafe way to make sure that we are ok and will */
|
||||
/* never return a valid handle to more than one thread for the same channel? */
|
||||
|
||||
wan_udp.wan_udphdr_command = GET_OPEN_HANDLES_COUNTER;
|
||||
wan_udp.wan_udphdr_data_len = 0;
|
||||
|
||||
DeviceIoControl(
|
||||
fd,
|
||||
IoctlManagementCommand,
|
||||
(LPVOID)&wan_udp,
|
||||
sizeof(wan_udp_hdr_t),
|
||||
(LPVOID)&wan_udp,
|
||||
sizeof(wan_udp_hdr_t),
|
||||
(LPDWORD)(&ln),
|
||||
(LPOVERLAPPED)NULL
|
||||
);
|
||||
|
||||
if ((wan_udp.wan_udphdr_return_code) || (*(int*)&wan_udp.wan_udphdr_data[0] != 1)){
|
||||
/* somone already has this channel, or somthing else is not right. */
|
||||
tdmv_api_close_socket(&fd);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Does this fail if another thread already has this chan open? */
|
||||
/* if not, we need to add some code to make sure it does */
|
||||
snprintf(fname, FNAME_LEN, "/dev/wptdm_s%dc%d",span,chan);
|
||||
|
||||
fd = open(fname, O_RDWR);
|
||||
|
||||
if (fd < 0) {
|
||||
fd = WP_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
#endif
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static zap_io_interface_t wanpipe_interface;
|
||||
|
||||
static zap_status_t wp_tdm_cmd_exec(zap_channel_t *zchan, wanpipe_tdm_api_t *tdm_api)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* I'm told the 2nd arg is ignored but i send it as the cmd anyway for good measure */
|
||||
err = ioctl(zchan->sockfd, tdm_api->wp_tdm_cmd.cmd, &tdm_api->wp_tdm_cmd);
|
||||
|
||||
if (err) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number)
|
||||
{
|
||||
unsigned configured = 0, x;
|
||||
|
||||
for(x = start; x < end; x++) {
|
||||
zap_channel_t *chan;
|
||||
zap_socket_t sockfd = WP_INVALID_SOCKET;
|
||||
|
||||
sockfd = tdmv_api_open_span_chan(spanno, x);
|
||||
|
||||
if (sockfd != WP_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
|
||||
wanpipe_tdm_api_t tdm_api;
|
||||
zap_log(ZAP_LOG_INFO, "configuring device s%dc%d as OpenZAP device %d:%d fd:%d\n", spanno, x, chan->span_id, chan->chan_id, sockfd);
|
||||
chan->physical_span_id = spanno;
|
||||
chan->physical_chan_id = x;
|
||||
chan->rate = 8000;
|
||||
|
||||
if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
|
||||
|
||||
|
||||
#if 1
|
||||
if (type == ZAP_CHAN_TYPE_FXO) {
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_ONHOOK;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
|
||||
wp_tdm_cmd_exec(chan, &tdm_api);
|
||||
}
|
||||
#endif
|
||||
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_RING_DETECT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
|
||||
wp_tdm_cmd_exec(chan, &tdm_api);
|
||||
#if 1
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_RING_TRIP_DETECT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
|
||||
wp_tdm_cmd_exec(chan, &tdm_api);
|
||||
#endif
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_RXHOOK;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
|
||||
wp_tdm_cmd_exec(chan, &tdm_api);
|
||||
|
||||
}
|
||||
|
||||
if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO || type == ZAP_CHAN_TYPE_B) {
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_GET_HW_CODING;
|
||||
wp_tdm_cmd_exec(chan, &tdm_api);
|
||||
if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
|
||||
chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
|
||||
} else {
|
||||
chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zap_strlen_zero(name)) {
|
||||
zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
|
||||
}
|
||||
if (!zap_strlen_zero(number)) {
|
||||
zap_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
|
||||
}
|
||||
configured++;
|
||||
} else {
|
||||
zap_log(ZAP_LOG_ERROR, "failure configuring device s%dc%d\n", spanno, x);
|
||||
}
|
||||
}
|
||||
|
||||
return configured;
|
||||
}
|
||||
|
||||
static ZIO_CONFIGURE_FUNCTION(wanpipe_configure)
|
||||
{
|
||||
int num;
|
||||
|
||||
if (!strcasecmp(category, "defaults")) {
|
||||
if (!strcasecmp(var, "codec_ms")) {
|
||||
num = atoi(val);
|
||||
if (num < 10 || num > 60) {
|
||||
zap_log(ZAP_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
|
||||
} else {
|
||||
wp_globals.codec_ms = num;
|
||||
}
|
||||
} else if (!strcasecmp(var, "wink_ms")) {
|
||||
num = atoi(val);
|
||||
if (num < 50 || num > 3000) {
|
||||
zap_log(ZAP_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
|
||||
} else {
|
||||
wp_globals.wink_ms = num;
|
||||
}
|
||||
} else if (!strcasecmp(var, "flash_ms")) {
|
||||
num = atoi(val);
|
||||
if (num < 50 || num > 3000) {
|
||||
zap_log(ZAP_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
|
||||
} else {
|
||||
wp_globals.flash_ms = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
|
||||
{
|
||||
int items, i;
|
||||
char *mydata, *item_list[10];
|
||||
char *sp, *ch, *mx;
|
||||
int channo;
|
||||
int spanno;
|
||||
int top = 0;
|
||||
unsigned configured = 0;
|
||||
|
||||
assert(str != NULL);
|
||||
|
||||
|
||||
mydata = strdup(str);
|
||||
assert(mydata != NULL);
|
||||
|
||||
|
||||
items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
|
||||
|
||||
for(i = 0; i < items; i++) {
|
||||
sp = item_list[i];
|
||||
if ((ch = strchr(sp, ':'))) {
|
||||
*ch++ = '\0';
|
||||
}
|
||||
|
||||
if (!(sp && ch)) {
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid input\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
channo = atoi(ch);
|
||||
spanno = atoi(sp);
|
||||
|
||||
|
||||
if (channo < 0) {
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spanno < 0) {
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid span number %d\n", channo);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((mx = strchr(ch, '-'))) {
|
||||
mx++;
|
||||
top = atoi(mx) + 1;
|
||||
} else {
|
||||
top = channo + 1;
|
||||
}
|
||||
|
||||
|
||||
if (top < 0) {
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
|
||||
continue;
|
||||
}
|
||||
|
||||
configured += wp_open_range(span, spanno, channo, top, type, name, number);
|
||||
|
||||
}
|
||||
|
||||
free(mydata);
|
||||
|
||||
return configured;
|
||||
}
|
||||
|
||||
static ZIO_OPEN_FUNCTION(wanpipe_open)
|
||||
{
|
||||
|
||||
wanpipe_tdm_api_t tdm_api;
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_DQ921 || zchan->type == ZAP_CHAN_TYPE_DQ931) {
|
||||
zchan->native_codec = zchan->effective_codec = ZAP_CODEC_NONE;
|
||||
} else {
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_CODEC;
|
||||
tdm_api.wp_tdm_cmd.tdm_codec = 0;
|
||||
wp_tdm_cmd_exec(zchan, &tdm_api);
|
||||
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_USR_PERIOD;
|
||||
tdm_api.wp_tdm_cmd.usr_period = wp_globals.codec_ms;
|
||||
wp_tdm_cmd_exec(zchan, &tdm_api);
|
||||
zap_channel_set_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL);
|
||||
zchan->effective_interval = zchan->native_interval = wp_globals.codec_ms;
|
||||
zchan->packet_len = zchan->native_interval * 8;
|
||||
zchan->native_codec = zchan->effective_codec;
|
||||
|
||||
}
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_CLOSE_FUNCTION(wanpipe_close)
|
||||
{
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_COMMAND_FUNCTION(wanpipe_command)
|
||||
{
|
||||
wanpipe_tdm_api_t tdm_api;
|
||||
int err = 0;
|
||||
|
||||
memset(&tdm_api, 0, sizeof(tdm_api));
|
||||
|
||||
switch(command) {
|
||||
case ZAP_COMMAND_OFFHOOK:
|
||||
{
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = zchan->span->start_type == ZAP_ANALOG_START_KEWL ?
|
||||
WP_TDMAPI_EVENT_TXSIG_START : WP_TDMAPI_EVENT_TXSIG_KEWL;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
|
||||
if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "OFFHOOK Failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_ONHOOK:
|
||||
{
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_ONHOOK;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
|
||||
if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "ONHOOK Failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_GENERATE_RING_ON:
|
||||
{
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_RING;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
|
||||
if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING);
|
||||
zap_set_pflag_locked(zchan, WP_RINGING);
|
||||
zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_on_ms;
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_GENERATE_RING_OFF:
|
||||
{
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_RING;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_DISABLE;
|
||||
if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off Failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
zap_clear_pflag_locked(zchan, WP_RINGING);
|
||||
zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_GET_INTERVAL:
|
||||
{
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_GET_USR_PERIOD;
|
||||
|
||||
if (!(err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
|
||||
ZAP_COMMAND_OBJ_INT = tdm_api.wp_tdm_cmd.usr_period;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_SET_INTERVAL:
|
||||
{
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_USR_PERIOD;
|
||||
tdm_api.wp_tdm_cmd.usr_period = ZAP_COMMAND_OBJ_INT;
|
||||
err = wp_tdm_cmd_exec(zchan, &tdm_api);
|
||||
zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
if (err) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_READ_FUNCTION(wanpipe_read)
|
||||
{
|
||||
int rx_len = 0;
|
||||
wp_tdm_api_rx_hdr_t hdrframe;
|
||||
|
||||
memset(&hdrframe, 0, sizeof(hdrframe));
|
||||
|
||||
rx_len = tdmv_api_readmsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen);
|
||||
|
||||
*datalen = rx_len;
|
||||
|
||||
if (rx_len <= 0) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_WRITE_FUNCTION(wanpipe_write)
|
||||
{
|
||||
int bsent;
|
||||
wp_tdm_api_tx_hdr_t hdrframe;
|
||||
|
||||
/* Do we even need the headerframe here? on windows, we don't even pass it to the driver */
|
||||
memset(&hdrframe, 0, sizeof(hdrframe));
|
||||
bsent = tdmv_api_writemsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen));
|
||||
|
||||
/* should we be checking if bsent == *datalen here? */
|
||||
if (bsent > 0) {
|
||||
*datalen = bsent;
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
static ZIO_WAIT_FUNCTION(wanpipe_wait)
|
||||
{
|
||||
int32_t inflags = 0;
|
||||
int result;
|
||||
|
||||
if (*flags & ZAP_READ) {
|
||||
inflags |= POLLIN;
|
||||
}
|
||||
|
||||
if (*flags & ZAP_WRITE) {
|
||||
inflags |= POLLOUT;
|
||||
}
|
||||
|
||||
if (*flags & ZAP_EVENTS) {
|
||||
inflags |= POLLPRI;
|
||||
}
|
||||
|
||||
result = tdmv_api_wait_socket(zchan->sockfd, to, &inflags);
|
||||
|
||||
*flags = ZAP_NO_FLAGS;
|
||||
|
||||
if (result < 0){
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "Poll failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
return ZAP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (inflags & POLLIN) {
|
||||
*flags |= ZAP_READ;
|
||||
}
|
||||
|
||||
if (inflags & POLLOUT) {
|
||||
*flags |= ZAP_WRITE;
|
||||
}
|
||||
|
||||
if (inflags & POLLPRI) {
|
||||
*flags |= ZAP_EVENTS;
|
||||
}
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
|
||||
{
|
||||
struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
|
||||
uint32_t i, j = 0, k = 0, l = 0;
|
||||
int r;
|
||||
|
||||
for(i = 1; i <= span->chan_count; i++) {
|
||||
zap_channel_t *zchan = &span->channels[i];
|
||||
memset(&pfds[j], 0, sizeof(pfds[j]));
|
||||
pfds[j].fd = span->channels[i].sockfd;
|
||||
pfds[j].events = POLLPRI;
|
||||
|
||||
/* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
|
||||
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_WINK) || zap_test_flag(zchan, ZAP_CHANNEL_FLASH)) {
|
||||
l = 5;
|
||||
}
|
||||
|
||||
j++;
|
||||
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
|
||||
l = 5;
|
||||
}
|
||||
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING) && zap_current_time_in_ms() >= zchan->ring_time) {
|
||||
wanpipe_tdm_api_t tdm_api;
|
||||
int err;
|
||||
memset(&tdm_api, 0, sizeof(tdm_api));
|
||||
if (zap_test_pflag(zchan, WP_RINGING)) {
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_RING;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_DISABLE;
|
||||
if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off Failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
zap_clear_pflag_locked(zchan, WP_RINGING);
|
||||
zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_off_ms;
|
||||
} else {
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_RING;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
|
||||
if ((err = wp_tdm_cmd_exec(zchan, &tdm_api))) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
zap_set_pflag_locked(zchan, WP_RINGING);
|
||||
zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_on_ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (l) {
|
||||
ms = l;
|
||||
}
|
||||
|
||||
r = poll(pfds, j, ms);
|
||||
|
||||
if (r == 0) {
|
||||
return l ? ZAP_SUCCESS : ZAP_TIMEOUT;
|
||||
} else if (r < 0) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
for(i = 1; i <= span->chan_count; i++) {
|
||||
zap_channel_t *zchan = &span->channels[i];
|
||||
|
||||
if (pfds[i-1].revents & POLLPRI) {
|
||||
zap_set_flag(zchan, ZAP_CHANNEL_EVENT);
|
||||
zchan->last_event_time = zap_current_time_in_ms();
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return k ? ZAP_SUCCESS : ZAP_FAIL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
|
||||
{
|
||||
uint32_t i;
|
||||
zap_oob_event_t event_id;
|
||||
|
||||
for(i = 1; i <= span->chan_count; i++) {
|
||||
if (span->channels[i].last_event_time && !zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) {
|
||||
uint32_t diff = (uint32_t)(zap_current_time_in_ms() - span->channels[i].last_event_time);
|
||||
/* XX printf("%u %u %u\n", diff, (unsigned)zap_current_time_in_ms(), (unsigned)span->channels[i].last_event_time); */
|
||||
if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_WINK)) {
|
||||
if (diff > wp_globals.wink_ms) {
|
||||
zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_WINK);
|
||||
zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_FLASH);
|
||||
zap_set_flag_locked((&span->channels[i]), ZAP_CHANNEL_OFFHOOK);
|
||||
event_id = ZAP_OOB_OFFHOOK;
|
||||
goto event;
|
||||
}
|
||||
}
|
||||
|
||||
if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_FLASH)) {
|
||||
if (diff > wp_globals.flash_ms) {
|
||||
zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_FLASH);
|
||||
zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_WINK);
|
||||
zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_OFFHOOK);
|
||||
event_id = ZAP_OOB_ONHOOK;
|
||||
|
||||
if (span->channels[i].type == ZAP_CHAN_TYPE_FXO) {
|
||||
wanpipe_tdm_api_t tdm_api;
|
||||
memset(&tdm_api, 0, sizeof(tdm_api));
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_ONHOOK;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
|
||||
wp_tdm_cmd_exec(&span->channels[i], &tdm_api);
|
||||
}
|
||||
goto event;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) {
|
||||
wanpipe_tdm_api_t tdm_api;
|
||||
memset(&tdm_api, 0, sizeof(tdm_api));
|
||||
zap_clear_flag((&span->channels[i]), ZAP_CHANNEL_EVENT);
|
||||
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_READ_EVENT;
|
||||
if (wp_tdm_cmd_exec(&span->channels[i], &tdm_api) != ZAP_SUCCESS) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
|
||||
case WP_TDMAPI_EVENT_RXHOOK:
|
||||
{
|
||||
if (span->channels[i].type == ZAP_CHAN_TYPE_FXS) {
|
||||
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? ZAP_OOB_OFFHOOK : ZAP_OOB_ONHOOK;
|
||||
if (event_id == ZAP_OOB_OFFHOOK) {
|
||||
if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_FLASH)) {
|
||||
zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_FLASH);
|
||||
zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_WINK);
|
||||
event_id = ZAP_OOB_FLASH;
|
||||
goto event;
|
||||
} else {
|
||||
zap_set_flag_locked((&span->channels[i]), ZAP_CHANNEL_WINK);
|
||||
}
|
||||
} else {
|
||||
if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_WINK)) {
|
||||
zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_WINK);
|
||||
zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_FLASH);
|
||||
event_id = ZAP_OOB_WINK;
|
||||
goto event;
|
||||
} else {
|
||||
zap_set_flag_locked((&span->channels[i]), ZAP_CHANNEL_FLASH);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
int err;
|
||||
|
||||
tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_SET_EVENT;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type = WP_TDMAPI_EVENT_TXSIG_ONHOOK;
|
||||
tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_mode = WP_TDMAPI_EVENT_ENABLE;
|
||||
if ((err = wp_tdm_cmd_exec(&span->channels[i], &tdm_api))) {
|
||||
snprintf(span->channels[i].last_error, sizeof(span->channels[i].last_error), "ONHOOK Failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? ZAP_OOB_ONHOOK : ZAP_OOB_NOOP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WP_TDMAPI_EVENT_RING_DETECT:
|
||||
{
|
||||
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? ZAP_OOB_RING_START : ZAP_OOB_RING_STOP;
|
||||
}
|
||||
break;
|
||||
case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
|
||||
{
|
||||
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? ZAP_OOB_ONHOOK : ZAP_OOB_OFFHOOK;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
|
||||
event_id = ZAP_OOB_INVALID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
event:
|
||||
|
||||
span->channels[i].last_event_time = 0;
|
||||
span->event_header.e_type = ZAP_EVENT_OOB;
|
||||
span->event_header.enum_id = event_id;
|
||||
span->event_header.channel = &span->channels[i];
|
||||
*event = &span->event_header;
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return ZAP_FAIL;
|
||||
|
||||
}
|
||||
|
||||
static ZIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
|
||||
{
|
||||
if (zchan->sockfd > -1) {
|
||||
close(zchan->sockfd);
|
||||
zchan->sockfd = WP_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_IO_LOAD_FUNCTION(wanpipe_init)
|
||||
{
|
||||
assert(zio != NULL);
|
||||
memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
|
||||
|
||||
wp_globals.codec_ms = 20;
|
||||
wp_globals.wink_ms = 150;
|
||||
wp_globals.flash_ms = 750;
|
||||
wp_globals.ring_on_ms = 2000;
|
||||
wp_globals.ring_off_ms = 4000;
|
||||
wanpipe_interface.name = "wanpipe";
|
||||
wanpipe_interface.configure_span = wanpipe_configure_span;
|
||||
wanpipe_interface.configure = wanpipe_configure;
|
||||
wanpipe_interface.open = wanpipe_open;
|
||||
wanpipe_interface.close = wanpipe_close;
|
||||
wanpipe_interface.command = wanpipe_command;
|
||||
wanpipe_interface.wait = wanpipe_wait;
|
||||
wanpipe_interface.read = wanpipe_read;
|
||||
wanpipe_interface.write = wanpipe_write;
|
||||
#ifndef WIN32
|
||||
wanpipe_interface.poll_event = wanpipe_poll_event;
|
||||
#endif
|
||||
wanpipe_interface.next_event = wanpipe_next_event;
|
||||
wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
|
||||
*zio = &wanpipe_interface;
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_IO_UNLOAD_FUNCTION(wanpipe_destroy)
|
||||
{
|
||||
memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
zap_module_t zap_module = {
|
||||
"wanpipe",
|
||||
wanpipe_init,
|
||||
wanpipe_destroy,
|
||||
};
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
@@ -0,0 +1,313 @@
|
||||
/*****************************************************************************
|
||||
* wanpipe_tdm_api.h
|
||||
*
|
||||
* WANPIPE(tm) AFT TE1 Hardware Support
|
||||
*
|
||||
* Authors: Nenad Corbic <ncorbic@sangoma.com>
|
||||
*
|
||||
* Copyright (c) 2007, Sangoma Technologies
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
* ============================================================================
|
||||
* Oct 04, 2005 Nenad Corbic Initial version.
|
||||
*
|
||||
* Jul 25, 2006 David Rokhvarg <davidr@sangoma.com> Ported to Windows.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __WANPIPE_TDM_API_IFACE_H_
|
||||
#define __WANPIPE_TDM_API_IFACE_H_
|
||||
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
typedef HANDLE sng_fd_t;
|
||||
#else
|
||||
typedef int sng_fd_t;
|
||||
#endif
|
||||
|
||||
enum wanpipe_tdm_api_cmds {
|
||||
|
||||
SIOC_WP_TDM_GET_USR_MTU_MRU, /* 0x00 */
|
||||
|
||||
SIOC_WP_TDM_SET_USR_PERIOD, /* 0x01 */
|
||||
SIOC_WP_TDM_GET_USR_PERIOD, /* 0x02 */
|
||||
|
||||
SIOC_WP_TDM_SET_HW_MTU_MRU, /* 0x03 */
|
||||
SIOC_WP_TDM_GET_HW_MTU_MRU, /* 0x04 */
|
||||
|
||||
SIOC_WP_TDM_SET_CODEC, /* 0x05 */
|
||||
SIOC_WP_TDM_GET_CODEC, /* 0x06 */
|
||||
|
||||
SIOC_WP_TDM_SET_POWER_LEVEL, /* 0x07 */
|
||||
SIOC_WP_TDM_GET_POWER_LEVEL, /* 0x08 */
|
||||
|
||||
SIOC_WP_TDM_TOGGLE_RX, /* 0x09 */
|
||||
SIOC_WP_TDM_TOGGLE_TX, /* 0x0A */
|
||||
|
||||
SIOC_WP_TDM_GET_HW_CODING, /* 0x0B */
|
||||
SIOC_WP_TDM_SET_HW_CODING, /* 0x0C */
|
||||
|
||||
SIOC_WP_TDM_GET_FULL_CFG, /* 0x0D */
|
||||
|
||||
SIOC_WP_TDM_SET_EC_TAP, /* 0x0E */
|
||||
SIOC_WP_TDM_GET_EC_TAP, /* 0x0F */
|
||||
|
||||
SIOC_WP_TDM_ENABLE_RBS_EVENTS, /* 0x10 */
|
||||
SIOC_WP_TDM_DISABLE_RBS_EVENTS, /* 0x11 */
|
||||
SIOC_WP_TDM_WRITE_RBS_BITS, /* 0x12 */
|
||||
|
||||
SIOC_WP_TDM_GET_STATS, /* 0x13 */
|
||||
SIOC_WP_TDM_FLUSH_BUFFERS, /* 0x14 */
|
||||
|
||||
SIOC_WP_TDM_READ_EVENT, /* 0x15 */
|
||||
|
||||
SIOC_WP_TDM_SET_EVENT,
|
||||
|
||||
SIOC_WP_TDM_SET_RX_GAINS,
|
||||
SIOC_WP_TDM_SET_TX_GAINS,
|
||||
SIOC_WP_TDM_CLEAR_RX_GAINS,
|
||||
SIOC_WP_TDM_CLEAR_TX_GAINS,
|
||||
|
||||
SIOC_WP_TDM_GET_FE_ALARMS,
|
||||
|
||||
SIOC_WP_TDM_ENABLE_HWEC,
|
||||
SIOC_WP_TDM_DISABLE_HWEC,
|
||||
|
||||
SIOC_WP_TDM_NOTSUPP /* */
|
||||
|
||||
|
||||
};
|
||||
|
||||
enum wanpipe_tdm_api_events {
|
||||
WP_TDMAPI_EVENT_NONE,
|
||||
WP_TDMAPI_EVENT_RBS,
|
||||
WP_TDMAPI_EVENT_ALARM,
|
||||
WP_TDMAPI_EVENT_DTMF,
|
||||
WP_TDMAPI_EVENT_RM_DTMF,
|
||||
WP_TDMAPI_EVENT_RXHOOK,
|
||||
WP_TDMAPI_EVENT_RING,
|
||||
WP_TDMAPI_EVENT_RING_DETECT,
|
||||
WP_TDMAPI_EVENT_RING_TRIP_DETECT,
|
||||
WP_TDMAPI_EVENT_TONE,
|
||||
WP_TDMAPI_EVENT_TXSIG_KEWL,
|
||||
WP_TDMAPI_EVENT_TXSIG_START,
|
||||
WP_TDMAPI_EVENT_TXSIG_OFFHOOK,
|
||||
WP_TDMAPI_EVENT_TXSIG_ONHOOK,
|
||||
WP_TDMAPI_EVENT_ONHOOKTRANSFER,
|
||||
WP_TDMAPI_EVENT_SETPOLARITY
|
||||
};
|
||||
|
||||
#define WP_TDMAPI_EVENT_ENABLE 0x01
|
||||
#define WP_TDMAPI_EVENT_DISABLE 0x02
|
||||
#define WP_TDMAPI_EVENT_MODE_DECODE(mode) \
|
||||
((mode) == WP_TDMAPI_EVENT_ENABLE) ? "Enable" : \
|
||||
((mode) == WP_TDMAPI_EVENT_DISABLE) ? "Disable" : \
|
||||
"(Unknown mode)"
|
||||
|
||||
#define WPTDM_A_BIT WAN_RBS_SIG_A
|
||||
#define WPTDM_B_BIT WAN_RBS_SIG_B
|
||||
#define WPTDM_C_BIT WAN_RBS_SIG_C
|
||||
#define WPTDM_D_BIT WAN_RBS_SIG_D
|
||||
|
||||
#define WP_TDMAPI_EVENT_RXHOOK_OFF 0x01
|
||||
#define WP_TDMAPI_EVENT_RXHOOK_ON 0x02
|
||||
#define WP_TDMAPI_EVENT_RXHOOK_DECODE(state) \
|
||||
((state) == WP_TDMAPI_EVENT_RXHOOK_OFF) ? "Off-hook" : \
|
||||
((state) == WP_TDMAPI_EVENT_RXHOOK_ON) ? "On-hook" : \
|
||||
"(Unknown state)"
|
||||
|
||||
#define WP_TDMAPI_EVENT_RING_PRESENT 0x01
|
||||
#define WP_TDMAPI_EVENT_RING_STOP 0x02
|
||||
#define WP_TDMAPI_EVENT_RING_DECODE(state) \
|
||||
((state) == WP_TDMAPI_EVENT_RING_PRESENT) ? "Ring Present" : \
|
||||
((state) == WP_TDMAPI_EVENT_RING_STOP) ? "Ring Stop" : \
|
||||
"(Unknown state)"
|
||||
|
||||
#define WP_TDMAPI_EVENT_RING_TRIP_PRESENT 0x01
|
||||
#define WP_TDMAPI_EVENT_RING_TRIP_STOP 0x02
|
||||
#define WP_TDMAPI_EVENT_RING_TRIP_DECODE(state) \
|
||||
((state) == WP_TDMAPI_EVENT_RING_TRIP_PRESENT) ? "Ring Present" : \
|
||||
((state) == WP_TDMAPI_EVENT_RING_TRIP_STOP) ? "Ring Stop" : \
|
||||
"(Unknown state)"
|
||||
|
||||
#define WP_TDMAPI_EVENT_TONE_DIAL 0x01
|
||||
#define WP_TDMAPI_EVENT_TONE_BUSY 0x02
|
||||
#define WP_TDMAPI_EVENT_TONE_RING 0x03
|
||||
#define WP_TDMAPI_EVENT_TONE_CONGESTION 0x04
|
||||
|
||||
typedef struct {
|
||||
|
||||
uint8_t type;
|
||||
uint8_t mode;
|
||||
uint32_t time_stamp;
|
||||
uint16_t channel;
|
||||
uint32_t chan_map;
|
||||
union {
|
||||
struct {
|
||||
uint8_t alarm;
|
||||
} te1_alarm;
|
||||
struct {
|
||||
uint8_t rbs_bits;
|
||||
} te1_rbs;
|
||||
struct {
|
||||
uint8_t state;
|
||||
uint8_t sig;
|
||||
} rm_hook;
|
||||
struct {
|
||||
uint8_t state;
|
||||
} rm_ring;
|
||||
struct {
|
||||
uint8_t type;
|
||||
} rm_tone;
|
||||
struct {
|
||||
uint8_t digit; /* DTMF: digit */
|
||||
uint8_t port; /* DTMF: SOUT/ROUT */
|
||||
uint8_t type; /* DTMF: PRESET/STOP */
|
||||
} dtmf;
|
||||
struct {
|
||||
uint16_t polarity;
|
||||
uint16_t ohttimer;
|
||||
} rm_common;
|
||||
} wp_tdm_api_event_u;
|
||||
#define wp_tdm_api_event_type type
|
||||
#define wp_tdm_api_event_mode mode
|
||||
#define wp_tdm_api_event_alarm wp_tdm_api_event_u.te1_alarm.alarm
|
||||
#define wp_tdm_api_event_alarm wp_tdm_api_event_u.te1_alarm.alarm
|
||||
#define wp_tdm_api_event_rbs_bits wp_tdm_api_event_u.te1_rbs.rbs_bits
|
||||
#define wp_tdm_api_event_hook_state wp_tdm_api_event_u.rm_hook.state
|
||||
#define wp_tdm_api_event_hook_sig wp_tdm_api_event_u.rm_hook.sig
|
||||
#define wp_tdm_api_event_ring_state wp_tdm_api_event_u.rm_ring.state
|
||||
#define wp_tdm_api_event_tone_type wp_tdm_api_event_u.rm_tone.type
|
||||
#define wp_tdm_api_event_dtmf_digit wp_tdm_api_event_u.dtmf.digit
|
||||
#define wp_tdm_api_event_dtmf_type wp_tdm_api_event_u.dtmf.type
|
||||
#define wp_tdm_api_event_dtmf_port wp_tdm_api_event_u.dtmf.port
|
||||
#define wp_tdm_api_event_ohttimer wp_tdm_api_event_u.rm_common.ohttimer
|
||||
#define wp_tdm_api_event_polarity wp_tdm_api_event_u.rm_common.polarity
|
||||
} wp_tdm_api_event_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
unsigned char reserved[16];
|
||||
}wp_rx_hdr_u;
|
||||
} wp_tdm_api_rx_hdr_t;
|
||||
|
||||
typedef struct {
|
||||
wp_tdm_api_rx_hdr_t hdr;
|
||||
unsigned char data[1];
|
||||
} wp_tdm_api_rx_element_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
unsigned char _rbs_rx_bits;
|
||||
unsigned int _time_stamp;
|
||||
}wp_tx;
|
||||
unsigned char reserved[16];
|
||||
}wp_tx_hdr_u;
|
||||
#define wp_api_time_stamp wp_tx_hdr_u.wp_tx._time_stamp
|
||||
} wp_tdm_api_tx_hdr_t;
|
||||
|
||||
typedef struct {
|
||||
wp_tdm_api_tx_hdr_t hdr;
|
||||
unsigned char data[1];
|
||||
} wp_tdm_api_tx_element_t;
|
||||
|
||||
|
||||
|
||||
typedef struct wp_tdm_chan_stats
|
||||
{
|
||||
unsigned int rx_packets; /* total packets received */
|
||||
unsigned int tx_packets; /* total packets transmitted */
|
||||
unsigned int rx_bytes; /* total bytes received */
|
||||
unsigned int tx_bytes; /* total bytes transmitted */
|
||||
unsigned int rx_errors; /* bad packets received */
|
||||
unsigned int tx_errors; /* packet transmit problems */
|
||||
unsigned int rx_dropped; /* no space in linux buffers */
|
||||
unsigned int tx_dropped; /* no space available in linux */
|
||||
unsigned int multicast; /* multicast packets received */
|
||||
#if !defined(__WINDOWS__)
|
||||
unsigned int collisions;
|
||||
#endif
|
||||
/* detailed rx_errors: */
|
||||
unsigned int rx_length_errors;
|
||||
unsigned int rx_over_errors; /* receiver ring buff overflow */
|
||||
unsigned int rx_crc_errors; /* recved pkt with crc error */
|
||||
unsigned int rx_frame_errors; /* recv'd frame alignment error */
|
||||
#if !defined(__WINDOWS__)
|
||||
unsigned int rx_fifo_errors; /* recv'r fifo overrun */
|
||||
#endif
|
||||
unsigned int rx_missed_errors; /* receiver missed packet */
|
||||
|
||||
/* detailed tx_errors */
|
||||
#if !defined(__WINDOWS__)
|
||||
unsigned int tx_aborted_errors;
|
||||
unsigned int tx_carrier_errors;
|
||||
#endif
|
||||
unsigned int tx_fifo_errors;
|
||||
unsigned int tx_heartbeat_errors;
|
||||
unsigned int tx_window_errors;
|
||||
|
||||
}wp_tdm_chan_stats_t;
|
||||
|
||||
|
||||
|
||||
typedef struct wanpipe_tdm_api_cmd{
|
||||
unsigned int cmd;
|
||||
unsigned int hw_tdm_coding; /* Set/Get HW TDM coding: uLaw muLaw */
|
||||
unsigned int hw_mtu_mru; /* Set/Get HW TDM MTU/MRU */
|
||||
unsigned int usr_period; /* Set/Get User Period in ms */
|
||||
unsigned int tdm_codec; /* Set/Get TDM Codec: SLinear */
|
||||
unsigned int power_level; /* Set/Get Power level treshold */
|
||||
unsigned int rx_disable; /* Enable/Disable Rx */
|
||||
unsigned int tx_disable; /* Enable/Disable Tx */
|
||||
unsigned int usr_mtu_mru; /* Set/Get User TDM MTU/MRU */
|
||||
unsigned int ec_tap; /* Echo Cancellation Tap */
|
||||
unsigned int rbs_poll; /* Enable/Disable RBS Polling */
|
||||
unsigned int rbs_rx_bits; /* Rx RBS Bits */
|
||||
unsigned int rbs_tx_bits; /* Tx RBS Bits */
|
||||
unsigned int hdlc; /* HDLC based device */
|
||||
unsigned int idle_flag; /* IDLE flag to Tx */
|
||||
unsigned int fe_alarms; /* FE Alarms detected */
|
||||
wp_tdm_chan_stats_t stats; /* TDM Statistics */
|
||||
wp_tdm_api_event_t event; /* TDM Event */
|
||||
unsigned int data_len;
|
||||
void *data;
|
||||
}wanpipe_tdm_api_cmd_t;
|
||||
|
||||
typedef struct wanpipe_tdm_api_event{
|
||||
int (*wp_rbs_event)(sng_fd_t fd, unsigned char rbs_bits);
|
||||
int (*wp_dtmf_event)(sng_fd_t fd, unsigned char dtmf, unsigned char type, unsigned char port);
|
||||
int (*wp_rxhook_event)(sng_fd_t fd, unsigned char hook_state);
|
||||
int (*wp_ring_detect_event)(sng_fd_t fd, unsigned char ring_state);
|
||||
int (*wp_ring_trip_detect_event)(sng_fd_t fd, unsigned char ring_state);
|
||||
int (*wp_fe_alarm_event)(sng_fd_t fd, unsigned char fe_alarm_event);
|
||||
}wanpipe_tdm_api_event_t;
|
||||
|
||||
typedef struct wanpipe_tdm_api{
|
||||
wanpipe_tdm_api_cmd_t wp_tdm_cmd;
|
||||
wanpipe_tdm_api_event_t wp_tdm_event;
|
||||
}wanpipe_tdm_api_t;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,798 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "openzap.h"
|
||||
#include "ozmod_zt.h"
|
||||
|
||||
|
||||
static struct {
|
||||
uint32_t codec_ms;
|
||||
uint32_t wink_ms;
|
||||
uint32_t flash_ms;
|
||||
uint32_t eclevel;
|
||||
uint32_t etlevel;
|
||||
} zt_globals;
|
||||
|
||||
#define ZT_INVALID_SOCKET -1
|
||||
static const char ctlpath[] = "/dev/zap/ctl";
|
||||
static zap_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
|
||||
|
||||
ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
|
||||
ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
|
||||
|
||||
static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number)
|
||||
{
|
||||
unsigned configured = 0, x;
|
||||
char path[] = "/dev/zap/channel";
|
||||
zt_params_t ztp;
|
||||
|
||||
memset(&ztp, 0, sizeof(ztp));
|
||||
|
||||
for(x = start; x < end; x++) {
|
||||
zap_channel_t *zchan;
|
||||
zap_socket_t sockfd = ZT_INVALID_SOCKET;
|
||||
int len;
|
||||
|
||||
sockfd = open(path, O_RDWR);
|
||||
if (sockfd != ZT_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &zchan) == ZAP_SUCCESS) {
|
||||
|
||||
if (ioctl(sockfd, ZT_SPECIFY, &x)) {
|
||||
zap_log(ZAP_LOG_ERROR, "failure configuring device %s chan %d fd %d (%s)\n", path, x, sockfd, strerror(errno));
|
||||
close(sockfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
|
||||
struct zt_bufferinfo binfo;
|
||||
memset(&binfo, 0, sizeof(binfo));
|
||||
binfo.txbufpolicy = 0;
|
||||
binfo.rxbufpolicy = 0;
|
||||
binfo.numbufs = 32;
|
||||
binfo.bufsize = 1024;
|
||||
if (ioctl(sockfd, ZT_SET_BUFINFO, &binfo)) {
|
||||
zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", path, zchan->span_id, zchan->chan_id, sockfd);
|
||||
close(sockfd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
|
||||
struct zt_chanconfig cc;
|
||||
memset(&cc, 0, sizeof(cc));
|
||||
cc.chan = cc.master = x;
|
||||
|
||||
switch(type) {
|
||||
case ZAP_CHAN_TYPE_FXS:
|
||||
{
|
||||
switch(span->start_type) {
|
||||
case ZAP_ANALOG_START_KEWL:
|
||||
cc.sigtype = ZT_SIG_FXOKS;
|
||||
break;
|
||||
case ZAP_ANALOG_START_LOOP:
|
||||
cc.sigtype = ZT_SIG_FXOLS;
|
||||
break;
|
||||
case ZAP_ANALOG_START_GROUND:
|
||||
cc.sigtype = ZT_SIG_FXOGS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHAN_TYPE_FXO:
|
||||
{
|
||||
switch(span->start_type) {
|
||||
case ZAP_ANALOG_START_KEWL:
|
||||
cc.sigtype = ZT_SIG_FXSKS;
|
||||
break;
|
||||
case ZAP_ANALOG_START_LOOP:
|
||||
cc.sigtype = ZT_SIG_FXSLS;
|
||||
break;
|
||||
case ZAP_ANALOG_START_GROUND:
|
||||
cc.sigtype = ZT_SIG_FXSGS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ioctl(CONTROL_FD, ZT_CHANCONFIG, &cc)) {
|
||||
zap_log(ZAP_LOG_WARNING, "this ioctl fails on older zaptel but is harmless if you used ztcfg\n[device %s chan %d fd %d (%s)]\n", path, x, CONTROL_FD, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (zchan->type != ZAP_CHAN_TYPE_DQ921 && zchan->type != ZAP_CHAN_TYPE_DQ931) {
|
||||
len = zt_globals.codec_ms * 8;
|
||||
if (ioctl(zchan->sockfd, ZT_SET_BLOCKSIZE, &len)) {
|
||||
zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d err:%s\n",
|
||||
path, zchan->span_id, zchan->chan_id, sockfd, strerror(errno));
|
||||
close(sockfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
zchan->packet_len = len;
|
||||
zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8;
|
||||
|
||||
if (zchan->effective_codec == ZAP_CODEC_SLIN) {
|
||||
zchan->packet_len *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(sockfd, ZT_GET_PARAMS, &ztp) < 0) {
|
||||
zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", path, zchan->span_id, zchan->chan_id, sockfd);
|
||||
close(sockfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
|
||||
if ((ztp.sig_type != ZT_SIG_HDLCRAW) && (ztp.sig_type != ZT_SIG_HDLCFCS)) {
|
||||
zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", path, zchan->span_id, zchan->chan_id, sockfd);
|
||||
close(sockfd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
zap_log(ZAP_LOG_INFO, "configuring device %s channel %d as OpenZAP device %d:%d fd:%d\n", path, x, zchan->span_id, zchan->chan_id, sockfd);
|
||||
|
||||
zchan->rate = 8000;
|
||||
zchan->physical_span_id = ztp.span_no;
|
||||
zchan->physical_chan_id = ztp.chan_no;
|
||||
|
||||
if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO || type == ZAP_CHAN_TYPE_B) {
|
||||
if (ztp.g711_type == ZT_G711_ALAW) {
|
||||
zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ALAW;
|
||||
} else if (ztp.g711_type == ZT_G711_MULAW) {
|
||||
zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ULAW;
|
||||
} else {
|
||||
int type;
|
||||
|
||||
if (zchan->span->trunk_type == ZAP_TRUNK_E1) {
|
||||
type = ZAP_CODEC_ALAW;
|
||||
} else {
|
||||
type = ZAP_CODEC_ULAW;
|
||||
}
|
||||
|
||||
zchan->native_codec = zchan->effective_codec = type;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ztp.wink_time = zt_globals.wink_ms;
|
||||
ztp.flash_time = zt_globals.flash_ms;
|
||||
|
||||
if (ioctl(sockfd, ZT_SET_PARAMS, &ztp) < 0) {
|
||||
zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", path, zchan->span_id, zchan->chan_id, sockfd);
|
||||
close(sockfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!zap_strlen_zero(name)) {
|
||||
zap_copy_string(zchan->chan_name, name, sizeof(zchan->chan_name));
|
||||
}
|
||||
if (!zap_strlen_zero(number)) {
|
||||
zap_copy_string(zchan->chan_number, number, sizeof(zchan->chan_number));
|
||||
}
|
||||
configured++;
|
||||
} else {
|
||||
zap_log(ZAP_LOG_ERROR, "failure configuring device %s\n", path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return configured;
|
||||
}
|
||||
|
||||
static ZIO_CONFIGURE_SPAN_FUNCTION(zt_configure_span)
|
||||
{
|
||||
|
||||
int items, i;
|
||||
char *mydata, *item_list[10];
|
||||
char *ch, *mx;
|
||||
int channo;
|
||||
int top = 0;
|
||||
unsigned configured = 0;
|
||||
|
||||
assert(str != NULL);
|
||||
|
||||
|
||||
mydata = strdup(str);
|
||||
assert(mydata != NULL);
|
||||
|
||||
|
||||
items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
|
||||
|
||||
for(i = 0; i < items; i++) {
|
||||
ch = item_list[i];
|
||||
|
||||
if (!(ch)) {
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid input\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
channo = atoi(ch);
|
||||
|
||||
if (channo < 0) {
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((mx = strchr(ch, '-'))) {
|
||||
mx++;
|
||||
top = atoi(mx) + 1;
|
||||
} else {
|
||||
top = channo + 1;
|
||||
}
|
||||
|
||||
|
||||
if (top < 0) {
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
|
||||
continue;
|
||||
}
|
||||
|
||||
configured += zt_open_range(span, channo, top, type, name, number);
|
||||
|
||||
}
|
||||
|
||||
free(mydata);
|
||||
|
||||
return configured;
|
||||
|
||||
}
|
||||
|
||||
static ZIO_CONFIGURE_FUNCTION(zt_configure)
|
||||
{
|
||||
|
||||
int num;
|
||||
|
||||
if (!strcasecmp(category, "defaults")) {
|
||||
if (!strcasecmp(var, "codec_ms")) {
|
||||
num = atoi(val);
|
||||
if (num < 10 || num > 60) {
|
||||
zap_log(ZAP_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
|
||||
} else {
|
||||
zt_globals.codec_ms = num;
|
||||
}
|
||||
} else if (!strcasecmp(var, "wink_ms")) {
|
||||
num = atoi(val);
|
||||
if (num < 50 || num > 3000) {
|
||||
zap_log(ZAP_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
|
||||
} else {
|
||||
zt_globals.wink_ms = num;
|
||||
}
|
||||
} else if (!strcasecmp(var, "flash_ms")) {
|
||||
num = atoi(val);
|
||||
if (num < 50 || num > 3000) {
|
||||
zap_log(ZAP_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
|
||||
} else {
|
||||
zt_globals.flash_ms = num;
|
||||
}
|
||||
} else if (!strcasecmp(var, "echo_cancel_level")) {
|
||||
num = atoi(val);
|
||||
if (num < 0 || num > 256) {
|
||||
zap_log(ZAP_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
|
||||
} else {
|
||||
zt_globals.eclevel = num;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_OPEN_FUNCTION(zt_open)
|
||||
{
|
||||
zap_channel_set_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL);
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_DQ921 || zchan->type == ZAP_CHAN_TYPE_DQ931) {
|
||||
zchan->native_codec = zchan->effective_codec = ZAP_CODEC_NONE;
|
||||
} else {
|
||||
int blocksize = zt_globals.codec_ms * (zchan->rate / 1000);
|
||||
int err;
|
||||
if ((err = ioctl(zchan->sockfd, ZT_SET_BLOCKSIZE, &blocksize))) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
} else {
|
||||
zchan->effective_interval = zchan->native_interval;
|
||||
zchan->packet_len = blocksize;
|
||||
zchan->native_codec = zchan->effective_codec;
|
||||
}
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_B) {
|
||||
int one = 1;
|
||||
if (ioctl(zchan->sockfd, ZT_AUDIOMODE, &one)) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
||||
zap_log(ZAP_LOG_ERROR, "%s\n", zchan->last_error);
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
} else if (zchan->type == ZAP_CHAN_TYPE_FXS || zchan->type == ZAP_CHAN_TYPE_FXO) {
|
||||
int len = zt_globals.eclevel;
|
||||
if (ioctl(zchan->sockfd, ZT_ECHOCANCEL, &len)) {
|
||||
zap_log(ZAP_LOG_WARNING, "Echo cancel not available for %d:%d\n", zchan->span_id, zchan->chan_id);
|
||||
//snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
||||
//zap_log(ZAP_LOG_ERROR, "%s\n", zchan->last_error);
|
||||
//return ZAP_FAIL;
|
||||
} else {
|
||||
len = zt_globals.etlevel;
|
||||
if (ioctl(zchan->sockfd, ZT_ECHOTRAIN, &len)) {
|
||||
zap_log(ZAP_LOG_WARNING, "Echo training not available for %d:%d\n", zchan->span_id, zchan->chan_id);
|
||||
//snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
||||
//zap_log(ZAP_LOG_ERROR, "%s\n", zchan->last_error);
|
||||
//return ZAP_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_CLOSE_FUNCTION(zt_close)
|
||||
{
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_COMMAND_FUNCTION(zt_command)
|
||||
{
|
||||
zt_params_t ztp;
|
||||
int err = 0;
|
||||
|
||||
memset(&ztp, 0, sizeof(ztp));
|
||||
|
||||
switch(command) {
|
||||
case ZAP_COMMAND_ENABLE_ECHOCANCEL:
|
||||
{
|
||||
int level = ZAP_COMMAND_OBJ_INT;
|
||||
err = ioctl(zchan->sockfd, ZT_ECHOCANCEL, &level);
|
||||
ZAP_COMMAND_OBJ_INT = level;
|
||||
}
|
||||
case ZAP_COMMAND_DISABLE_ECHOCANCEL:
|
||||
{
|
||||
int level = 0;
|
||||
err = ioctl(zchan->sockfd, ZT_ECHOCANCEL, &level);
|
||||
ZAP_COMMAND_OBJ_INT = level;
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_ENABLE_ECHOTRAIN:
|
||||
{
|
||||
int level = ZAP_COMMAND_OBJ_INT;
|
||||
err = ioctl(zchan->sockfd, ZT_ECHOTRAIN, &level);
|
||||
ZAP_COMMAND_OBJ_INT = level;
|
||||
}
|
||||
case ZAP_COMMAND_DISABLE_ECHOTRAIN:
|
||||
{
|
||||
int level = 0;
|
||||
err = ioctl(zchan->sockfd, ZT_ECHOTRAIN, &level);
|
||||
ZAP_COMMAND_OBJ_INT = level;
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_OFFHOOK:
|
||||
{
|
||||
int command = ZT_OFFHOOK;
|
||||
if (ioctl(zchan->sockfd, ZT_HOOK, &command)) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "OFFHOOK Failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_ONHOOK:
|
||||
{
|
||||
int command = ZT_ONHOOK;
|
||||
if (ioctl(zchan->sockfd, ZT_HOOK, &command)) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "ONHOOK Failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_GENERATE_RING_ON:
|
||||
{
|
||||
int command = ZT_RING;
|
||||
if (ioctl(zchan->sockfd, ZT_HOOK, &command)) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING);
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_GENERATE_RING_OFF:
|
||||
{
|
||||
int command = ZT_RINGOFF;
|
||||
if (ioctl(zchan->sockfd, ZT_HOOK, &command)) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_GET_INTERVAL:
|
||||
{
|
||||
|
||||
if (!(err = ioctl(zchan->sockfd, ZT_GET_BLOCKSIZE, &zchan->packet_len))) {
|
||||
zchan->native_interval = zchan->packet_len / 8;
|
||||
if (zchan->effective_codec == ZAP_CODEC_SLIN) {
|
||||
zchan->packet_len *= 2;
|
||||
}
|
||||
ZAP_COMMAND_OBJ_INT = zchan->native_interval;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_SET_INTERVAL:
|
||||
{
|
||||
int interval = ZAP_COMMAND_OBJ_INT;
|
||||
int len = interval * 8;
|
||||
|
||||
if (!(err = ioctl(zchan->sockfd, ZT_SET_BLOCKSIZE, &len))) {
|
||||
zchan->packet_len = len;
|
||||
zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8;
|
||||
|
||||
if (zchan->effective_codec == ZAP_CODEC_SLIN) {
|
||||
zchan->packet_len *= 2;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
if (err) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_GET_ALARMS_FUNCTION(zt_get_alarms)
|
||||
{
|
||||
struct zt_spaninfo info;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.span_no = zchan->physical_span_id;
|
||||
|
||||
if (ioctl(CONTROL_FD, ZT_SPANSTAT, &info)) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "ioctl failed (%s)", strerror(errno));
|
||||
snprintf(zchan->span->last_error, sizeof(zchan->span->last_error), "ioctl failed (%s)", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
zchan->alarm_flags = info.alarms;
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static ZIO_WAIT_FUNCTION(zt_wait)
|
||||
{
|
||||
int32_t inflags = 0;
|
||||
int result;
|
||||
struct pollfd pfds[1];
|
||||
|
||||
if (*flags & ZAP_READ) {
|
||||
inflags |= POLLIN;
|
||||
}
|
||||
|
||||
if (*flags & ZAP_WRITE) {
|
||||
inflags |= POLLOUT;
|
||||
}
|
||||
|
||||
if (*flags & ZAP_EVENTS) {
|
||||
inflags |= POLLPRI;
|
||||
}
|
||||
|
||||
|
||||
memset(&pfds[0], 0, sizeof(pfds[0]));
|
||||
pfds[0].fd = zchan->sockfd;
|
||||
pfds[0].events = inflags;
|
||||
result = poll(pfds, 1, to);
|
||||
*flags = 0;
|
||||
|
||||
if (pfds[0].revents & POLLERR) {
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if (result > 0) {
|
||||
inflags = pfds[0].revents;
|
||||
}
|
||||
|
||||
*flags = ZAP_NO_FLAGS;
|
||||
|
||||
if (result < 0){
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "Poll failed");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
return ZAP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (inflags & POLLIN) {
|
||||
*flags |= ZAP_READ;
|
||||
}
|
||||
|
||||
if (inflags & POLLOUT) {
|
||||
*flags |= ZAP_WRITE;
|
||||
}
|
||||
|
||||
if (inflags & POLLPRI) {
|
||||
*flags |= ZAP_EVENTS;
|
||||
}
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
|
||||
{
|
||||
struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
|
||||
uint32_t i, j = 0, k = 0;
|
||||
int r;
|
||||
|
||||
for(i = 1; i <= span->chan_count; i++) {
|
||||
memset(&pfds[j], 0, sizeof(pfds[j]));
|
||||
pfds[j].fd = span->channels[i].sockfd;
|
||||
pfds[j].events = POLLPRI;
|
||||
j++;
|
||||
}
|
||||
|
||||
r = poll(pfds, j, ms);
|
||||
|
||||
if (r == 0) {
|
||||
return ZAP_TIMEOUT;
|
||||
} else if (r < 0 || (pfds[i-1].revents & POLLERR)) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
for(i = 1; i <= span->chan_count; i++) {
|
||||
if (pfds[i-1].revents & POLLPRI) {
|
||||
zap_set_flag((&span->channels[i]), ZAP_CHANNEL_EVENT);
|
||||
span->channels[i].last_event_time = zap_current_time_in_ms();
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!k) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "no matching descriptor");
|
||||
}
|
||||
|
||||
return k ? ZAP_SUCCESS : ZAP_FAIL;
|
||||
}
|
||||
|
||||
ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
|
||||
{
|
||||
uint32_t i, event_id = 0;
|
||||
zap_oob_event_t zt_event_id = 0;
|
||||
|
||||
for(i = 1; i <= span->chan_count; i++) {
|
||||
if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) {
|
||||
zap_clear_flag((&span->channels[i]), ZAP_CHANNEL_EVENT);
|
||||
if (ioctl(span->channels[i].sockfd, ZT_GETEVENT, &zt_event_id) == -1) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
switch(zt_event_id) {
|
||||
case ZT_EVENT_RINGEROFF:
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGERON:
|
||||
{
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGBEGIN:
|
||||
{
|
||||
event_id = ZAP_OOB_RING_START;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_ONHOOK:
|
||||
{
|
||||
event_id = ZAP_OOB_ONHOOK;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_WINKFLASH:
|
||||
{
|
||||
if (span->channels[i].state == ZAP_CHANNEL_STATE_DOWN) {
|
||||
event_id = ZAP_OOB_WINK;
|
||||
} else {
|
||||
event_id = ZAP_OOB_FLASH;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGOFFHOOK:
|
||||
{
|
||||
if (span->channels[i].type == ZAP_CHAN_TYPE_FXS) {
|
||||
zap_set_flag_locked((&span->channels[i]), ZAP_CHANNEL_OFFHOOK);
|
||||
event_id = ZAP_OOB_OFFHOOK;
|
||||
} else if (span->channels[i].type == ZAP_CHAN_TYPE_FXO) {
|
||||
event_id = ZAP_OOB_RING_START;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_ALARM:
|
||||
{
|
||||
event_id = ZAP_OOB_ALARM_TRAP;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_NOALARM:
|
||||
{
|
||||
event_id = ZAP_OOB_ALARM_CLEAR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
|
||||
event_id = ZAP_OOB_INVALID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
span->channels[i].last_event_time = 0;
|
||||
span->event_header.e_type = ZAP_EVENT_OOB;
|
||||
span->event_header.enum_id = event_id;
|
||||
span->event_header.channel = &span->channels[i];
|
||||
*event = &span->event_header;
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return ZAP_FAIL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static ZIO_READ_FUNCTION(zt_read)
|
||||
{
|
||||
zap_ssize_t r = 0;
|
||||
int errs = 0;
|
||||
|
||||
while (errs++ < 100) {
|
||||
if ((r = read(zchan->sockfd, data, *datalen)) > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
*datalen = r;
|
||||
if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
|
||||
*datalen -= 2;
|
||||
}
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_WRITE_FUNCTION(zt_write)
|
||||
{
|
||||
zap_ssize_t w = 0;
|
||||
zap_size_t bytes = *datalen;
|
||||
|
||||
if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
|
||||
memset(data+bytes, 0, 2);
|
||||
bytes += 2;
|
||||
}
|
||||
|
||||
w = write(zchan->sockfd, data, bytes);
|
||||
|
||||
if (w >= 0) {
|
||||
*datalen = w;
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
static ZIO_CHANNEL_DESTROY_FUNCTION(zt_channel_destroy)
|
||||
{
|
||||
close(zchan->sockfd);
|
||||
zchan->sockfd = ZT_INVALID_SOCKET;
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static zap_io_interface_t zt_interface;
|
||||
|
||||
static ZIO_IO_LOAD_FUNCTION(zt_init)
|
||||
{
|
||||
assert(zio != NULL);
|
||||
memset(&zt_interface, 0, sizeof(zt_interface));
|
||||
memset(&zt_globals, 0, sizeof(zt_globals));
|
||||
|
||||
if ((CONTROL_FD = open(ctlpath, O_RDWR)) < 0) {
|
||||
zap_log(ZAP_LOG_ERROR, "Cannot open control device\n");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
zt_globals.codec_ms = 20;
|
||||
zt_globals.wink_ms = 150;
|
||||
zt_globals.flash_ms = 750;
|
||||
zt_globals.eclevel = 64;
|
||||
zt_globals.etlevel = 0;
|
||||
|
||||
zt_interface.name = "zt";
|
||||
zt_interface.configure = zt_configure;
|
||||
zt_interface.configure_span = zt_configure_span;
|
||||
zt_interface.open = zt_open;
|
||||
zt_interface.close = zt_close;
|
||||
zt_interface.command = zt_command;
|
||||
zt_interface.wait = zt_wait;
|
||||
zt_interface.read = zt_read;
|
||||
zt_interface.write = zt_write;
|
||||
zt_interface.poll_event = zt_poll_event;
|
||||
zt_interface.next_event = zt_next_event;
|
||||
zt_interface.channel_destroy = zt_channel_destroy;
|
||||
zt_interface.get_alarms = zt_get_alarms;
|
||||
*zio = &zt_interface;
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static ZIO_IO_UNLOAD_FUNCTION(zt_destroy)
|
||||
{
|
||||
close(CONTROL_FD);
|
||||
memset(&zt_interface, 0, sizeof(zt_interface));
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
zap_module_t zap_module = {
|
||||
"zt",
|
||||
zt_init,
|
||||
zt_destroy,
|
||||
};
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ZAP_ZT_H
|
||||
#define ZAP_ZT_H
|
||||
#include "openzap.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <poll.h>
|
||||
|
||||
#ifdef __sun
|
||||
#include <unistd.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <stropts.h>
|
||||
#endif
|
||||
|
||||
/* Hardware interface structures and defines */
|
||||
/* Based on documentation of the structures required for the hardware interface */
|
||||
/* from http://wiki.freeswitch.org/wiki/Zapata_zaptel_interface */
|
||||
|
||||
/* Structures */
|
||||
|
||||
/* Used with ioctl: ZT_GET_PARAMS and ZT_SET_PARAMS */
|
||||
struct zt_params {
|
||||
int chan_no; /* Channel Number */
|
||||
int span_no; /* Span Number */
|
||||
int chan_position; /* Channel Position */
|
||||
int sig_type; /* Signal Type (read-only) */
|
||||
int sig_cap; /* Signal Cap (read-only) */
|
||||
int receive_offhook; /* Receive is offhook (read-only) */
|
||||
int receive_bits; /* Number of bits in receive (read-only) */
|
||||
int transmit_bits; /* Number of bits in transmit (read-only) */
|
||||
int transmit_hook_sig; /* Transmit Hook Signal (read-only) */
|
||||
int receive_hook_sig; /* Receive Hook Signal (read-only) */
|
||||
int g711_type; /* Member of zt_g711_t (read-only) */
|
||||
int idlebits; /* bits for the idle state (read-only) */
|
||||
char chan_name[40]; /* Channel Name */
|
||||
int prewink_time;
|
||||
int preflash_time;
|
||||
int wink_time;
|
||||
int flash_time;
|
||||
int start_time;
|
||||
int receive_wink_time;
|
||||
int receive_flash_time;
|
||||
int debounce_time;
|
||||
int pulse_break_time;
|
||||
int pulse_make_time;
|
||||
int pulse_after_time;
|
||||
};
|
||||
|
||||
typedef struct zt_params zt_params_t;
|
||||
|
||||
/* Used with ioctl: ZT_CONFLINK, ZT_GETCONF and ZT_SETCONF */
|
||||
struct zt_confinfo {
|
||||
int chan_no; /* Channel Number, 0 for current */
|
||||
int conference_number;
|
||||
int conference_mode;
|
||||
};
|
||||
|
||||
/* Used with ioctl: ZT_GETGAINS and ZT_SETGAINS */
|
||||
struct zt_gains {
|
||||
int chan_no; /* Channel Number, 0 for current */
|
||||
unsigned char receive_gain[256]; /* Receive gain table */
|
||||
unsigned char transmit_gain[256]; /* Transmit gain table */
|
||||
};
|
||||
|
||||
/* Used with ioctl: ZT_SPANSTAT */
|
||||
struct zt_spaninfo {
|
||||
int span_no; /* span number (-1 to use name) */
|
||||
char name[20]; /* Name of span */
|
||||
char description[40]; /* Description of span */
|
||||
int alarms; /* alarms status */
|
||||
int transmit_level; /* Transmit level */
|
||||
int receive_level; /* Receive level */
|
||||
int bpv_count; /* Current BPV count */
|
||||
int crc4_count; /* Current CRC4 error count */
|
||||
int ebit_count; /* Current E-bit error count */
|
||||
int fas_count; /* Current FAS error count */
|
||||
int irq_misses; /* Current IRQ misses */
|
||||
int sync_src; /* Span # of sync source (0 = free run) */
|
||||
int configured_chan_count; /* Count of channels configured on the span */
|
||||
int channel_count; /* Total count of channels on the span */
|
||||
int span_count; /* Total count of zaptel spans on the system*/
|
||||
};
|
||||
|
||||
struct zt_maintinfo {
|
||||
int span_no; /* span number */
|
||||
int command; /* Maintenance mode to set (from zt_maintenance_mode_t) */
|
||||
};
|
||||
|
||||
struct zt_lineconfig {
|
||||
/* Used in ZT_SPANCONFIG */
|
||||
int span; /* Which span number (0 to use name) */
|
||||
char name[20]; /* Name of span to use */
|
||||
int lbo; /* line build-outs */
|
||||
int lineconfig; /* line config parameters (framing, coding) */
|
||||
int sync; /* what level of sync source we are */
|
||||
};
|
||||
|
||||
struct zt_chanconfig {
|
||||
/* Used in ZT_CHANCONFIG */
|
||||
int chan; /* Channel we're applying this to (0 to use name) */
|
||||
char name[40]; /* Name of channel to use */
|
||||
int sigtype; /* Signal type */
|
||||
int deflaw; /* Default law (ZT_LAW_DEFAULT, ZT_LAW_MULAW, or ZT_LAW_ALAW */
|
||||
int master; /* Master channel if sigtype is ZT_SLAVE */
|
||||
int idlebits; /* Idle bits (if this is a CAS channel) or channel to monitor (if this is DACS channel) */
|
||||
char netdev_name[16]; /* name for the hdlc network device */
|
||||
};
|
||||
|
||||
struct zt_bufferinfo {
|
||||
/* used in ZT_SET_BUFINFO and ZT_GET_BUFINFO */
|
||||
int txbufpolicy; /* Policy for handling receive buffers */
|
||||
int rxbufpolicy; /* Policy for handling receive buffers */
|
||||
int numbufs; /* How many buffers to use */
|
||||
int bufsize; /* How big each buffer is */
|
||||
int readbufs; /* How many read buffers are full (read-only) */
|
||||
int writebufs; /* How many write buffers are full (read-only) */
|
||||
};
|
||||
|
||||
/* Enumerations */
|
||||
|
||||
/* Values in zt_params structure for member g711_type */
|
||||
typedef enum {
|
||||
ZT_G711_DEFAULT = 0, /* Default mulaw/alaw from the span */
|
||||
ZT_G711_MULAW = 1,
|
||||
ZT_G711_ALAW = 2
|
||||
} zt_g711_t;
|
||||
|
||||
typedef enum {
|
||||
ZT_EVENT_NONE = 0,
|
||||
ZT_EVENT_ONHOOK = 1,
|
||||
ZT_EVENT_RINGOFFHOOK = 2,
|
||||
ZT_EVENT_WINKFLASH = 3,
|
||||
ZT_EVENT_ALARM = 4,
|
||||
ZT_EVENT_NOALARM = 5,
|
||||
ZT_EVENT_ABORT = 6,
|
||||
ZT_EVENT_OVERRUN = 7,
|
||||
ZT_EVENT_BADFCS = 8,
|
||||
ZT_EVENT_DIALCOMPLETE = 9,
|
||||
ZT_EVENT_RINGERON = 10,
|
||||
ZT_EVENT_RINGEROFF = 11,
|
||||
ZT_EVENT_HOOKCOMPLETE = 12,
|
||||
ZT_EVENT_BITSCHANGED = 13,
|
||||
ZT_EVENT_PULSE_START = 14,
|
||||
ZT_EVENT_TIMER_EXPIRED = 15,
|
||||
ZT_EVENT_TIMER_PING = 16,
|
||||
ZT_EVENT_POLARITY = 17,
|
||||
ZT_EVENT_RINGBEGIN = 18
|
||||
} zt_event_t;
|
||||
|
||||
typedef enum {
|
||||
ZT_FLUSH_READ = 1,
|
||||
ZT_FLUSH_WRITE = 2,
|
||||
ZT_FLUSH_BOTH = (ZT_FLUSH_READ | ZT_FLUSH_WRITE),
|
||||
ZT_FLUSH_EVENT = 4,
|
||||
ZT_FLUSH_ALL = (ZT_FLUSH_READ | ZT_FLUSH_WRITE | ZT_FLUSH_EVENT)
|
||||
} zt_flush_t;
|
||||
|
||||
typedef enum {
|
||||
ZT_IOMUX_READ = 1,
|
||||
ZT_IOMUX_WRITE = 2,
|
||||
ZT_IOMUX_WRITEEMPTY = 4,
|
||||
ZT_IOMUX_SIGEVENT = 8,
|
||||
ZT_IOMUX_NOWAIT = 256
|
||||
} zt_iomux_t;
|
||||
|
||||
typedef enum {
|
||||
ZT_ONHOOK = 0,
|
||||
ZT_OFFHOOK = 1,
|
||||
ZT_WINK = 2,
|
||||
ZT_FLASH = 3,
|
||||
ZT_START = 4,
|
||||
ZT_RING = 5,
|
||||
ZT_RINGOFF = 6
|
||||
} zt_hookstate_t;
|
||||
|
||||
typedef enum {
|
||||
ZT_MAINT_NONE = 0, /* Normal Mode */
|
||||
ZT_MAINT_LOCALLOOP = 1, /* Local Loopback */
|
||||
ZT_MAINT_REMOTELOOP = 2, /* Remote Loopback */
|
||||
ZT_MAINT_LOOPUP = 3, /* Send Loopup Code */
|
||||
ZT_MAINT_LOOPDOWN = 4, /* Send Loopdown Code */
|
||||
ZT_MAINT_LOOPSTOP = 5 /* Stop Sending Loop Codes */
|
||||
} zt_maintenance_mode_t;
|
||||
|
||||
typedef enum {
|
||||
/* Signalling type */
|
||||
ZT_SIG_NONE = 0, /* chan not configured. */
|
||||
|
||||
ZT_SIG_FXSLS = ((1 << 0) | (1 << 13)), /* FXS, Loopstart */
|
||||
ZT_SIG_FXSGS = ((1 << 1) | (1 << 13)), /* FXS, Groundstart */
|
||||
ZT_SIG_FXSKS = ((1 << 2) | (1 << 13)), /* FXS, Kewlstart */
|
||||
ZT_SIG_FXOLS = ((1 << 3) | (1 << 12)), /* FXO, Loopstart */
|
||||
ZT_SIG_FXOGS = ((1 << 4) | (1 << 12)), /* FXO, Groupstart */
|
||||
ZT_SIG_FXOKS = ((1 << 5) | (1 << 12)), /* FXO, Kewlstart */
|
||||
ZT_SIG_EM = (1 << 6), /* E&M */
|
||||
ZT_SIG_CLEAR = (1 << 7),
|
||||
ZT_SIG_HDLCRAW = ((1 << 8) | ZT_SIG_CLEAR),
|
||||
ZT_SIG_HDLCFCS = ((1 << 9) | ZT_SIG_HDLCRAW)
|
||||
} zt_sigtype_t;
|
||||
|
||||
|
||||
/* Defines */
|
||||
|
||||
#define ZT_MAX_BLOCKSIZE 8192
|
||||
#define ZT_DEFAULT_MTU_MRU 2048
|
||||
|
||||
/* ioctl defines */
|
||||
|
||||
#define ZT_CODE 'J'
|
||||
|
||||
|
||||
#define ZT_GET_BLOCKSIZE _IOR (ZT_CODE, 1, int) /* Get Transfer Block Size. */
|
||||
#define ZT_SET_BLOCKSIZE _IOW (ZT_CODE, 2, int) /* Set Transfer Block Size. */
|
||||
#define ZT_FLUSH _IOW (ZT_CODE, 3, int) /* Flush Buffer(s) and stop I/O */
|
||||
#define ZT_SYNC _IOW (ZT_CODE, 4, int) /* Wait for Write to Finish */
|
||||
#define ZT_GET_PARAMS _IOR (ZT_CODE, 5, struct zt_params) /* Get channel parameters */
|
||||
#define ZT_SET_PARAMS _IOW (ZT_CODE, 6, struct zt_params) /* Set channel parameters */
|
||||
#define ZT_HOOK _IOW (ZT_CODE, 7, int) /* Set Hookswitch Status */
|
||||
#define ZT_GETEVENT _IOR (ZT_CODE, 8, int) /* Get Signalling Event */
|
||||
#define ZT_IOMUX _IOWR (ZT_CODE, 9, int) /* Wait for something to happen (IO Mux) */
|
||||
#define ZT_SPANSTAT _IOWR (ZT_CODE, 10, struct zt_spaninfo) /* Get Span Status */
|
||||
#define ZT_MAINT _IOW (ZT_CODE, 11, struct zt_maintinfo)/* Set Maintenance Mode for a span */
|
||||
#define ZT_GETCONF _IOWR (ZT_CODE, 12, struct zt_confinfo) /* Get Conference Mode */
|
||||
#define ZT_SETCONF _IOWR (ZT_CODE, 13, struct zt_confinfo) /* Set Conference Mode */
|
||||
#define ZT_CONFLINK _IOW (ZT_CODE, 14, struct zt_confinfo) /* Setup or Remove Conference Link */
|
||||
#define ZT_CONFDIAG _IOR (ZT_CODE, 15, int) /* Display Conference Diagnostic Information on Console */
|
||||
|
||||
#define ZT_GETGAINS _IOWR (ZT_CODE, 16, struct zt_gains) /* Get Channel audio gains */
|
||||
#define ZT_SETGAINS _IOWR (ZT_CODE, 17, struct zt_gains) /* Set Channel audio gains */
|
||||
#define ZT_SPANCONFIG _IOW (ZT_CODE, 18, struct zt_lineconfig)/* Set Line (T1) Configurations and start system */
|
||||
#define ZT_CHANCONFIG _IOW (ZT_CODE, 19, struct zt_chanconfig)/* Set Channel Configuration */
|
||||
#define ZT_SET_BUFINFO _IOW (ZT_CODE, 27, struct zt_bufferinfo)/* Set buffer policy */
|
||||
#define ZT_GET_BUFINFO _IOR (ZT_CODE, 28, struct zt_bufferinfo)/* Get current buffer info */
|
||||
#define ZT_AUDIOMODE _IOW (ZT_CODE, 32, int) /* Set a clear channel into audio mode */
|
||||
#define ZT_ECHOCANCEL _IOW (ZT_CODE, 33, int) /* Control Echo Canceller */
|
||||
#define ZT_HDLCRAWMODE _IOW (ZT_CODE, 36, int) /* Set a clear channel into HDLC w/out FCS checking/calculation mode */
|
||||
#define ZT_HDLCFCSMODE _IOW (ZT_CODE, 37, int) /* Set a clear channel into HDLC w/ FCS mode */
|
||||
|
||||
/* Specify a channel on /dev/zap/chan -- must be done before any other ioctl's and is only valid on /dev/zap/chan */
|
||||
#define ZT_SPECIFY _IOW (ZT_CODE, 38, int)
|
||||
|
||||
/* Temporarily set the law on a channel to ZT_LAW_DEFAULT, ZT_LAW_ALAW, or ZT_LAW_MULAW. Is reset on close. */
|
||||
#define ZT_SETLAW _IOW (ZT_CODE, 39, int)
|
||||
|
||||
/* Temporarily set the channel to operate in linear mode when non-zero or default law if 0 */
|
||||
#define ZT_SETLINEAR _IOW (ZT_CODE, 40, int)
|
||||
|
||||
#define ZT_GETCONFMUTE _IOR (ZT_CODE, 49, int) /* Get Conference to mute mode */
|
||||
#define ZT_ECHOTRAIN _IOW (ZT_CODE, 50, int) /* Control Echo Trainer */
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
||||
Reference in new issue
Block a user