]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: refactor ftmod_gsm.c code to use proper core functions and interrupts to...
authorMoises Silva <moy@sangoma.com>
Mon, 26 Dec 2011 01:55:02 +0000 (20:55 -0500)
committerMoises Silva <moy@sangoma.com>
Mon, 7 May 2012 19:13:26 +0000 (15:13 -0400)
libs/freetdm/src/ftmod/ftmod_gsm/ftmod_gsm.c

index 1a6c18f5131421c0e1bf73f6f0e115d67034470b..dd46e0354c2e5c468a2a8bfa2eea12b33e236bc4 100644 (file)
 #include <freetdm.h>
 #include <private/ftdm_core.h>
 
-#define MAX_SPANS 32
 typedef struct ftdm_gsm_span_data_s {
        ftdm_span_t *span;
-       fio_signal_cb_t sig_cb;
-       ftdm_conf_parameter_t *ftdm_parameters;
-}ftdm_gsm_span_data_t;
+       ftdm_channel_t *dchan;
+} ftdm_gsm_span_data_t;
 
-
-static ftdm_gsm_span_data_t spans_info[MAX_SPANS];
-static int n_spans_info = 0;
-
-typedef struct ftdm_gsm_data_s {
-
-       wat_interface_t wat_interface;  
-
-       
-
-} ftdm_gsm_data_t;
-
-
-static ftdm_status_t  init_wat_lib(void);
+static ftdm_status_t init_wat_lib(void);
 static int wat_lib_initialized = 0;
 
-ftdm_span_t *get_span(int span_id);
-
-ftdm_span_t *get_span(int span_id)
-{
-       int i;
-       for(i=0; i< n_spans_info;i++)
-       {
-               if(spans_info[i].span->span_id == span_id) {
-                       
-                       return spans_info[i].span;
-               }
-
-       }
-       
-       return NULL;
-}
-
-ftdm_channel_t *get_channel(int span_id, int channel_id);
-ftdm_channel_t *get_channel(int span_id, int channel_id)
-{
-       ftdm_channel_t *ftdmchan = NULL;
-       ftdm_span_t * span = get_span(span_id);
-
-       if(!span){
-               return NULL;
-       }
-
-
-               
-       
-       ftdm_iterator_t *citer = ftdm_span_get_chan_iterator(span, NULL);
-       
-               for ( ; citer; citer = ftdm_iterator_next(citer)) {
-                       ftdmchan = ftdm_iterator_current(citer);
-                       if(ftdmchan->chan_id == channel_id) {
-                               ftdm_iterator_free(citer);
-                               return ftdmchan;
-                       }
-                       
-                       
-
-                       
-               }
-
-       ftdm_iterator_free(citer);
-       return NULL;
-}
-
-
 static int read_channel(ftdm_channel_t *ftdm_chan , const void *buf, int size)
 {
        
@@ -139,7 +75,7 @@ static int read_channel(ftdm_channel_t *ftdm_chan , const void *buf, int size)
 }
 
 /* wat callbacks */
-int     on_wat_span_write(unsigned char span_id, void *buffer, unsigned len);
+int on_wat_span_write(unsigned char span_id, void *buffer, unsigned len);
 
 void on_wat_con_ind(unsigned char span_id, uint8_t call_id, wat_con_event_t *con_event);
 void on_wat_con_sts(unsigned char span_id, uint8_t call_id, wat_con_status_t *status);
@@ -155,28 +91,24 @@ 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, ...);
 
-
-/*     gsm_data->wat_interface.wat_log = on_log; */
-       
-/*     gsm_data->wat_interface.wat
-_log_span = on_log_span; */
-
-/*             gsm_data->wat_interface.wat_malloc = on_wat_malloc;*/
-/*             gsm_data->wat_interface.wat_calloc = on_wat_calloc;*/
-/*     gsm_data->wat_interface.wat_free = on_wat_frspanee;*/
-
-
 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);*/
-
-       ftdm_channel_t * ftdm_chan = get_channel(span_id, 2);
+       ftdm_span_t *span = NULL;
+       ftdm_status_t status = FTDM_FAIL;
+       ftdm_gsm_span_data_t *gsm_data = NULL;
        ftdm_size_t outsize = len;
-       ftdm_channel_lock(ftdm_chan);
-       ftdm_status_t status = ftdm_channel_write(ftdm_chan, (void *)buffer, len, &outsize);
-       ftdm_channel_unlock(ftdm_chan);
-       if (FTDM_FAIL == status) {
+
+       status = ftdm_span_find(span_id, &span);
+       if (status != FTDM_SUCCESS) {
+               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;
@@ -346,6 +278,11 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(gsm_outgoing_call)
 
 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_thread_create_detached(ftdm_gsm_run, span);
 }
 
@@ -500,17 +437,15 @@ static ftdm_status_t ftdm_gsm_state_advance(ftdm_channel_t *ftdmchan)
 
 static ftdm_status_t init_wat_lib(void)
 {
-
-       if(wat_lib_initialized)
-       {
+       if (wat_lib_initialized) {
                return FTDM_SUCCESS;
        }
 
        wat_interface_t wat_interface;
 
        ftdm_log(FTDM_LOG_DEBUG, "Registering interface to WAT Library...\n");
-       fprintf(stdout, "Registering interface to WAT Library...\n");
 
+       memset(&wat_interface, 0, sizeof(wat_interface));
        wat_interface.wat_span_write = on_wat_span_write;
        
        wat_interface.wat_log = on_wat_log;
@@ -528,13 +463,12 @@ static ftdm_status_t init_wat_lib(void)
        wat_interface.wat_span_sts = on_wat_span_status;
        
        if (wat_register(&wat_interface)) {
-               ftdm_log(FTDM_LOG_DEBUG, "FAILED Registering interface to WAT Library...\n");
+               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");
+       ftdm_log(FTDM_LOG_DEBUG, "Registered interface to WAT library\n");
 
-       fprintf(stdout, "Registered interface to WAT Library\n");
        wat_lib_initialized = 1;
        return FTDM_SUCCESS;
 }
@@ -542,70 +476,81 @@ static ftdm_status_t init_wat_lib(void)
 
 static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
 {
+       wat_span_config_t span_config;
+       ftdm_gsm_span_data_t *gsm_data = NULL;
+       ftdm_iterator_t *chaniter = NULL;
+       ftdm_iterator_t *citer = NULL;
+       ftdm_channel_t *ftdmchan = NULL;
+       ftdm_channel_t *dchan = NULL;
        unsigned paramindex = 0;
        const char *var = NULL;
        const char *val = NULL;
 
-       if(FTDM_SUCCESS != init_wat_lib())
-       {
+       /* 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));
+       
+       /* set some span defaults */
+       span_config.moduletype = WAT_MODULE_TELIT;
+
+       if (FTDM_SUCCESS != init_wat_lib()) {
                return FTDM_FAIL;
        }
 
-       if (n_spans_info >= MAX_SPANS) {
-               snprintf(span->last_error, sizeof(span->last_error), "MAX_SPANS Exceeded !!!\n");
-               ftdm_log(FTDM_LOG_DEBUG, span->last_error);
+       if (!sig_cb) {
+               ftdm_log(FTDM_LOG_ERROR, "No signaling callback provided\n");
                return FTDM_FAIL;
-
        }
 
-       memset(&spans_info[n_spans_info], 0 ,sizeof(spans_info[n_spans_info]));
-
-       spans_info[n_spans_info].span = span;
-       spans_info[n_spans_info].sig_cb = sig_cb;
-       spans_info[n_spans_info].ftdm_parameters = ftdm_parameters;
-        n_spans_info ++;
-
-
-
-       ftdm_gsm_data_t *gsm_data = malloc(sizeof(*gsm_data));
-       if (!gsm_data) {
-
-               snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate GSM data.");
+       if (span->signal_type) {
+               ftdm_log(FTDM_LOG_ERROR, "Span %s is already configured for another signaling\n", span->name);
                return FTDM_FAIL;
        }
-       memset(gsm_data,0, sizeof(*gsm_data));
-
-
-  /* */
-
 
+       /* 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;
+       }
 
-       ftdm_assert_return(sig_cb != NULL, FTDM_FAIL, "No signaling cb provided\n");
+       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)) {
+                       dchan = ftdmchan;
+                       break;
+               }
+       }
+       ftdm_iterator_free(chaniter);
 
-       if (span->signal_type) {
-               snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+       if (!dchan) {
+               ftdm_log(FTDM_LOG_CRIT, "Could not find a d-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;
 
-       for (; ftdm_parameters[paramindex].var; paramindex++) {
+       for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) {
                var = ftdm_parameters[paramindex].var;
                val = ftdm_parameters[paramindex].val;
-               ftdm_log(FTDM_LOG_DEBUG, "Reading GSM parameter %s for span %d\n", var, span->span_id);
+               if (!ftdm_strlen_zero_buf(val)) {
+                       ftdm_log(FTDM_LOG_WARNING, "Ignoring empty GSM parameter %s for span %s\n", var, val, span->name);
+                       continue;
+               }
+               ftdm_log(FTDM_LOG_DEBUG, "Reading GSM parameter %s=%s for span %s\n", var, val, span->name);
                if (!strcasecmp(var, "moduletype")) {
-                       if (!val) {
-                               break;
-                       }
-                       if (ftdm_strlen_zero_buf(val)) {
-                               ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty moduletype parameter\n");
+                       span_config.moduletype = wat_str2wat_moduletype(val);
+                       if (span_config.moduletype == WAT_MODULE_INVALID) {
+                               ftdm_log(FTDM_LOG_DEBUG, "Unknown GSM module type %s for span %s\n", val, span->name);
                                continue;
                        }
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring GSM span %d for moduletype %s\n", span->span_id, val);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring GSM span %s with moduletype %s\n", span->name, val);
                } else {
-                       snprintf(span->last_error, sizeof(span->last_error), "Unknown GSM parameter [%s]", var);
-                       return FTDM_FAIL;
+                       ftdm_log(FTDM_LOG_ERROR, "Ignoring unknown GSM parameter '%s'", var);
                }
        }
 
@@ -629,11 +574,12 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
 
        /* use signals queue */
        ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
+       ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
 
        /* we can skip states (going straight from RING to UP) */
        ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
 
-       
+       gsm_data->span = span;
 
 #if 0
        /* setup the scheduler (create if needed) */
@@ -642,208 +588,105 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
        spanpvt->sched = r2data->sched;
 #endif
 
-
-#if 0
-ftdm_log(FTDM_LOG_DEBUG, "Registering interface to WAT Library...\n");
-
-       gsm_data->wat_interface.wat_sigstatus_change = on_wat_sigstatus_change;
-       gsm_data->wat_interface.wat_span_write = on_wat_span_write;
        
-       gsm_data->wat_interface.wat_log = on_wat_log;
-       gsm_data->wat_interface.wat_log_span = on_wat_log_span; 
-       gsm_data->wat_interface.wat_malloc = on_wat_malloc;
-       gsm_data->wat_interface.wat_calloc = on_wat_calloc;
-       gsm_data->wat_interface.wat_free = on_wat_free;
-       
-       gsm_data->wat_interface.wat_alarm   = on_wat_span_alarm;
-       gsm_data->wat_interface.wat_con_ind = on_wat_con_ind;
-       gsm_data->wat_interface.wat_con_sts = on_wat_con_sts;
-       gsm_data->wat_interface.wat_rel_ind = on_wat_rel_ind;
-       gsm_data->wat_interface.wat_rel_cfm = on_wat_rel_cfm;
-       gsm_data->wat_interface.wat_sms_ind = on_wat_sms_ind;
-       gsm_data->wat_interface.wat_sms_sts = on_wat_sms_sts;
-       
-       if (wat_register(&gsm_data->wat_interface)) {
-               snprintf(span->last_error, sizeof(span->last_error), "Failed to register WAT Library !!!\n");
-               ftdm_log(FTDM_LOG_DEBUG, "FAILED Registering interface to WAT Library...\n");
+       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;
-
        }
-       ftdm_log(FTDM_LOG_DEBUG, "Registered interface to WAT Library\n");
-
-#endif
-
-
-       ftdm_log(FTDM_LOG_DEBUG, "Configuring span\n");
-
-       
-
-       wat_span_config_t _wat_span_config;
-
-
-       _wat_span_config.moduletype = WAT_MODULE_TELIT;
-       _wat_span_config.timeout_cid_num = 10;
-       
-       if (wat_span_config(span->span_id, &_wat_span_config)) {
-               fprintf(stderr, "Failed to configure span!!\n");
-               return FTDM_FAIL;
-       }
-
-/*
-       fprintf(stdout, "Starting span %d\n", span->span_id);
-       if (wat_span_start(span->span_id)) {
-               fprintf(stderr, "Failed to start span %d!!\n", span->span_id);
-               return FTDM_FAIL;
-       }
-
-
-               fprintf(stdout, "SUCCESS Starting span %d\n", span->span_id);
-
-       */
-       
-
 
        return FTDM_SUCCESS;
 
 }
 
+#define GSM_POLL_INTERVAL_MS 20
 static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj)
 {
-
-
-
        ftdm_channel_t *ftdmchan = NULL;
        ftdm_span_t *span = (ftdm_span_t *) obj;
-       ftdm_iterator_t *chaniter = NULL;
-       ftdm_iterator_t *citer = NULL;
-       int waitms = 10, i;
-       ftdm_status_t status;
-
-
-
+       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;
        
-fprintf(stdout, "Starting span %d\n", span->span_id);
-       
-       if (wat_span_start(span->span_id)) {
-       
-               fprintf(stderr, "Failed to start span %d!!\n", span->span_id);
-               return NULL;
-       }
+       gsm_data = span->signal_data;
 
-       
-               fprintf(stdout, "SUCCESS Starting span %d\n", span->span_id);
-       
+       ftdm_assert_return(gsm_data != NULL, NULL, "No gsm data attached to span\n");
 
-       short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count);
-       
-       unsigned next;
        ftdm_log(FTDM_LOG_DEBUG, "GSM monitor thread for span %s started\n", span->name);
-
-       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);
+       if (!gsm_data->dchan || ftdm_channel_open_chan(gsm_data->dchan) != FTDM_SUCCESS) {
+               ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open GSM d-channel of span %s!\n", span->name);
+               gsm_data->dchan = NULL;
                goto done;
        }
 
-  ftdmchan = get_channel(span->span_id, 2);
-
-       if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
-               ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open channel during incoming call! [%s]\n", ftdmchan->last_error);
-               return NULL;
+       /* 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()) {
 
+               wat_span_run(span->span_id);
 
-       wat_span_run(span->span_id);
-       next = wat_span_schedule_next(span->span_id);
-       if(next < waitms) {
-               next = waitms;
-       }
+               waitms = wat_span_schedule_next(span->span_id);
+               if (waitms > GSM_POLL_INTERVAL_MS) {
+                       waitms = GSM_POLL_INTERVAL_MS;
+               }
 
 #if 0
                /* run any span timers */
                ftdm_sched_run(r2data->sched);
                        
 #endif
-               /* deliver the actual channel events to the user now without any channel locking */
-               ftdm_span_trigger_signals(span);
-#if 0
-                /* figure ouwat_chip_info_tt what event to poll each channel for. POLLPRI when the channel is down,
-                 * POLLPRI|POLLIN|POLLOUT otherwise */
-               memset(poll_events, 0, sizeof(short)*span->chan_count);
-               citer = ftdm_span_get_chan_iterator(span, chaniter);
-               if (!citer) {
-                       ftdm_log(Fshort *poll_events = ftdm_malloc(sizeof(short) * span->chan_count);TDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
-                       goto done;short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count);
-               }
-               for (i = 0; citer; citer = ftdm_iterator_next(citer), i++) {
-                       ftdmchan = ftdm_iterator_current(citer);
-                       r2chan = R2CALL(ftdmchan)->r2chan;
-                       poll_events[i] = FTDM_EVENTS;
-                       if (openr2_chan_get_read_enabled(r2chan)) {
-                               poll_events[i] |= FTDM_READ;
+               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);
                        }
-               }
-               status = ftdm_span_poll_event(span, waitms, poll_events);
-
-               /* run any span timers */
-               ftdm_sched_runshort *poll_events = ftdm_malloc(sizeof(short) * span->chan_count);(r2data->sched);
-#endif
-               ftdm_sleep(waitms);
-
-
-               /* this main loop takes care of MF and CAS signaling during call setup and tear down
-                * for every single channel in the span, do not perform blocking operations here! */
-               citer = ftdm_span_get_chan_iterator(span, chaniter);
-               for ( ; citer; citer = ftdm_iterator_next(citer)) {
-                       ftdmchan = ftdm_iterator_current(citer);
-
-                       ftdm_channel_lock(ftdmchan);
-
-
-                       ftdm_channel_advance_states(ftdmchan);
-
-                       ftdm_channel_unlock(ftdmchan);
+                       break;
+               case FTDM_FAIL:
+                       ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned error!\n", span->name);
+                       break;
 
+               default:
+                       ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned with unknown code\n", span->name);
+                       break;
                }
 
-               for(i=0;i< span->chan_count; i++)
-                       poll_events[i] = FTDM_EVENTS;
-
-               poll_events[1]  |= FTDM_READ;
-               status = ftdm_span_poll_event(span, next, poll_events);
-
-               if(FTDM_SUCCESS == status)
-               {
-                       ftdm_channel_lock(ftdmchan);
-                       ftdm_channel_t * ftdm_chan = get_channel(span->span_id, 2);
-                       char buffer[2001];
-                       memset(buffer, 0, sizeof(buffer));
-                       unsigned int n = 0;
-                       n = read_channel(ftdm_chan , buffer, sizeof(buffer));
-                       
-                       ftdm_channel_unlock(ftdmchan);
-                       if(n > 0) {
-               
-                               wat_span_process_read(span->span_id, buffer, n);
-                               /*ftdm_log(FTDM_LOG_DEBUG, "<<<<<<<<<<<<<<<<<<<<<<===== %s (%d) - %d\n", buffer, n, (int) span->span_id);*/
-                               /*
-                               ftdm_log(FTDM_LOG_DEBUG, "!!! read_channel got %d bytes\n", n);
-                               */
-                       }
-                       else    {
-                               ftdm_sleep(waitms);
-                       }
-
-               }
        }
 
 done:
-       ftdm_iterator_free(chaniter);
+       if (data_sources[0]) {
+               ftdm_interrupt_destroy(&data_sources[0]);
+       }
 
        ftdm_log(FTDM_LOG_DEBUG, "GSM thread ending.\n");
 
@@ -856,86 +699,80 @@ done:
 "--------------------------------------------------------------------------------\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 (argc == 1) {
-               if (!strcasecmp(argv[0], "version")) {
-                       uint8_t current = 0, revision = 0, age = 0;
-                       wat_version(&current, &revision, &age);
-                       stream->write_function(stream, "libwat GSM VERSION: %d.%d.%d\n", current, revision, age);
-                       stream->write_function(stream, "+OK.\n");
-                       goto done;
+       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;
                }
 
-               if (!strcasecmp(argv[0], "status")) {
-                       
-                       int n;
-                       for(n = 0; n < n_spans_info; n++)
-                       {
-                               ftdm_span_t *span = spans_info[n].span;
-                               wat_chip_info_t* chip_info  = (wat_chip_info_t*)wat_span_get_chip_info(span->span_id);  
-                               wat_sim_info_t*  sim_info       = (wat_sim_info_t*)wat_span_get_sim_info(span->span_id);
-                               wat_net_info_t*  net_info       = (wat_net_info_t*)wat_span_get_net_info(span->span_id);
-                               /*wat_sig_info_t*  sig_info     = (wat_sig_info_t*)wat_span_get_sig_info(span->span_id);*/
-                               /*wat_pin_stat_t*  pin_stat     = (wat_pin_stat_t*)wat_span_get_pin_info(span->span_id);*/
-                               
-                               stream->write_function(stream, "Span %d:\n",  span->span_id);
-                               
-
-                               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
-                                       );              
-       
-                               const char *stypes[] = {WAT_NUMBER_TYPE_STRINGS };
-                               const char *ptypes[] = {WAT_NUMBER_PLAN_STRINGS };
-                               const char *validities[] = {WAT_NUMBER_VALIDITY_STRINGS };
+               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;
+               }
 
-                               stream->write_function(stream, "Subscriber - Number %s, Plan %s, validity %s\n", 
-                                               sim_info->subscriber.digits,
-                                               stypes[sim_info->subscriber.type],
-                                               ptypes[sim_info->subscriber.plan],
-                                               validities[sim_info->subscriber.validity]
+               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);
 
-                               const char *net_stats[] = {WAT_NET_STAT_STRINGS};
-                                                       
+               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, "Network - status %s, Area Code %d,  Cell ID %d, Operator %s\n", 
-                                       net_stats[net_info->stat],
-                                       net_info->lac,
-                                       net_info->ci,
-                                       net_info->operator_name
-                                       );              
+               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, "\n");
+               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, "+OK.\n");
-                       goto done;
-               }
+               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);