*
*/
+
#define _GNU_SOURCE
#include <string.h>
#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);
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;
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;
}
{
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;
}
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:
{
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;
/* 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);
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 = {
{
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,
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;
}
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;
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));
/* 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;
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);
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;
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;
#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;
}
#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;
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()) {
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:
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(¤t, &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)
{
* 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(¤t, &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;
+}
+
+