]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: First GSM working version
authorMoises Silva <moy@sangoma.com>
Mon, 7 May 2012 19:35:13 +0000 (15:35 -0400)
committerMoises Silva <moy@sangoma.com>
Mon, 7 May 2012 19:35:13 +0000 (15:35 -0400)
         - Manually merging latest code from gideon.gsm branch after review/inspection/modifications

libs/freetdm/mod_freetdm/mod_freetdm.c
libs/freetdm/src/ftmod/ftmod_gsm/ftmod_gsm.c [changed mode: 0644->0755]
libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c [changed mode: 0644->0755]
libs/freetdm/src/include/freetdm.h

index e40ca5ef937c3b2da489cb3b66ff4176be70bf9b..a31a5342c97c4f55729ceb1a931850cb4e6b5874 100755 (executable)
@@ -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;
old mode 100644 (file)
new mode 100755 (executable)
index dd46e03..35a7be2
@@ -37,6 +37,7 @@
  *
  */
 
+
 #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);
@@ -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;
+}
+
+
old mode 100644 (file)
new mode 100755 (executable)
index 1e9f3b0..75d165b
@@ -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) {
index 165f243cf30a8f4ad10a3060d349fa1b28a67c97..b48bb50ae565776195249b392ef8ace07b09f1ac 100755 (executable)
@@ -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)