uint32_t chan_id = 0;
uint32_t span_id = 0;
uint32_t chan_count = 0;
+ ftdm_status_t status;
ftdm_span_t *span = NULL;
ftdm_channel_t *chan = NULL;
if (chan_id) {
chan = ftdm_span_get_channel(span, chan_id);
+
snprintf(tracepath, sizeof(tracepath), "%s-in-s%dc%d", argv[1], span_id, chan_id);
- ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
+ status = ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
+ if (status != FTDM_SUCCESS) {
+ stream->write_function(stream, "-ERR failed to enable input trace at path %s\n", tracepath);
+ goto end;
+ }
+
snprintf(tracepath, sizeof(tracepath), "%s-out-s%dc%d", argv[1], span_id, chan_id);
- ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
+ status = ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
+ if (status != FTDM_SUCCESS) {
+ stream->write_function(stream, "-ERR failed to enable output trace at path %s\n", tracepath);
+ ftdm_channel_command(chan, FTDM_COMMAND_TRACE_END_ALL, NULL);
+ goto end;
+ }
} else {
for (i = 1; i <= chan_count; i++) {
chan = ftdm_span_get_channel(span, i);
+
snprintf(tracepath, sizeof(tracepath), "%s-in-s%dc%d", argv[1], span_id, i);
- ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
+ status = ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
+ if (status != FTDM_SUCCESS) {
+ stream->write_function(stream, "-ERR failed to enable input trace at path %s\n", tracepath);
+ goto end;
+ }
+
snprintf(tracepath, sizeof(tracepath), "%s-out-s%dc%d", argv[1], span_id, i);
- ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
+ status = ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
+ if (status != FTDM_SUCCESS) {
+ stream->write_function(stream, "-ERR failed to enable output trace at path %s\n", tracepath);
+ ftdm_channel_command(chan, FTDM_COMMAND_TRACE_END_ALL, NULL);
+ goto end;
+ }
}
}
stream->write_function(stream, "+OK trace enabled with prefix path %s\n", argv[1]);
"ftdm gsm status <span_id|span_name>\n" \
"ftdm gsm sms <span_id|span_name> <destination> <text>\n" \
"ftdm gsm exec <span_id|span_name> <command string>\n" \
+"ftdm gsm call <span_id|span_name> [number]\n" \
"--------------------------------------------------------------------------------\n"
// Used to declare command handler
ftdm_channel_t *bchan;
int32_t call_id;
uint32_t sms_id;
+ char conditional_forward_number[255];
+ ftdm_sched_t *sched;
+ ftdm_timer_id_t conditional_forwarding_timer;
} ftdm_gsm_span_data_t;
// command handler function type.
return len;
}
+static void ftdm_gsm_make_raw_call(ftdm_gsm_span_data_t *gsm_data, const char *number)
+{
+ wat_con_event_t con_event;
+
+ ftdm_channel_lock(gsm_data->bchan);
+
+ if (ftdm_test_flag(gsm_data->bchan, FTDM_CHANNEL_INUSE)) {
+ ftdm_log_chan(gsm_data->bchan, FTDM_LOG_ERROR, "Failed to place raw call to %s: channel busy\n", number);
+ goto done;
+ }
+
+ ftdm_log_chan(gsm_data->bchan, FTDM_LOG_INFO, "Placing raw call to %s\n", number);
+ ftdm_set_flag(gsm_data->bchan, FTDM_CHANNEL_INUSE);
+
+ gsm_data->call_id = g_outbound_call_id++;
+ memset(&con_event, 0, sizeof(con_event));
+ ftdm_set_string(con_event.called_num.digits, number);
+ wat_con_req(gsm_data->span->span_id, gsm_data->call_id , &con_event);
+
+done:
+ ftdm_channel_unlock(gsm_data->bchan);
+}
+
+static void ftdm_gsm_enable_conditional_forwarding(void *data)
+{
+ ftdm_gsm_span_data_t *gsm_data = data;
+ ftdm_log_chan(gsm_data->bchan, FTDM_LOG_NOTICE, "Enabling conditional forwarding to %s\n", gsm_data->conditional_forward_number);
+ ftdm_gsm_make_raw_call(data, gsm_data->conditional_forward_number);
+}
+
static void on_wat_span_status(unsigned char span_id, wat_span_status_t *status)
{
+ ftdm_span_t *span = NULL;
+ ftdm_gsm_span_data_t *gsm_data = NULL;
+ if (!(span = GetSpanByID(span_id, &gsm_data))) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to get span from id %d\n", span_id);
+ return;
+ }
+ gsm_data = span->signal_data;
+
switch (status->type) {
case WAT_SPAN_STS_READY:
{
case WAT_SPAN_STS_SIGSTATUS:
{
if (status->sts.sigstatus == WAT_SIGSTATUS_UP) {
- ftdm_log(FTDM_LOG_INFO, "span %d: Signaling is now up\n", span_id);
+ ftdm_log_chan_msg(gsm_data->bchan, FTDM_LOG_INFO, "Signaling is now up\n");
} else {
- ftdm_log(FTDM_LOG_INFO, "span %d: Signaling is now down\n", span_id);
+ ftdm_log_chan_msg(gsm_data->bchan, FTDM_LOG_INFO, "Signaling is now down\n");
+ }
+ if (!ftdm_strlen_zero_buf(gsm_data->conditional_forward_number)) {
+ ftdm_sched_timer(gsm_data->sched, "conditional_forwarding_delay", 500,
+ ftdm_gsm_enable_conditional_forwarding,
+ gsm_data,
+ &gsm_data->conditional_forwarding_timer);
}
}
break;
{
ftdm_span_t *span = NULL;
+ ftdm_channel_state_t state = FTDM_CHANNEL_STATE_END;
//ftdm_status_t ftdm_status = FTDM_FAIL;
ftdm_gsm_span_data_t *gsm_data = NULL;
- if(!(span = GetSpanByID(span_id, &gsm_data))) {
+ if (!(span = GetSpanByID(span_id, &gsm_data))) {
return;
}
-
-
- switch(status->type) {
-
+ 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);
+ ftdm_log_chan_msg(gsm_data->bchan, FTDM_LOG_INFO, "Received ringing indication\n");
+ state = 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);
+ ftdm_log_chan_msg(gsm_data->bchan, FTDM_LOG_INFO, "Received answer indication\n");
+ state = FTDM_CHANNEL_STATE_PROGRESS_MEDIA;
break;
+
default:
- ftdm_log(FTDM_LOG_INFO, "on_wat_con_sts - Unhandled state %d\n", span_id);
+ ftdm_log_chan(gsm_data->bchan, FTDM_LOG_WARNING, "Unhandled indication status %d\n", status->type);
+ break;
};
-
-
- return;
+
+ if (state != FTDM_CHANNEL_STATE_END && gsm_data->bchan->state != FTDM_CHANNEL_STATE_DOWN) {
+ ftdm_set_state(gsm_data->bchan, state);
+ }
}
void on_wat_rel_ind(unsigned char span_id, uint8_t call_id, wat_rel_event_t *rel_event)
if (gsm_data->bchan->state == FTDM_CHANNEL_STATE_HANGUP ||
gsm_data->bchan->state == FTDM_CHANNEL_STATE_DOWN) {
+ /* this might be due to a call to enable call forwarding,
+ * which does not run the state machine */
return;
}
ftdm_log(FTDM_LOG_INFO, "s%d: Call hangup complete (id:%d)\n", span_id, call_id);
- if(!(span = GetSpanByID(span_id, &gsm_data))) {
+ if (!(span = GetSpanByID(span_id, &gsm_data))) {
+ return;
+ }
+
+ if (gsm_data->bchan->state == FTDM_CHANNEL_STATE_DOWN) {
+ /* this is most likely a call forwarding enable call, which do not run the state machine */
+ ftdm_clear_flag(gsm_data->bchan, FTDM_CHANNEL_INUSE);
return;
}
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)
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);
}
return FTDM_SUCCESS;
}
+static ftdm_status_t ftdm_gsm_destroy(ftdm_span_t *span)
+{
+ ftdm_gsm_span_data_t *gsm_data = span->signal_data;
+ ftdm_assert_return(gsm_data != NULL, FTDM_FAIL, "Span does not have GSM data!\n");
+ if (gsm_data->sched) {
+ ftdm_sched_destroy(&gsm_data->sched);
+ }
+ ftdm_free(gsm_data);
+ return FTDM_SUCCESS;
+}
+
static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_gsm_get_channel_sig_status)
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
unsigned paramindex = 0;
const char *var = NULL;
const char *val = NULL;
+ char schedname[255];
int codec = FTDM_CODEC_SLIN;
int interval = 20;
span_config.hardware_dtmf = WAT_FALSE;
}
ftdm_log(FTDM_LOG_DEBUG, "Configuring GSM span %s with hardware dtmf %s\n", span->name, val);
+ } else if (!strcasecmp(var, "conditional-forwarding-number")) {
+ ftdm_set_string(gsm_data->conditional_forward_number, val);
} else {
ftdm_log(FTDM_LOG_ERROR, "Ignoring unknown GSM parameter '%s'", var);
}
/* Bind function pointers for control operations */
span->start = ftdm_gsm_start;
span->stop = ftdm_gsm_stop;
+ span->destroy = ftdm_gsm_destroy;
span->sig_read = NULL;
span->sig_write = NULL;
if (hwdtmf_detect || hwdtmf_generate) {
gsm_data->span = span;
+ /* Setup the scheduler */
+ snprintf(schedname, sizeof(schedname), "ftmod_gsm_%s", span->name);
+ if (ftdm_sched_create(&gsm_data->sched, schedname) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to setup scheduler for span %s!\n", span->name);
+ ftdm_gsm_destroy(span);
+ return FTDM_FAIL;
+ }
+
+ /* Start the signaling stack */
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);
+ ftdm_gsm_destroy(span);
return FTDM_FAIL;
}
ftdm_status_t status = FTDM_SUCCESS;
char buffer[1025] = { 0 };
int waitms = 0;
+ ftdm_wait_flag_t flags = 0;
+ ftdm_status_t status;
- ftdm_log(FTDM_LOG_INFO,"ftdm_gsm_run\r\n");
-
gsm_data = span->signal_data;
-
ftdm_assert_return(gsm_data != NULL, NULL, "No gsm data attached to span\n");
ftdm_log(FTDM_LOG_DEBUG, "GSM monitor thread for span %s started\n", span->name);
while (ftdm_running()) {
wat_span_run(span->span_id);
+ ftdm_sched_run(gsm_data->sched);
waitms = wat_span_schedule_next(span->span_id);
if (waitms > GSM_POLL_INTERVAL_MS) {
return (FTDM_SUCCESS);
}
-static FIO_SIG_LOAD_FUNCTION(ftdm_gsm_init)
-{
- /* this is called on module load */
- return FTDM_SUCCESS;
-}
-
-static FIO_SIG_UNLOAD_FUNCTION(ftdm_gsm_destroy)
-{
- /* this is called on module unload */
- return FTDM_SUCCESS;
-}
EX_DECLARE_DATA ftdm_module_t ftdm_module = {
/* .name */ "gsm",
/* .io_load */ ftdm_gsm_io_init,
/* .io_unload */ NULL,
- /* .sig_load */ ftdm_gsm_init,
+ /* .sig_load */ NULL,
/* .sig_configure */ NULL,
- /* .sig_unload */ ftdm_gsm_destroy,
+ /* .sig_unload */ NULL,
/* .configure_span_signaling */ ftdm_gsm_configure_span_signaling
};
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]);
+ stream->write_function(stream, "-ERR Failed to find GSM span '%s'\n", argv[0]);
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]);
+ stream->write_function(stream, "-ERR '%s' is not a valid GSM span\n", argv[0]);
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
+// AT Command Handler
+COMMAND_HANDLER(call)
+{
+ int span_id = 0;
+ ftdm_span_t *span = 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[0]);
+ 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[0]);
+ return FTDM_FAIL;
+ }
+
+ ftdm_gsm_make_raw_call(span->signal_data, argv[1]);
+ stream->write_function(stream, "+OK\n");
+ return FTDM_SUCCESS;
+}
+
// command map
struct {
const char*CMD; // command
COMMAND(version, 0),
COMMAND(status, 1),
COMMAND(sms, 3),
- COMMAND(exec, 2)
+ COMMAND(exec, 2),
+ COMMAND(call, 2),
};
// Commnand API entry point