提交 f316f930 authored 作者: Moises Silva's avatar Moises Silva

freetdm: First GSM working version

         - Manually merging latest code from gideon.gsm branch after review/inspection/modifications
上级 cf9f9370
......@@ -26,7 +26,7 @@
* Anthony Minessale II <anthm@freeswitch.org>
* Moises Silva <moy@sangoma.com>
* David Yat Sin <dyatsin@sangoma.com>
*
* Gideon Sadan <gsadan@sangoma.com>
*
* mod_freetdm.c -- FreeTDM Endpoint Module
*
......@@ -1887,6 +1887,24 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
switch (sigmsg->event_id) {
case FTDM_SIGEVENT_SMS:
{
ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(sigmsg->channel);
ftdm_sms_data_t *sms = (ftdm_sms_data_t*) caller_data->priv;
ftdm_log(FTDM_LOG_INFO,"FTDM_SIGEVENT_SMS from %s: %s", sms->from, sms->body);
if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "failed to create SMS event\n");
return FTDM_FAIL;
}
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", sms->from);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "body", sms->body);
alarmbits = 0;
}
//return FTDM_BREAK;
break;
case FTDM_SIGEVENT_ALARM_CLEAR:
case FTDM_SIGEVENT_ALARM_TRAP:
{
......@@ -1936,6 +1954,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
return FTDM_SUCCESS;
}
break;
case FTDM_SIGEVENT_RELEASED:
case FTDM_SIGEVENT_INDICATION_COMPLETED:
case FTDM_SIGEVENT_DIALING:
......@@ -1964,6 +1983,8 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
}
if (event) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", ftdm_channel_get_span_name(sigmsg->channel));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", ftdm_channel_get_span_id(sigmsg->channel));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", ftdm_channel_get_id(sigmsg->channel));
......@@ -2898,7 +2919,7 @@ static void parse_gsm_spans(switch_xml_t cfg, switch_xml_t spans)
"gsm",
on_clear_channel_signal,
spanparameters) != FTDM_SUCCESS) {
CONFIG_ERROR("Error configuring Sangoma ISDN FreeTDM span %d\n", span_id);
CONFIG_ERROR("Error configuring Sangoma GSM FreeTDM span %d\n", span_id);
continue;
}
SPAN_CONFIG[span_id].span = span;
......
......@@ -37,6 +37,7 @@
*
*/
#define _GNU_SOURCE
#include <string.h>
......@@ -48,31 +49,86 @@
#include <errno.h>
#include <sys/ioctl.h>
#include <poll.h>
/*========================*/
/*========================*/
#include <stdio.h>
#include <libwat.h>
#include <freetdm.h>
#include <private/ftdm_core.h>
// Debug
#define LOG_SIG_DATA 0
#define DEBUG_STATES 0
#if DEBUG_STATES // state debugging
#define STATE_ADVANCE_LOG_LEVEL FTDM_LOG_CRIT
#else
#define STATE_ADVANCE_LOG_LEVEL FTDM_LOG_DEBUG
#endif
/********************************************************************************/
/* */
/* MACROS */
/* */
/********************************************************************************/
// Macro to send signals
#define SEND_STATE_SIGNAL(sig) \
{ \
ftdm_sigmsg_t sigev; \
memset(&sigev, 0, sizeof(sigev)); \
sigev.event_id = sig; \
sigev.channel = ftdmchan; \
ftdm_span_send_signal(ftdmchan->span, &sigev); \
}
// Syntax message
#define FT_SYNTAX "USAGE:\n" \
"--------------------------------------------------------------------------------\n" \
"ftdm gsm version \n" \
"ftdm gsm status <span_id|span_name>\n" \
"ftdm gsm sms <span_id|span_name> <destination> <text>\n" \
"--------------------------------------------------------------------------------\n"
// Used to declare command handler
#define COMMAND_HANDLER(name) \
ftdm_status_t fCMD_##name(ftdm_stream_handle_t *stream, char *argv[], int argc); \
ftdm_status_t fCMD_##name(ftdm_stream_handle_t *stream, char *argv[], int argc)
// Used to define command entry in the command map.
#define COMMAND(name, argc) {#name, argc, fCMD_##name}
/********************************************************************************/
/* */
/* types */
/* */
/********************************************************************************/
// private data
typedef struct ftdm_gsm_span_data_s {
ftdm_span_t *span;
ftdm_channel_t *dchan;
ftdm_channel_t *bchan;
int32_t call_id;
} ftdm_gsm_span_data_t;
// command handler function type.
typedef ftdm_status_t (*fCMD)(ftdm_stream_handle_t *stream, char *argv[], int argc);
/********************************************************************************/
/* */
/* function declaration */
/* */
/********************************************************************************/
static ftdm_status_t init_wat_lib(void);
static int wat_lib_initialized = 0;
static FIO_API_FUNCTION(ftdm_gsm_api);
static int read_channel(ftdm_channel_t *ftdm_chan , const void *buf, int size)
{
ftdm_size_t outsize = size;
ftdm_status_t status = ftdm_channel_read(ftdm_chan, (void *)buf, &outsize);
if (FTDM_FAIL == status) {
return -1;
}
return (int)outsize;
}
/* wat callbacks */
int on_wat_span_write(unsigned char span_id, void *buffer, unsigned len);
......@@ -91,9 +147,45 @@ void *on_wat_calloc(size_t nmemb, size_t size);
void on_wat_free(void *ptr);
void on_wat_log_span(uint8_t span_id, uint8_t level, char *fmt, ...);
ftdm_span_t *GetSpanByID(unsigned char span_id, ftdm_gsm_span_data_t **gsm_data);
static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj);
/********************************************************************************/
/* */
/* static & global data */
/* */
/********************************************************************************/
int g_outbound_call_id = 8;
/* IO interface for the command API */
static ftdm_io_interface_t g_ftdm_gsm_interface;
/********************************************************************************/
/* */
/* implementation */
/* */
/********************************************************************************/
static int read_channel(ftdm_channel_t *ftdm_chan , const void *buf, int size)
{
ftdm_size_t outsize = size;
ftdm_status_t status = ftdm_channel_read(ftdm_chan, (void *)buf, &outsize);
if (FTDM_FAIL == status) {
return -1;
}
return (int)outsize;
}
int on_wat_span_write(unsigned char span_id, void *buffer, unsigned len)
{
/* ftdm_log(FTDM_LOG_DEBUG, "====================>>> %s (%d) - %d\n", buffer, len, (int) span_id);*/
#if LOG_SIG_DATA
fprintf(stdout, " Out Data ====================>>> %s \r\n (%d) - %d\n", (char *)buffer, len, (int) span_id);
#endif
ftdm_span_t *span = NULL;
ftdm_status_t status = FTDM_FAIL;
ftdm_gsm_span_data_t *gsm_data = NULL;
......@@ -104,14 +196,20 @@ int on_wat_span_write(unsigned char span_id, void *buffer, unsigned len)
ftdm_log(FTDM_LOG_ERROR, "Failed to find span %d to write %d bytes\n", span_id, len);
return -1;
}
gsm_data = span->signal_data;
status = ftdm_channel_write(gsm_data->dchan, (void *)buffer, len, &outsize);
if (status != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Failed to write %d bytes to d-channel in span %s\n", len, span->name);
return -1;
}
return (int)outsize;
//#if LOG_SIG_DATA
// fprintf(stdout, "\r\n==================== len=%d outsize=%d \r\n", len, (int)outsize);
//#endif
fflush(stdout);
return len;
}
......@@ -147,43 +245,200 @@ static void on_wat_span_status(unsigned char span_id, wat_span_status_t *status)
{
ftdm_log(FTDM_LOG_INFO, "span %d: Unhandled span status notification %d\n", span_id, status->type);
}
break;
break;
}
}
void on_wat_con_ind(unsigned char span_id, uint8_t call_id, wat_con_event_t *con_event)
{
fprintf(stdout, "s%d: Incoming call (id:%d) Calling Number:%s type:%d plan:%d\n", span_id, call_id, con_event->calling_num.digits, con_event->calling_num.type, con_event->calling_num.plan);
//fprintf(stdout, "s%d: Incoming call (id:%d) Calling Number:%s Calling Name:\"%s\" type:%d plan:%d\n", span_id, call_id, con_event->calling_num.digits, con_event->calling_name, con_event->calling_num.type, con_event->calling_num.plan);
ftdm_log(FTDM_LOG_INFO, "s%d: Incoming call (id:%d) Calling Number:%s Calling Name:\"%s\" type:%d plan:%d\n", span_id, call_id, con_event->calling_num.digits, con_event->calling_name, con_event->calling_num.type, con_event->calling_num.plan);
ftdm_span_t *span = NULL;
//ftdm_status_t ftdm_status = FTDM_FAIL;
ftdm_gsm_span_data_t *gsm_data = NULL;
if(!(span = GetSpanByID(span_id, &gsm_data))) {
return;
}
gsm_data->call_id = call_id;
#define ZERO_ARRAY(arr) memset(arr, 0, sizeof(arr))
// cid date
{
time_t t;
struct tm *tmp;
t = time(NULL);
tmp = localtime(&t);
if (tmp == NULL) {
ZERO_ARRAY(gsm_data->bchan->caller_data.cid_date);
strftime(gsm_data->bchan->caller_data.cid_date, sizeof(gsm_data->bchan->caller_data.cid_date), "%y/%m/%d", tmp);
}
}
// cid name
ZERO_ARRAY(gsm_data->bchan->caller_data.cid_name);
strncpy(gsm_data->bchan->caller_data.cid_name, con_event->calling_name,sizeof(gsm_data->bchan->caller_data.cid_name));
// dnis
ZERO_ARRAY(gsm_data->bchan->caller_data.dnis.digits);
strncpy(gsm_data->bchan->caller_data.dnis.digits, con_event->calling_num.digits, FTDM_DIGITS_LIMIT);
//collected
ZERO_ARRAY(gsm_data->bchan->caller_data.collected);
strncpy(gsm_data->bchan->caller_data.collected, con_event->calling_num.digits, FTDM_DIGITS_LIMIT);
ftdm_set_state(gsm_data->bchan, FTDM_CHANNEL_STATE_RING);
if (ftdm_channel_open_chan(gsm_data->bchan) != FTDM_SUCCESS) {
ftdm_log_chan(gsm_data->bchan, FTDM_LOG_ERROR, "Failed to open GSM b-channel of span %s!\n", span->name);
}
}
ftdm_span_t *GetSpanByID(unsigned char span_id, ftdm_gsm_span_data_t **gsm_data)
{
ftdm_status_t ftdm_status = FTDM_FAIL;
ftdm_span_t *span = NULL;
if(gsm_data) {
(*gsm_data) = NULL;
}
ftdm_status = ftdm_span_find(span_id, &span);
if (ftdm_status != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "GetSpanByID - Failed to find span %d\n", span_id);
return NULL;
}
if(gsm_data) {
(*gsm_data) = span->signal_data;
}
return span;
return;
}
void on_wat_con_sts(unsigned char span_id, uint8_t call_id, wat_con_status_t *status)
{
ftdm_span_t *span = NULL;
//ftdm_status_t ftdm_status = FTDM_FAIL;
ftdm_gsm_span_data_t *gsm_data = NULL;
if(!(span = GetSpanByID(span_id, &gsm_data))) {
return;
}
switch(status->type) {
case WAT_CON_STATUS_TYPE_RINGING:
ftdm_log(FTDM_LOG_INFO, "on_wat_con_sts - WAT_CON_STATUS_TYPE_RINGING\r\n");
ftdm_set_state(gsm_data->bchan, FTDM_CHANNEL_STATE_RINGING);
break;
case WAT_CON_STATUS_TYPE_ANSWER:
ftdm_log(FTDM_LOG_INFO, "on_wat_con_sts - WAT_CON_STATUS_TYPE_ANSWER\r\n");
ftdm_set_state(gsm_data->bchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
break;
default:
ftdm_log(FTDM_LOG_INFO, "on_wat_con_sts - Unhandled state %d\n", span_id);
};
return;
}
void on_wat_rel_ind(unsigned char span_id, uint8_t call_id, wat_rel_event_t *rel_event)
{
fprintf(stdout, "s%d: Call hangup (id:%d) cause:%d\n", span_id, call_id, rel_event->cause);
ftdm_log(FTDM_LOG_INFO, "s%d: Call hangup (id:%d) cause:%d\n", span_id, call_id, rel_event->cause);
return;
ftdm_span_t *span = NULL;
//ftdm_status_t ftdm_status = FTDM_FAIL;
ftdm_gsm_span_data_t *gsm_data = NULL;
if(!(span = GetSpanByID(span_id, &gsm_data))) {
return;
}
ftdm_set_state(gsm_data->bchan, FTDM_CHANNEL_STATE_HANGUP);
}
void on_wat_rel_cfm(unsigned char span_id, uint8_t call_id)
{
fprintf(stdout, "s%d: Call hangup complete (id:%d)\n", span_id, call_id);
return;
ftdm_log(FTDM_LOG_INFO, "s%d: Call hangup complete (id:%d)\n", span_id, call_id);
ftdm_span_t *span = NULL;
//ftdm_status_t ftdm_status = FTDM_FAIL;
ftdm_gsm_span_data_t *gsm_data = NULL;
if(!(span = GetSpanByID(span_id, &gsm_data))) {
return;
}
switch(gsm_data->dchan->state) {
case FTDM_CHANNEL_STATE_UP:
ftdm_set_state(gsm_data->bchan, FTDM_CHANNEL_STATE_HANGUP);
break;
default:
ftdm_set_state(gsm_data->bchan, FTDM_CHANNEL_STATE_DOWN);
break;
}
}
void on_wat_sms_ind(unsigned char span_id, wat_sms_event_t *sms_event)
{
//printf("on_wat_sms_ind\r\n");
ftdm_span_t *span = NULL;
ftdm_channel_t *ftdmchan;
ftdm_gsm_span_data_t *gsm_data = NULL;
if(!(span = GetSpanByID(span_id, &gsm_data))) {
return;
}
ftdmchan = gsm_data->dchan;
{
ftdm_sms_data_t sms_data;
memset(&sms_data, 0, sizeof(sms_data));
strncpy(sms_data.from, sms_event->from.digits, sizeof(sms_data.from));
strncpy(sms_data.body, sms_event->content.data, sizeof(sms_data.body));
ftdm_sigmsg_t sigev;
memset(&sigev, 0, sizeof(sigev));
sigev.event_id = FTDM_SIGEVENT_SMS;
sigev.channel = ftdmchan ;
gsm_data->dchan->caller_data.priv = (void *)&sms_data;
ftdm_span_send_signal(span, &sigev);
}
// SEND_STATE_SIGNAL(FTDM_SIGEVENT_SMS);
return;
}
void on_wat_sms_sts(unsigned char span_id, uint8_t sms_id, wat_sms_status_t *status)
{
if(status->success) {
ftdm_log(FTDM_LOG_INFO, "Span %d SMS Send - OK\n", span_id );
}
else {
ftdm_log(FTDM_LOG_CRIT, "Span %d SMS Send - FAIL (%s)\n", span_id, status->error);
}
return;
}
......@@ -198,8 +453,7 @@ void on_wat_log(uint8_t level, char *fmt, ...)
va_start(argptr, fmt);
char buff[10001];
switch(level)
{
switch(level) {
case WAT_LOG_CRIT: ftdm_level = FTDM_LOG_LEVEL_CRIT; break;
case WAT_LOG_ERROR: ftdm_level = FTDM_LOG_LEVEL_ERROR; break;
default:
......@@ -223,27 +477,30 @@ void *on_wat_malloc(size_t size)
{
return ftdm_malloc(size);
}
void *on_wat_calloc(size_t nmemb, size_t size)
{
return ftdm_calloc(nmemb, size);
}
void on_wat_free(void *ptr)
{
ftdm_free(ptr);
}
void on_wat_log_span(uint8_t span_id, uint8_t level, char *fmt, ...)
{
int ftdm_level;
return;
va_list argptr;
va_start(argptr, fmt);
char buff[10001];
switch(level)
{
switch(level) {
case WAT_LOG_CRIT: ftdm_level = FTDM_LOG_LEVEL_CRIT; break;
case WAT_LOG_ERROR: ftdm_level = FTDM_LOG_LEVEL_ERROR; break;
default:
case WAT_LOG_WARNING: ftdm_level = FTDM_LOG_LEVEL_WARNING; break;
case WAT_LOG_INFO: ftdm_level = FTDM_LOG_LEVEL_INFO; break;
case WAT_LOG_NOTICE: ftdm_level = FTDM_LOG_LEVEL_NOTICE; break;
......@@ -265,22 +522,17 @@ void on_wat_log_span(uint8_t span_id, uint8_t level, char *fmt, ...)
/* END wat callbacks */
/* span monitor thread */
static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj);
/* IO interface for the command API */
static ftdm_io_interface_t g_ftdm_gsm_interface;
static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(gsm_outgoing_call)
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "GSM place call not implemented yet!\n");
return FTDM_FAIL;
return FTDM_SUCCESS;
}
static ftdm_status_t ftdm_gsm_start(ftdm_span_t *span)
{
if (wat_span_start(span->span_id)) {
ftdm_log(FTDM_LOG_ERROR, "Failed to start span %s!\n", span->name);
return FTDM_FAIL;
return FTDM_SUCCESS;
}
return ftdm_thread_create_detached(ftdm_gsm_run, span);
......@@ -288,32 +540,38 @@ static ftdm_status_t ftdm_gsm_start(ftdm_span_t *span)
static ftdm_status_t ftdm_gsm_stop(ftdm_span_t *span)
{
ftdm_log(FTDM_LOG_CRIT, "STOP not implemented yet!\n");
return FTDM_FAIL;
return FTDM_SUCCESS;
}
static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_gsm_get_channel_sig_status)
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "get sig status not implemented yet!\n");
return FTDM_FAIL;
ftdm_log(FTDM_LOG_INFO, "\r\nftdm_gsm_get_channel_sig_status\r\n");
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
*status = FTDM_SIG_STATE_UP;
}
else {
*status = FTDM_SIG_STATE_DOWN;
}
*status = FTDM_SIG_STATE_UP;
return FTDM_SUCCESS;
}
static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_gsm_set_channel_sig_status)
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "set sig status not implemented yet!\n");
return FTDM_FAIL;
return FTDM_SUCCESS;
}
static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_gsm_get_span_sig_status)
{
ftdm_log(FTDM_LOG_CRIT, "span get sig status not implemented yet!\n");
return FTDM_FAIL;
*status = FTDM_SIG_STATE_UP;
return FTDM_SUCCESS;
}
static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_gsm_set_span_sig_status)
{
ftdm_log(FTDM_LOG_CRIT, "span set sig status not implemented yet!\n");
return FTDM_FAIL;
return FTDM_SUCCESS;
}
static ftdm_state_map_t gsm_state_map = {
......@@ -393,10 +651,12 @@ static ftdm_state_map_t gsm_state_map = {
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_DIALING, FTDM_END},
{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}
{FTDM_CHANNEL_STATE_DIALING, FTDM_CHANNEL_STATE_RINGING, FTDM_END},
{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_RINGING, FTDM_END}
},
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
......@@ -429,7 +689,135 @@ static ftdm_state_map_t gsm_state_map = {
static ftdm_status_t ftdm_gsm_state_advance(ftdm_channel_t *ftdmchan)
{
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
ftdm_log_chan(ftdmchan, STATE_ADVANCE_LOG_LEVEL , "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
ftdm_channel_complete_state(ftdmchan);
switch (ftdmchan->state) {
/* starting an incoming call */
case FTDM_CHANNEL_STATE_COLLECT:
{
}
break;
/* starting an outgoing call */
case FTDM_CHANNEL_STATE_DIALING:
{
uint32_t interval = 0;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting outgoing call with interval %d\n", interval);
{
ftdm_gsm_span_data_t *gsm_data;
gsm_data = ftdmchan->span->signal_data;
gsm_data->call_id = g_outbound_call_id++;
wat_con_event_t con_event;
memset(&con_event, 0, sizeof(con_event));
sprintf(con_event.called_num.digits, ftdmchan->caller_data.dnis.digits);
ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s\n", con_event.called_num.digits);
wat_con_req(ftdmchan->span->span_id, gsm_data->call_id , &con_event);
SEND_STATE_SIGNAL(FTDM_SIGEVENT_DIALING);
}
}
break;
/* incoming call was offered */
case FTDM_CHANNEL_STATE_RING:
/* notify the user about the new call */
ftdm_log(FTDM_LOG_INFO, "Answering Incomming Call\r\n");
SEND_STATE_SIGNAL(FTDM_SIGEVENT_START);
break;
/* the call is making progress */
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
{
SEND_STATE_SIGNAL(FTDM_SIGEVENT_PROGRESS_MEDIA);
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
}
break;
/* the call was answered */
case FTDM_CHANNEL_STATE_UP:
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
SEND_STATE_SIGNAL(FTDM_SIGEVENT_UP);
}
else {
ftdm_gsm_span_data_t *gsm_data;
gsm_data = ftdmchan->span->signal_data;
wat_con_cfm(ftdmchan->span->span_id, gsm_data->call_id);
}
}
break;
/* just got hangup */
case FTDM_CHANNEL_STATE_HANGUP:
{
ftdm_gsm_span_data_t *gsm_data;
gsm_data = ftdmchan->span->signal_data;
wat_rel_req(ftdmchan->span->span_id, gsm_data->call_id);
gsm_data->call_id = 0;
SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
}
break;
case FTDM_CHANNEL_STATE_TERMINATING:
{
SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
}
break;
/* finished call for good */
case FTDM_CHANNEL_STATE_DOWN:
{
ftdm_channel_t *closed_chan;
closed_chan = ftdmchan;
ftdm_channel_close(&closed_chan);
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "State processing ended.\n");
SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
}
break;
/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
case FTDM_CHANNEL_STATE_RINGING:
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
SEND_STATE_SIGNAL(FTDM_SIGEVENT_RINGING);
break;
/* put the r2 channel back to IDLE, close ftdmchan and set it's state as DOWN */
case FTDM_CHANNEL_STATE_RESET:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RESET indicated, putting the R2 channel back to IDLE\n");
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
}
break;
}
return FTDM_SUCCESS;
}
......@@ -465,8 +853,8 @@ static ftdm_status_t init_wat_lib(void)
if (wat_register(&wat_interface)) {
ftdm_log(FTDM_LOG_DEBUG, "Failed registering interface to WAT library ...\n");
return FTDM_FAIL;
}
ftdm_log(FTDM_LOG_DEBUG, "Registered interface to WAT library\n");
wat_lib_initialized = 1;
......@@ -482,10 +870,12 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
ftdm_iterator_t *citer = NULL;
ftdm_channel_t *ftdmchan = NULL;
ftdm_channel_t *dchan = NULL;
ftdm_channel_t *bchan = NULL;
unsigned paramindex = 0;
const char *var = NULL;
const char *val = NULL;
/* libwat is smart enough to set good default values for the timers if they are set to 0 */
memset(&span_config, 0, sizeof(span_config));
......@@ -508,6 +898,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
/* verify the span has one d-channel */
chaniter = ftdm_span_get_chan_iterator(span, NULL);
if (!chaniter) {
ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
return FTDM_FAIL;
......@@ -516,10 +907,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
citer = ftdm_span_get_chan_iterator(span, chaniter);
for ( ; citer; citer = ftdm_iterator_next(citer)) {
ftdmchan = ftdm_iterator_current(citer);
if (FTDM_IS_DCHAN(ftdmchan)) {
if ((NULL == dchan) && FTDM_IS_DCHAN(ftdmchan)) {
dchan = ftdmchan;
break;
}
if ((NULL == bchan) && FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
bchan = ftdmchan;
}
}
ftdm_iterator_free(chaniter);
......@@ -527,12 +922,24 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
ftdm_log(FTDM_LOG_CRIT, "Could not find a d-channel for GSM span %s!\n", span->name);
return FTDM_FAIL;
}
if (!bchan) {
ftdm_log(FTDM_LOG_CRIT, "Could not find a b-channel for GSM span %s!\n", span->name);
return FTDM_FAIL;
}
gsm_data = ftdm_calloc(1, sizeof(*gsm_data));
if (!gsm_data) {
return FTDM_FAIL;
}
gsm_data->dchan = dchan;
gsm_data->bchan = bchan;
//sprintf(gsm_data->dchan->chan_name, "%s\t\n", "GSM dchan");
//sprintf(gsm_data->bchan->chan_name, "%s\r\n", "GSM bchan");
for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) {
var = ftdm_parameters[paramindex].var;
......@@ -569,6 +976,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
span->get_channel_sig_status = ftdm_gsm_get_channel_sig_status;
span->set_channel_sig_status = ftdm_gsm_set_channel_sig_status;
//printf("\r\nspan->state_map = &gsm_state_map;\r\n");
span->state_map = &gsm_state_map;
span->state_processor = ftdm_gsm_state_advance;
......@@ -589,11 +997,21 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
#endif
fprintf(stdout, "Configuring wat span %d %s \r\n", span->span_id, span->name);
if (wat_span_config(span->span_id, &span_config)) {
ftdm_log(FTDM_LOG_ERROR, "Failed to configure span %s for GSM signaling!!\n", span->name);
return FTDM_FAIL;
}
{
int codec = FTDM_CODEC_SLIN;
int interval = 20;
ftdm_channel_command(gsm_data->bchan, FTDM_COMMAND_SET_NATIVE_CODEC, &codec);
ftdm_channel_command(gsm_data->bchan, FTDM_COMMAND_SET_CODEC, &codec);
ftdm_channel_command(gsm_data->bchan, FTDM_COMMAND_SET_INTERVAL, &interval);
}
return FTDM_SUCCESS;
}
......@@ -601,11 +1019,12 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
#define GSM_POLL_INTERVAL_MS 20
static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj)
{
ftdm_log(FTDM_LOG_INFO,"ftdm_gsm_run\r\n");
ftdm_channel_t *ftdmchan = NULL;
ftdm_span_t *span = (ftdm_span_t *) obj;
ftdm_gsm_span_data_t *gsm_data = NULL;
ftdm_status_t status = FTDM_SUCCESS;
ftdm_wait_flag_t ioflags = FTDM_NO_FLAGS;
ftdm_interrupt_t *data_sources[2] = {NULL, NULL};
int waitms = 0;
......@@ -620,16 +1039,8 @@ static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj)
goto done;
}
/* create an interrupt object to wait for data from the d-channel device */
if (ftdm_interrupt_create(&data_sources[0], gsm_data->dchan->sockfd, FTDM_READ) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "Failed to create GSM d-channel interrupt for span %s\n", span->name);
goto done;
}
status = ftdm_queue_get_interrupt(span->pendingchans, &data_sources[1]);
if (status != FTDM_SUCCESS || data_sources[1] == NULL) {
ftdm_log(FTDM_LOG_CRIT, "Failed to retrieve channel queue interrupt for span %s\n", span->name);
goto done;
}
while (ftdm_running()) {
......@@ -640,47 +1051,48 @@ static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj)
waitms = GSM_POLL_INTERVAL_MS;
}
#if 0
/* run any span timers */
ftdm_sched_run(r2data->sched);
/////////////////////
{
ftdm_wait_flag_t flags = FTDM_READ | FTDM_EVENTS;
ftdm_status_t status = ftdm_channel_wait(gsm_data->dchan, &flags, waitms);
/* double check that this channel has a state change pending */
ftdm_channel_lock(gsm_data->bchan);
ftdm_channel_advance_states(gsm_data->bchan);
if(FTDM_SUCCESS == status ) {
if(flags &FTDM_READ ) {
char buffer[1025];
int n = 0, m = 0;
memset(buffer, 0, sizeof(buffer));
n = read_channel(gsm_data->dchan, buffer, sizeof(buffer)-1);
m = strlen(buffer);
wat_span_process_read(span->span_id, buffer, m);
#if LOG_SIG_DATA
printf("<<======================= incomming data len = %d, %s\r\n", n, buffer);
#endif
status = ftdm_interrupt_multiple_wait(data_sources, ftdm_array_len(data_sources), waitms);
switch (status) {
case FTDM_ETIMEDOUT:
break;
case FTDM_SUCCESS:
{
/* process first the d-channel if ready */
if ((ioflags = ftdm_interrupt_device_ready(data_sources[0])) != FTDM_NO_FLAGS) {
char buffer[1024];
unsigned int n = 0;
n = read_channel(gsm_data->dchan, buffer, sizeof(buffer));
/* this may trigger any of the callbacks registered through wat_register() */
wat_span_process_read(span->span_id, buffer, n);
}
/* now process all channels with state changes pending */
while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
/* double check that this channel has a state change pending */
ftdm_channel_lock(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
ftdm_channel_unlock(ftdmchan);
}
/* deliver the actual channel events to the user now without any channel locking */
ftdm_span_trigger_signals(span);
}
break;
case FTDM_FAIL:
ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned error!\n", span->name);
break;
ftdm_channel_advance_states(gsm_data->bchan);
ftdm_channel_unlock(gsm_data->bchan);
default:
ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned with unknown code\n", span->name);
break;
}
ftdm_span_trigger_signals(span);
}
done:
......@@ -693,94 +1105,7 @@ done:
return NULL;
}
#define FT_SYNTAX "USAGE:\n" \
"--------------------------------------------------------------------------------\n" \
"ftdm gsm status <span_id|span_name>\n" \
"--------------------------------------------------------------------------------\n"
static FIO_API_FUNCTION(ftdm_gsm_api)
{
ftdm_span_t *span = NULL;
int span_id = 0;
char *mycmd = NULL, *argv[10] = { 0 };
int argc = 0;
if (data) {
mycmd = ftdm_strdup(data);
argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
if (!strcasecmp(argv[0], "version")) {
uint8_t current = 0, revision = 0, age = 0;
wat_version(&current, &revision, &age);
stream->write_function(stream, "libwat version: %d.%d.%d\n", current, revision, age);
stream->write_function(stream, "+OK.\n");
goto done;
} else if (!strcasecmp(argv[0], "status")) {
const wat_chip_info_t *chip_info = NULL;
const wat_sim_info_t *sim_info = NULL;
const wat_net_info_t *net_info = NULL;
const wat_sig_info_t *sig_info = NULL;
const wat_pin_stat_t *pin_stat = NULL;
if (argc < 2) {
goto syntax;
}
span_id = atoi(argv[1]);
if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS &&
ftdm_span_find(span_id, &span) != FTDM_SUCCESS) {
stream->write_function(stream, "-ERR Failed to find GSM span '%s'\n", argv[1]);
goto done;
}
if (!span || !span->signal_data || (span->start != ftdm_gsm_start)) {
stream->write_function(stream, "-ERR '%s' is not a valid GSM span\n", argv[1]);
goto done;
}
chip_info = wat_span_get_chip_info(span->span_id);
sim_info = wat_span_get_sim_info(span->span_id);
net_info = wat_span_get_net_info(span->span_id);
sig_info = wat_span_get_sig_info(span->span_id);
pin_stat = wat_span_get_pin_info(span->span_id);
stream->write_function(stream, "Span %d (%s):\n", span->span_id, span->name);
stream->write_function(stream, "CHIP - %s (%s), revision %s, serial %s \n",
chip_info->manufacturer_name,
chip_info->manufacturer_id,
chip_info->revision,
chip_info->serial);
stream->write_function(stream, "SIM - Subscriber type %s, imsi %s\n", sim_info->subscriber_type, sim_info->imsi);
stream->write_function(stream, "Subscriber - Number %s, Plan %s, validity %s\n",
sim_info->subscriber.digits,
wat_number_type2str(sim_info->subscriber.type),
wat_number_plan2str(sim_info->subscriber.plan),
wat_number_validity2str(sim_info->subscriber.validity));
stream->write_function(stream, "Network - status %s, Area Code %d, Cell ID %d, Operator %s\n",
wat_net_stat2str(net_info->stat), net_info->lac, net_info->ci, net_info->operator_name);
stream->write_function(stream, "\n");
stream->write_function(stream, "+OK.\n");
goto done;
}
syntax:
stream->write_function(stream, "%s", FT_SYNTAX);
done:
ftdm_safe_free(mycmd);
return FTDM_SUCCESS;
}
static FIO_IO_LOAD_FUNCTION(ftdm_gsm_io_init)
{
......@@ -827,3 +1152,178 @@ EX_DECLARE_DATA ftdm_module_t ftdm_module = {
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
/********************************************************************************/
/* */
/* COMMAND HANDLERS */
/* */
/********************************************************************************/
// Version Command Handler
COMMAND_HANDLER(version)
{
uint8_t current = 0, revision = 0, age = 0;
wat_version(&current, &revision, &age);
stream->write_function(stream, "libwat version: %d.%d.%d\n", current, revision, age);
stream->write_function(stream, "+OK.\n");
return FTDM_SUCCESS;
}
// Status Command Handler
COMMAND_HANDLER(status)
{
int span_id = 0;
ftdm_span_t *span = NULL;
const wat_chip_info_t *chip_info = NULL;
const wat_sim_info_t *sim_info = NULL;
const wat_net_info_t *net_info = NULL;
const wat_sig_info_t *sig_info = NULL;
const wat_pin_stat_t *pin_stat = NULL;
span_id = atoi(argv[0]);
if (ftdm_span_find_by_name(argv[0], &span) != FTDM_SUCCESS && ftdm_span_find(span_id, &span) != FTDM_SUCCESS) {
stream->write_function(stream, "-ERR Failed to find GSM span '%s'\n", argv[1]);
return FTDM_FAIL;
}
if (!span || !span->signal_data || (span->start != ftdm_gsm_start)) {
stream->write_function(stream, "-ERR '%s' is not a valid GSM span\n", argv[1]);
return FTDM_FAIL;
}
chip_info = wat_span_get_chip_info(span->span_id);
sim_info = wat_span_get_sim_info(span->span_id);
net_info = wat_span_get_net_info(span->span_id);
sig_info = wat_span_get_sig_info(span->span_id);
pin_stat = wat_span_get_pin_info(span->span_id);
stream->write_function(stream, "Span %d (%s):\n", span->span_id, span->name);
stream->write_function(stream, "CHIP type - %s (%s), revision %s, serial %s \n",
chip_info->manufacturer,
chip_info->model,
chip_info->revision,
chip_info->serial);
stream->write_function(stream, "SIM - Subscriber type %s, imsi %s\n", sim_info->subscriber_type, sim_info->imsi);
stream->write_function(stream, "Subscriber - Number %s, Plan %s, validity %s\n",
sim_info->subscriber.digits,
wat_number_type2str(sim_info->subscriber.type),
wat_number_plan2str(sim_info->subscriber.plan),
wat_number_validity2str(sim_info->subscriber.validity));
stream->write_function(stream, "Network - status %s, Area Code %d, Cell ID %d, Operator %s\n",
wat_net_stat2str(net_info->stat), net_info->lac, net_info->ci, net_info->operator_name);
stream->write_function(stream, "\n");
stream->write_function(stream, "+OK.\n");
return FTDM_SUCCESS;
}
// SMS Command Handler
COMMAND_HANDLER(sms)
{
int span_id = 0,i;
ftdm_span_t *span = NULL;
wat_sms_event_t sms;
span_id = atoi(argv[0]);
if (ftdm_span_find_by_name(argv[0], &span) != FTDM_SUCCESS && ftdm_span_find(span_id, &span) != FTDM_SUCCESS) {
stream->write_function(stream, "-ERR Failed to find GSM span '%s'\n", argv[1]);
return FTDM_FAIL;
}
if (!span || !span->signal_data || (span->start != ftdm_gsm_start)) {
stream->write_function(stream, "-ERR '%s' is not a valid GSM span\n", argv[1]);
return FTDM_FAIL;
}
memset(&sms, 0, sizeof(sms));
strcpy(sms.to.digits, argv[1]);
sms.type = WAT_SMS_TXT;
sms.content.data[0] = '\0';
for(i=2;i<argc;i++) {
strcat(sms.content.data, argv[i]);
strcat(sms.content.data, " ");
}
sms.content.len = strlen(sms.content.data);
if(WAT_SUCCESS != wat_sms_req(span->span_id, g_outbound_call_id++ , &sms)) {
stream->write_function(stream, "Failed to Send SMS \n");
}
else {
stream->write_function(stream, "SMS Sent.\n");
}
return FTDM_SUCCESS;
}
// command map
struct {
const char*CMD; // command
int Argc; // minimum args
fCMD Handler; // handling function
}
GSM_COMMANDS[] = {
COMMAND(version, 0),
COMMAND(status, 1),
COMMAND(sms, 3)
};
// Commnand API entry point
static FIO_API_FUNCTION(ftdm_gsm_api)
{
char *mycmd = NULL, *argv[10] = { 0 };
int argc = 0;
int i;
ftdm_status_t status = FTDM_FAIL;
ftdm_status_t syntax = FTDM_FAIL;
if (data) {
mycmd = ftdm_strdup(data);
argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
if(argc > 0) {
for(i=0;i<sizeof(GSM_COMMANDS)/sizeof(GSM_COMMANDS[0]);i++) {
if(strcasecmp(argv[0],GSM_COMMANDS[i].CMD)==0) {
if(argc -1 >= GSM_COMMANDS[i].Argc) {
syntax = FTDM_SUCCESS;
status = GSM_COMMANDS[i].Handler(stream, &argv[1], argc-1);
}
break;
}
}
}
if(FTDM_SUCCESS != syntax) {
stream->write_function(stream, "%s", FT_SYNTAX);
}
else
if(FTDM_SUCCESS != status) {
stream->write_function(stream, "%s Command Failed\r\n", GSM_COMMANDS[i].CMD);
}
ftdm_safe_free(mycmd);
return FTDM_SUCCESS;
}
......@@ -36,9 +36,9 @@
* David Yat Sin <davidy@sangoma.com>
* Nenad Corbic <ncorbic@sangoma.com>
* Arnaldo Pereira <arnaldo@sangoma.com>
* Gideon Sadan <gsadan@sangoma.com>
*
*/
*/
#ifdef WP_DEBUG_IO
#define _BSD_SOURCE
#include <syscall.h>
......@@ -121,6 +121,16 @@ FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event);
FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event);
static void wp_swap16(char *data, int datalen)
{
int i = 0;
uint16_t *samples = data;
for (i = 0; i < datalen/2; i++) {
uint16_t sample = ((samples[i] & 0x00FF) << 8) | ((samples[i] & 0xFF00) >> 8);
samples[i] = sample;
}
}
/**
* \brief Poll for event on a wanpipe socket
* \param fd Wanpipe socket descriptor
......@@ -305,11 +315,20 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
err = sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
} else {
chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
}
if ((span->trunk_type == FTDM_TRUNK_GSM) && (chan->type == FTDM_CHAN_TYPE_B)) {
chan->native_codec = FTDM_CODEC_SLIN;
chan->native_interval = 20;
chan->packet_len = 320;
}
err = sangoma_tdm_get_hw_dtmf(chan->sockfd, &tdm_api);
if (err > 0) {
......@@ -580,8 +599,9 @@ static FIO_OPEN_FUNCTION(wanpipe_open)
ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL);
ftdmchan->effective_interval = ftdmchan->native_interval = wp_globals.codec_ms;
ftdmchan->packet_len = ftdmchan->native_interval * 8;
/* The packet len will depend on the codec and interval */
ftdmchan->packet_len = ftdmchan->native_interval * ((ftdmchan->native_codec==FTDM_CODEC_SLIN) ? 16 : 8);
if (wp_globals.txqueue_size > 0) {
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &wp_globals.txqueue_size);
}
......@@ -772,6 +792,7 @@ static FIO_COMMAND_FUNCTION(wanpipe_command)
case FTDM_COMMAND_SET_INTERVAL:
{
err=sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, FTDM_COMMAND_OBJ_INT);
ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
}
break;
......@@ -793,7 +814,7 @@ static FIO_COMMAND_FUNCTION(wanpipe_command)
FTDM_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits);
}
#else
// does sangoma_tdm_read_rbs is available here?
/* is sangoma_tdm_read_rbs available here? */
FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits;
#endif
}
......@@ -969,12 +990,15 @@ static void wanpipe_read_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_rx_hdr_t *rx
* \param datalen Size of data buffer
* \return Success, failure or timeout
*/
static FIO_READ_FUNCTION(wanpipe_read)
{
int rx_len = 0;
int rq_len = (int)*datalen;
wp_tdm_api_rx_hdr_t hdrframe;
#ifdef WP_DEBUG_IO
wp_channel_t *wchan = ftdmchan->io_data;
ftdm_time_t time_diff = 0;
......@@ -1034,6 +1058,10 @@ static FIO_READ_FUNCTION(wanpipe_read)
wanpipe_read_stats(ftdmchan, &hdrframe);
}
if ((ftdmchan->type == FTDM_CHAN_TYPE_B) && (ftdmchan->span->trunk_type == FTDM_TRUNK_GSM)) {
wp_swap16(data, *datalen);
}
return FTDM_SUCCESS;
}
......@@ -1050,6 +1078,10 @@ static FIO_WRITE_FUNCTION(wanpipe_write)
int err = 0;
wp_tdm_api_tx_hdr_t hdrframe;
if ((ftdmchan->type == FTDM_CHAN_TYPE_B) && (ftdmchan->span->trunk_type == FTDM_TRUNK_GSM)) {
wp_swap16(data, *datalen);
}
/* Do we even need the headerframe here? on windows, we don't even pass it to the driver */
memset(&hdrframe, 0, sizeof(hdrframe));
if (*datalen == 0) {
......
......@@ -346,6 +346,11 @@ typedef struct {
uint8_t plan;
} ftdm_number_t;
typedef struct {
char from[FTDM_MAX_NUMBER_STR_SZ];
char body[FTDM_MAX_NAME_STR_SZ];
} ftdm_sms_data_t;
/*! \brief Caller information */
typedef struct ftdm_caller_data {
char cid_date[8]; /*!< Caller ID date */
......@@ -456,12 +461,13 @@ typedef enum {
FTDM_SIGEVENT_INDICATION_COMPLETED, /*!< Last requested indication was completed */
FTDM_SIGEVENT_DIALING, /*!< Outgoing call just started */
FTDM_SIGEVENT_TRANSFER_COMPLETED, /*!< Transfer request is completed */
FTDM_SIGEVENT_SMS,
FTDM_SIGEVENT_INVALID, /*!<Invalid */
} ftdm_signal_event_t;
#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "RINGING", "PROGRESS", \
"PROGRESS_MEDIA", "ALARM_TRAP", "ALARM_CLEAR", \
"COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "FACILITY", \
"TRACE", "TRACE_RAW", "INDICATION_COMPLETED", "DIALING", "TRANSFER_COMPLETED", "INVALID"
"TRACE", "TRACE_RAW", "INDICATION_COMPLETED", "DIALING", "TRANSFER_COMPLETED", "SMS", "INVALID"
/*! \brief Move from string to ftdm_signal_event_t and viceversa */
FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论