It simulates a simple voice call with client. Client could use ATD
to dial out a call and Server could use a pseudo command 'AT+INCM'
to notify an incoming call.
---
 gatchat/test-server.c |  419 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 419 insertions(+), 0 deletions(-)

diff --git a/gatchat/test-server.c b/gatchat/test-server.c
index fdb7475..0485f39 100644
--- a/gatchat/test-server.c
+++ b/gatchat/test-server.c
@@ -46,9 +46,16 @@
 #include "gatserver.h"
 #include "ringbuffer.h"
 
+#include "ofono/types.h"
+
 #define DEFAULT_TCP_PORT 12346
 #define DEFAULT_SOCK_PATH "./server_sock"
 
+#define INCOMING_CALL "1234567890"
+#define TIMEOUT_INTERVAL 2000
+#define TIMEOUT_DIAL 10000
+#define TIMEOUT_INCOMING 10000
+
 struct sock_server{
        int server_sock;
 };
@@ -57,8 +64,45 @@ static GMainLoop *mainloop;
 static GAtServer *server;
 unsigned int server_watch;
 
+unsigned int outgoing_source;
+unsigned int outgoing_timeout;
+unsigned int incoming_source;
+unsigned int incoming_timeout;
+unsigned int call_ids;
+static GSList *call_list;
+
+static void release_id(int id)
+{
+       call_ids &= ~(0x1 << id);
+}
+
+static void voicecall_destroy(gpointer data, gpointer user_data)
+{
+       struct ofono_call *call = data;
+
+       if (call) {
+               if (call->direction == 0 && outgoing_source) {
+                       g_source_remove(outgoing_source);
+                       outgoing_source = 0;
+               } else if (call->direction == 1 && incoming_source) {
+                       g_source_remove(incoming_source);
+                       incoming_source = 0;
+               }
+
+               release_id(call->id);
+       }
+
+       g_free(call);
+}
+
 static gboolean server_cleanup()
 {
+       if (call_list) {
+               g_slist_foreach(call_list, voicecall_destroy, NULL);
+               g_slist_free(call_list);
+               call_list = NULL;
+       }
+
        if (server_watch)
                g_source_remove(server_watch);
 
@@ -77,9 +121,384 @@ static void server_debug(const char *str, void *data)
        g_print("%s: %s\n", (char *) data, str);
 }
 
+static unsigned int alloc_next_id()
+{
+       unsigned int i;
+
+       for (i = 1; i < sizeof(call_ids) * 8; i++) {
+               if (call_ids & (0x1 << i))
+                       continue;
+
+               return i;
+       }
+
+       return 0;
+}
+
+static struct ofono_call *create_call(int type, int direction, int status,
+                                       const char *num, int num_type, int clip)
+{
+       struct ofono_call *call;
+
+       call = g_try_new0(struct ofono_call, 1);
+       if (!call)
+               return NULL;
+
+       call->id = alloc_next_id();
+       call->type = type;
+       call->direction = direction;
+       call->status = status;
+
+       if (clip != 2) {
+               strncpy(call->phone_number.number, num,
+                       OFONO_MAX_PHONE_NUMBER_LENGTH);
+               call->phone_number.type = num_type;
+       }
+
+       call->clip_validity = clip;
+
+       call_list = g_slist_prepend(call_list, call);
+
+       return call;
+}
+
+static void list_calls(GAtServer *server)
+{
+       GSList *text = NULL;
+       GSList *l;
+       char buf[512];
+       gboolean is_mpty = FALSE;
+
+       /* No calls */
+       if (!call_list)
+               return;
+
+       if (g_slist_length(call_list) > 1)
+               is_mpty = TRUE;
+
+       for (l = call_list; l; l = l->next) {
+               struct ofono_call *call = l->data;
+
+               /* +CLCC: <id>,<dir>,<stat>,<mode>,<mpty>[<number>,<type>] */
+               sprintf(buf, "+CLCC: %d,%d,%d,%d,%d,%s,%d",
+                                               call->id, call->direction,
+                                               call->status, call->type,
+                                               call->mpty,
+                                               call->phone_number.number,
+                                               call->phone_number.type);
+
+               text = g_slist_append(text, g_strdup(buf));
+       }
+
+       g_at_server_send_info_text(server, text);
+
+       g_slist_foreach(text, (GFunc) g_free, NULL);
+       g_slist_free(text);
+}
+
+static GAtServerResult at_clcc_cb(GAtServerRequestType type, GAtResult *result,
+                                       gpointer user_data)
+{
+       GAtServerResult res = G_AT_SERVER_RESULT_ERROR;
+       GAtResultIter iter;
+       GAtServer *server = user_data;
+
+       if (type == G_AT_SERVER_REQUEST_TYPE_SUPPORT) {
+               res = G_AT_SERVER_RESULT_OK;
+               goto done;
+       }
+
+       if (type != G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY)
+               goto done;
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "+CLCC"))
+               goto done;
+
+       list_calls(server);
+
+       res = G_AT_SERVER_RESULT_OK;
+
+done:
+       return res;
+}
+
+static gboolean hangup_current()
+{
+       struct ofono_call *call;
+
+       if (!call_list)
+               return FALSE;
+
+       call = call_list->data;
+       call_list = g_slist_remove(call_list, call);
+       voicecall_destroy(call, NULL);
+
+       return TRUE;
+}
+
+static gboolean hangup_specific(struct ofono_call *call)
+{
+       if (!call_list)
+               return FALSE;
+
+       call_list = g_slist_remove(call_list, call);
+       voicecall_destroy(call, NULL);
+
+       return TRUE;
+}
+
+static gboolean dial_timeout(gpointer user_data)
+{
+       struct ofono_call *call = user_data;
+
+       hangup_specific(call);
+
+       if (outgoing_source) {
+               g_source_remove(outgoing_source);
+               outgoing_source = 0;
+       }
+
+       outgoing_timeout = 0;
+
+       return FALSE;
+}
+
+static GAtServerResult dial_voicecall(const char *dial_str)
+{
+       GAtServerResult res = G_AT_SERVER_RESULT_ERROR;
+       char c;
+       char *number;
+       int len = strlen(dial_str);
+       struct ofono_call *call;
+
+       /* Skip last comma */
+       len--;
+
+       c = dial_str[len-1];
+       /* Skip closed user group flag */
+       if (c == 'G' || c == 'g')
+               len--;
+
+       c = dial_str[len-1];
+       /* Skip caller id suppress flag */
+       if (c == 'I' || c == 'i')
+               len--;
+
+       number = g_strndup(dial_str, len);
+
+       call = create_call(0, 0, 2, number, 129, 0);
+       if (!call)
+               goto done;
+
+       outgoing_timeout = g_timeout_add(TIMEOUT_DIAL,
+                                       (GSourceFunc) dial_timeout,
+                                       call);
+
+       res = G_AT_SERVER_RESULT_OK;
+
+done:
+       if (number)
+               g_free(number);
+
+       return res;
+}
+
+static GAtServerResult dial_call(GAtServer *server, const char *dial_str)
+{
+       GAtServerResult res = G_AT_SERVER_RESULT_ERROR;
+       int len = strlen(dial_str);
+
+       if (dial_str[0] == '*' || dial_str[0] == '#') {
+               /* Supplementary service request */
+               sleep(2);
+               g_at_server_send_intermediate(server, "CONNECT");
+               sleep(2);
+               res = G_AT_SERVER_RESULT_OK;
+               goto done;
+       }
+
+       if (dial_str[len-1] == ';') {
+               /* Voice call */
+               res = dial_voicecall(dial_str);
+
+       }
+
+done:
+       return res;
+}
+
+static GAtServerResult dial_cb(GAtServerRequestType type, GAtResult *result,
+                                       gpointer user_data)
+{
+       GAtServerResult res = G_AT_SERVER_RESULT_ERROR;
+       GAtResultIter iter;
+       const char *dial_str;
+       GAtServer *server = user_data;
+
+       if (type != G_AT_SERVER_REQUEST_TYPE_SET)
+               goto done;
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "D"))
+               goto done;
+
+       dial_str = g_at_result_iter_raw_line(&iter);
+       if (!dial_str)
+               goto done;
+
+       if (outgoing_source) {
+               g_source_remove(outgoing_source);
+               outgoing_source = 0;
+       }
+
+       res = dial_call(server, dial_str);
+
+done:
+       return res;
+}
+
+static GAtServerResult at_chup_cb(GAtServerRequestType type, GAtResult *result,
+                                       gpointer user_data)
+{
+       GAtServerResult res = G_AT_SERVER_RESULT_ERROR;
+       GAtResultIter iter;
+
+       if (type == G_AT_SERVER_REQUEST_TYPE_SUPPORT) {
+               res = G_AT_SERVER_RESULT_OK;
+               goto done;
+       }
+
+       if (type != G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY)
+               goto done;
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "+CHUP"))
+               goto done;
+
+       if (!hangup_current())
+               goto done;
+
+       res = G_AT_SERVER_RESULT_OK;
+
+done:
+       return res;
+}
+
+static GAtServerResult answer_cb(GAtServerRequestType type, GAtResult *result,
+                                       gpointer user_data)
+{
+       GAtServerResult res = G_AT_SERVER_RESULT_ERROR;
+       GAtResultIter iter;
+       struct ofono_call *call;
+
+       if (type != G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY)
+               goto done;
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "A"))
+               goto done;
+
+       if (incoming_source) {
+               g_source_remove(incoming_source);
+               incoming_source = 0;
+       }
+
+       if (!call_list)
+               goto done;
+
+       call = call_list->data;
+       call->status = 0;
+
+       res = G_AT_SERVER_RESULT_OK;
+
+done:
+       return res;
+}
+
+static gboolean ring_timeout(gpointer user_data)
+{
+       struct ofono_call *call = user_data;
+
+       hangup_specific(call);
+
+       if (incoming_source) {
+               g_source_remove(incoming_source);
+               incoming_source = 0;
+       }
+
+       incoming_timeout = 0;
+
+       return FALSE;
+}
+
+static gboolean ring_notify(gpointer user_data)
+{
+       GAtServer *server = user_data;
+       char buf[100];
+
+       /* Notify a new incoming call to client */
+       g_at_server_send_unsolicited(server, "RING");
+
+       sprintf(buf, "+CLIP: \"%s\",129", INCOMING_CALL);
+       g_at_server_send_unsolicited(server, buf);
+
+       return TRUE;
+}
+
+static GAtServerResult at_incm_cb(GAtServerRequestType type, GAtResult *result,
+                                       gpointer user_data)
+{
+       GAtServerResult res = G_AT_SERVER_RESULT_ERROR;
+       GAtResultIter iter;
+       GAtServer *server = user_data;
+       struct ofono_call *call;
+
+       if (type != G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY)
+               goto done;
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "+INCM"))
+               goto done;
+
+       /* Remove existing incoming call if exists */
+       if (incoming_source) {
+               g_source_remove(incoming_source);
+               incoming_source = 0;
+       }
+
+       call = create_call(0, 1, 4, INCOMING_CALL, 129, 0);
+       if (!call)
+               goto done;
+
+       incoming_source = g_timeout_add(TIMEOUT_INTERVAL,
+                                       (GSourceFunc) ring_notify, server);
+
+       incoming_timeout = g_timeout_add(TIMEOUT_INCOMING,
+                                       (GSourceFunc) ring_timeout, call);
+
+       res = G_AT_SERVER_RESULT_OK;
+
+done:
+       return res;
+}
+
 static void add_handler(GAtServer *server)
 {
        g_at_server_set_debug(server, server_debug, "Server");
+
+       g_at_server_register(server, "D", dial_cb, server, NULL);
+       g_at_server_register(server, "A", answer_cb, server, NULL);
+       g_at_server_register(server, "+CLCC", at_clcc_cb, server, NULL);
+       g_at_server_register(server, "+CHUP", at_chup_cb, server, NULL);
+
+       /* Psuedo command to notify an incoming call to the client */
+       g_at_server_register(server, "+INCM", at_incm_cb, server, NULL);
 }
 
 static void server_destroy(gpointer user)
-- 
1.6.6.1

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to