* [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer
@ 2010-01-11 10:53 Zhenhua Zhang
2010-01-11 10:53 ` [PATCH 2/4] Add GAtServer basic parsing support Zhenhua Zhang
2010-01-14 15:49 ` [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Denis Kenzior
0 siblings, 2 replies; 10+ messages in thread
From: Zhenhua Zhang @ 2010-01-11 10:53 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 10937 bytes --]
Add gatutil.c/gatutil.h and move shared typedef and APIs into it.
So that they can be shared by GAtServer.
---
Makefile.am | 3 +-
gatchat/gatchat.c | 98 +++-------------------------------------
gatchat/gatchat.h | 8 +---
gatchat/gatutil.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++
gatchat/gatutil.h | 46 +++++++++++++++++++
5 files changed, 186 insertions(+), 100 deletions(-)
create mode 100644 gatchat/gatutil.c
create mode 100644 gatchat/gatutil.h
diff --git a/Makefile.am b/Makefile.am
index 276b478..67882b9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,7 +51,8 @@ gatchat_sources = gatchat/gatchat.h gatchat/gatchat.c \
gatchat/ringbuffer.h gatchat/ringbuffer.c \
gatchat/gatmux.h gatchat/gatmux.c \
gatchat/gsm0710.h gatchat/gsm0710.c \
- gatchat/gattty.h gatchat/gattty.c
+ gatchat/gattty.h gatchat/gattty.c \
+ gatchat/gatutil.h gatchat/gatutil.c
udev_files = plugins/ofono.rules
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c
index 8045c6b..e5cf235 100644
--- a/gatchat/gatchat.c
+++ b/gatchat/gatchat.c
@@ -40,7 +40,6 @@
static const char *none_prefix[] = { NULL };
static void g_at_chat_wakeup_writer(GAtChat *chat);
-static void debug_chat(GAtChat *chat, gboolean in, const char *str, gsize len);
struct at_command {
char *cmd;
@@ -686,81 +685,6 @@ static void new_bytes(GAtChat *p)
g_at_chat_unref(p);
}
-static void debug_chat(GAtChat *chat, gboolean in, const char *str, gsize len)
-{
- char type = in ? '<' : '>';
- gsize escaped = 2; /* Enough for '<', ' ' */
- char *escaped_str;
- const char *esc = "<ESC>";
- gsize esc_size = strlen(esc);
- const char *ctrlz = "<CtrlZ>";
- gsize ctrlz_size = strlen(ctrlz);
- gsize i;
-
- if (!chat->debugf || !len)
- return;
-
- for (i = 0; i < len; i++) {
- char c = str[i];
-
- if (isprint(c))
- escaped += 1;
- else if (c == '\r' || c == '\t' || c == '\n')
- escaped += 2;
- else if (c == 26)
- escaped += ctrlz_size;
- else if (c == 25)
- escaped += esc_size;
- else
- escaped += 4;
- }
-
- escaped_str = g_malloc(escaped + 1);
- escaped_str[0] = type;
- escaped_str[1] = ' ';
- escaped_str[2] = '\0';
- escaped_str[escaped] = '\0';
-
- for (escaped = 2, i = 0; i < len; i++) {
- char c = str[i];
-
- switch (c) {
- case '\r':
- escaped_str[escaped++] = '\\';
- escaped_str[escaped++] = 'r';
- break;
- case '\t':
- escaped_str[escaped++] = '\\';
- escaped_str[escaped++] = 't';
- break;
- case '\n':
- escaped_str[escaped++] = '\\';
- escaped_str[escaped++] = 'n';
- break;
- case 26:
- strncpy(&escaped_str[escaped], ctrlz, ctrlz_size);
- escaped += ctrlz_size;
- break;
- case 25:
- strncpy(&escaped_str[escaped], esc, esc_size);
- escaped += esc_size;
- break;
- default:
- if (isprint(c))
- escaped_str[escaped++] = c;
- else {
- escaped_str[escaped++] = '\\';
- escaped_str[escaped++] = '0' + ((c >> 6) & 07);
- escaped_str[escaped++] = '0' + ((c >> 3) & 07);
- escaped_str[escaped++] = '0' + (c & 07);
- }
- }
- }
-
- chat->debugf(escaped_str, chat->debug_data);
- g_free(escaped_str);
-}
-
static gboolean received_data(GIOChannel *channel, GIOCondition cond,
gpointer data)
{
@@ -786,7 +710,8 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
buf = ring_buffer_write_ptr(chat->buf);
err = g_io_channel_read(channel, (char *) buf, toread, &rbytes);
- debug_chat(chat, TRUE, (char *)buf, rbytes);
+ g_at_util_debug_chat(chat->debugf, TRUE, (char *)buf, rbytes,
+ chat->debug_data);
total_read += rbytes;
@@ -932,8 +857,9 @@ static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
return FALSE;
}
- debug_chat(chat, FALSE, cmd->cmd + chat->cmd_bytes_written,
- bytes_written);
+ g_at_util_debug_chat(chat->debugf, FALSE,
+ cmd->cmd + chat->cmd_bytes_written,
+ bytes_written, chat->debug_data);
chat->cmd_bytes_written += bytes_written;
if (bytes_written < towrite)
@@ -961,7 +887,6 @@ static void g_at_chat_wakeup_writer(GAtChat *chat)
GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax)
{
GAtChat *chat;
- GIOFlags io_flags;
if (!channel)
return NULL;
@@ -992,20 +917,9 @@ GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax)
chat->notify_list = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, (GDestroyNotify)at_notify_destroy);
- if (g_io_channel_set_encoding(channel, NULL, NULL) !=
- G_IO_STATUS_NORMAL)
- goto error;
-
- io_flags = g_io_channel_get_flags(channel);
-
- io_flags |= G_IO_FLAG_NONBLOCK;
-
- if (g_io_channel_set_flags(channel, io_flags, NULL) !=
- G_IO_STATUS_NORMAL)
+ if (!g_at_util_set_io(channel))
goto error;
- g_io_channel_set_close_on_unref(channel, TRUE);
-
chat->channel = channel;
chat->read_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
diff --git a/gatchat/gatchat.h b/gatchat/gatchat.h
index 999b92d..3c3fa5d 100644
--- a/gatchat/gatchat.h
+++ b/gatchat/gatchat.h
@@ -26,19 +26,13 @@
extern "C" {
#endif
-#include "gatresult.h"
#include "gatsyntax.h"
+#include "gatutil.h"
struct _GAtChat;
typedef struct _GAtChat GAtChat;
-typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
- gpointer user_data);
-typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);
-typedef void (*GAtDisconnectFunc)(gpointer user_data);
-typedef void (*GAtDebugFunc)(const char *str, gpointer user_data);
-
GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax);
GIOChannel *g_at_chat_get_channel(GAtChat *chat);
diff --git a/gatchat/gatutil.c b/gatchat/gatutil.c
new file mode 100644
index 0000000..585a590
--- /dev/null
+++ b/gatchat/gatutil.c
@@ -0,0 +1,131 @@
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+#include <glib.h>
+
+#include "gatutil.h"
+
+void g_at_util_debug_chat(GAtDebugFunc debugf, gboolean in, const char *str,
+ gsize len, gpointer user_data)
+{
+ char type = in ? '<' : '>';
+ gsize escaped = 2; /* Enough for '<', ' ' */
+ char *escaped_str;
+ const char *esc = "<ESC>";
+ gsize esc_size = strlen(esc);
+ const char *ctrlz = "<CtrlZ>";
+ gsize ctrlz_size = strlen(ctrlz);
+ gsize i;
+
+ if (!debugf || !len)
+ return;
+
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+
+ if (isprint(c))
+ escaped += 1;
+ else if (c == '\r' || c == '\t' || c == '\n')
+ escaped += 2;
+ else if (c == 26)
+ escaped += ctrlz_size;
+ else if (c == 25)
+ escaped += esc_size;
+ else
+ escaped += 4;
+ }
+
+ escaped_str = g_malloc(escaped + 1);
+ escaped_str[0] = type;
+ escaped_str[1] = ' ';
+ escaped_str[2] = '\0';
+ escaped_str[escaped] = '\0';
+
+ for (escaped = 2, i = 0; i < len; i++) {
+ char c = str[i];
+
+ switch (c) {
+ case '\r':
+ escaped_str[escaped++] = '\\';
+ escaped_str[escaped++] = 'r';
+ break;
+ case '\t':
+ escaped_str[escaped++] = '\\';
+ escaped_str[escaped++] = 't';
+ break;
+ case '\n':
+ escaped_str[escaped++] = '\\';
+ escaped_str[escaped++] = 'n';
+ break;
+ case 26:
+ strncpy(&escaped_str[escaped], ctrlz, ctrlz_size);
+ escaped += ctrlz_size;
+ break;
+ case 25:
+ strncpy(&escaped_str[escaped], esc, esc_size);
+ escaped += esc_size;
+ break;
+ default:
+ if (isprint(c))
+ escaped_str[escaped++] = c;
+ else {
+ escaped_str[escaped++] = '\\';
+ escaped_str[escaped++] = '0' + ((c >> 6) & 07);
+ escaped_str[escaped++] = '0' + ((c >> 3) & 07);
+ escaped_str[escaped++] = '0' + (c & 07);
+ }
+ }
+ }
+
+ debugf(escaped_str, user_data);
+ g_free(escaped_str);
+}
+
+gboolean g_at_util_set_io(GIOChannel *io)
+{
+ GIOFlags io_flags;
+
+ if (g_io_channel_set_encoding(io, NULL, NULL) !=
+ G_IO_STATUS_NORMAL)
+ return FALSE;
+
+ io_flags = g_io_channel_get_flags(io);
+
+ io_flags |= G_IO_FLAG_NONBLOCK;
+ io_flags |= G_IO_FLAG_IS_READABLE;
+ io_flags |= G_IO_FLAG_IS_WRITEABLE;
+
+ if (g_io_channel_set_flags(io, io_flags, NULL) !=
+ G_IO_STATUS_NORMAL)
+ return FALSE;
+
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ return TRUE;
+}
+
diff --git a/gatchat/gatutil.h b/gatchat/gatutil.h
new file mode 100644
index 0000000..63bbfff
--- /dev/null
+++ b/gatchat/gatutil.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GATUTIL_H
+#define __GATUTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gatresult.h"
+
+typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
+ gpointer user_data);
+typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);
+typedef void (*GAtDisconnectFunc)(gpointer user_data);
+typedef void (*GAtDebugFunc)(const char *str, gpointer user_data);
+
+void g_at_util_debug_chat(GAtDebugFunc debugf, gboolean in, const char *str,
+ gsize len, gpointer user_data);
+
+gboolean g_at_util_set_io(GIOChannel *io);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GATUTIL_H */
--
1.6.3.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/4] Add GAtServer basic parsing support
2010-01-11 10:53 [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Zhenhua Zhang
@ 2010-01-11 10:53 ` Zhenhua Zhang
2010-01-11 10:53 ` [PATCH 3/4] Add AT command parsing support and interface Zhenhua Zhang
2010-01-14 17:24 ` [PATCH 2/4] Add GAtServer basic parsing support Denis Kenzior
2010-01-14 15:49 ` [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Denis Kenzior
1 sibling, 2 replies; 10+ messages in thread
From: Zhenhua Zhang @ 2010-01-11 10:53 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 13257 bytes --]
It's the basic skeleton of GAtServer, including new/shutdown, ref/
unref, received_data/parse_buffer and set_discuss/set_debug.
GAtServer is to emulate the server side of AT conversation. It
complies with V.250 and 27.007 spec to accept AT command like
ATV1, ATE0 and extended command like AT+CLCC. Upper layer could
create customize server to expose TTY, tcp or unix socket to client
side application.
---
Makefile.am | 3 +-
gatchat/gatserver.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++
gatchat/gatserver.h | 65 ++++++++
3 files changed, 495 insertions(+), 1 deletions(-)
create mode 100644 gatchat/gatserver.c
create mode 100644 gatchat/gatserver.h
diff --git a/Makefile.am b/Makefile.am
index 67882b9..50dabca 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -52,7 +52,8 @@ gatchat_sources = gatchat/gatchat.h gatchat/gatchat.c \
gatchat/gatmux.h gatchat/gatmux.c \
gatchat/gsm0710.h gatchat/gsm0710.c \
gatchat/gattty.h gatchat/gattty.c \
- gatchat/gatutil.h gatchat/gatutil.c
+ gatchat/gatutil.h gatchat/gatutil.c \
+ gatchat/gatserver.h gatchat/gatserver.c
udev_files = plugins/ofono.rules
diff --git a/gatchat/gatserver.c b/gatchat/gatserver.c
new file mode 100644
index 0000000..e861e25
--- /dev/null
+++ b/gatchat/gatserver.c
@@ -0,0 +1,428 @@
+/*
+ *
+ * AT server library with GLib integration
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "ringbuffer.h"
+#include "gatresult.h"
+#include "gatserver.h"
+
+#define DBG(fmt, arg...) g_print("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg)
+
+struct result_codes {
+ const char *v1;
+ unsigned int v0;
+};
+
+/* V.250 Table 1/V.250 Result codes */
+static struct result_codes at_server_result_codes[] = {
+ { "OK", 0, },
+ { "CONNECT", 1, },
+ { "RING", 2, },
+ { "NO CARRIER", 3, },
+ { "ERROR", 4, },
+ { "NO DIALTONE", 5, },
+ { "BUSY", 6, },
+ { "NO ANSWER", 7, },
+ { "CONNECT", 8, },
+ { NULL },
+};
+
+/* Basic command setting for V.250 */
+struct v250_settings {
+ char s3; /* set by S3=<val> */
+ char s4; /* set by S4=<val> */
+ char s5; /* set by S5=<val> */
+ gboolean echo; /* set by E<val> */
+ gboolean quiet; /* set by Q<val> */
+ gboolean is_v1; /* set by V<val>, v0 or v1 */
+ unsigned int res_format; /* set by X<val> */
+ unsigned int c109; /* set by &C<val> */
+ unsigned int c108; /* set by &D<val> */
+};
+
+struct _GAtServer {
+ gint ref_count; /* Ref count */
+ struct v250_settings *v250; /* V.250 command setting */
+ GIOChannel *server_io; /* Server IO */
+ int server_watch; /* Watch for server IO */
+ char *modem_path; /* Emulated modem path */
+ GAtDisconnectFunc user_disconnect; /* User disconnect func */
+ gpointer user_disconnect_data; /* User disconnect data */
+ GAtDebugFunc debugf; /* Debugging output function */
+ gpointer debug_data; /* Data to pass to debug func */
+ struct ring_buffer *buf; /* Current read buffer */
+};
+
+static int at_server_parse(GAtServer *server, char *buf);
+
+static void g_at_server_send_result_code(GAtServer *server, int error)
+{
+ struct v250_settings *v250 = server->v250;
+ char buf[1024];
+ char text[1024];
+ char t = v250->s3;
+ char r = v250->s4;
+ struct result_codes c;
+ gsize wbuf;
+
+ memset(buf, 0, sizeof(buf));
+ memset(text, 0, sizeof(text));
+
+ if (v250->quiet)
+ return;
+
+ c = at_server_result_codes[error];
+
+ if (v250->is_v1)
+ sprintf(text, "%s", c.v1);
+ else
+ sprintf(text, "%d", c.v0);
+
+ if (v250->is_v1)
+ sprintf(buf, "%c%c%s%c%c", t, r, text, t, r);
+ else
+ sprintf(buf, "%s%c", text, t);
+
+ g_at_util_debug_chat(server->debugf, FALSE, buf, strlen(buf),
+ server->debug_data);
+
+ g_io_channel_write(server->server_io, (char *) buf, strlen(buf),
+ &wbuf);
+}
+
+static gsize skip_space(const char *buf, gsize pos)
+{
+ gsize i = pos;
+ char c = buf[i];
+
+ while (c == ' ')
+ c = buf[++i];
+
+ return i;
+}
+
+static int parse_v250_settings(GAtServer *server, char *buf)
+{
+ int res = G_AT_SERVER_RESULT_ERROR;
+
+ return res;
+}
+
+static int at_server_parse(GAtServer *server, char *buf)
+{
+ int res = G_AT_SERVER_RESULT_ERROR;
+ struct v250_settings *v250 = server->v250;
+ gsize i = 0;
+ char c;
+
+ /* skip space after "AT" or previous command */
+ i = skip_space(buf, i);
+
+ c = buf[i];
+ /* skip semicolon */
+ if (c == ';')
+ c = buf[++i];
+
+ if (g_ascii_isalpha(c) || c == '&')
+ res = parse_v250_settings(server, buf + i);
+ else if (c == v250->s3)
+ res = G_AT_SERVER_RESULT_OK;
+
+ return res;
+}
+
+static void parse_buffer(GAtServer *server, unsigned int len)
+{
+ int res = G_AT_SERVER_RESULT_ERROR;
+ gsize i = 0;
+ char *buf = NULL;
+
+ g_at_server_ref(server);
+
+ buf = g_try_new0(char, len+1);
+
+ if (!buf)
+ goto out;
+
+ if (-1 == ring_buffer_read(server->buf, buf, len))
+ goto out;
+
+ buf[len] = '\0';
+
+ DBG("received %s\n", buf);
+
+ /* skip header space */
+ buf += skip_space(buf, i);
+
+ /* Make sure the command line prefix is "AT" or "at" */
+ if (g_str_has_prefix(buf, "AT") ||
+ g_str_has_prefix(buf, "at"))
+ res = at_server_parse(server, (char *) buf + 2);
+
+ g_at_server_send_result_code(server, res);
+
+out:
+ /* We're overflowing the buffer, shutdown the socket */
+ if (server->buf && ring_buffer_avail(server->buf) == 0)
+ g_at_server_shutdown(server);
+
+ g_at_server_unref(server);
+}
+
+static gboolean received_data(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ GAtServer *server = data;
+ struct v250_settings *v250 = server->v250;
+ GIOError err;
+ gsize rbytes;
+ gsize total_read = 0;
+ unsigned char *total_buf = ring_buffer_write_ptr(server->buf);
+ static gsize total_len;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ g_at_server_shutdown(server);
+
+ return FALSE;
+ }
+
+ /* Regardless of condition, try to read all the data available */
+ do {
+ unsigned char *buf;
+ gsize toread;
+
+ rbytes = 0;
+
+ toread = ring_buffer_avail_no_wrap(server->buf);
+
+ if (toread == 0)
+ break;
+
+ buf = ring_buffer_write_ptr(server->buf);
+
+ err = g_io_channel_read(chan, (char *) buf, toread, &rbytes);
+
+ total_read += rbytes;
+
+ if (rbytes > 0)
+ ring_buffer_write_advance(server->buf, rbytes);
+
+ } while (err == G_IO_ERROR_NONE && rbytes > 0);
+
+ g_at_util_debug_chat(server->debugf, TRUE, (char *) total_buf,
+ total_read, server->debug_data);
+
+ if (total_read == 0) {
+ g_at_server_shutdown(server);
+
+ return FALSE;
+ }
+
+ total_len += total_read;
+
+ /* Add '\0' to perform strchr */
+ total_buf[total_read] = '\0';
+
+ /* Parse buffer until we meet the terminator so that
+ * all preceding characters will be processed
+ */
+ if (strchr((char *) total_buf, v250->s3)) {
+ parse_buffer(server, total_len);
+
+ total_len = 0;
+ }
+
+ if (err != G_IO_ERROR_NONE && err != G_IO_ERROR_AGAIN)
+ return FALSE;
+
+ return TRUE;
+}
+
+static struct v250_settings *v250_settings_create()
+{
+ struct v250_settings *v250;
+
+ v250 = g_try_new0(struct v250_settings, 1);
+
+ if (!v250)
+ return NULL;
+
+ v250->s3 = '\r';
+ v250->s4 = '\n';
+ v250->s5 = '\b';
+ v250->echo = TRUE;
+ v250->quiet = FALSE;
+ v250->is_v1 = TRUE;
+ v250->res_format = 0;
+ v250->c109 = 1;
+ v250->c108 = 0;
+
+ return v250;
+}
+
+GAtServer *g_at_server_new(GIOChannel *io, const char *modem_path)
+{
+ GAtServer *server;
+
+ if (!io || !modem_path)
+ return NULL;
+
+ server = g_try_new0(GAtServer, 1);
+ if (!server)
+ return NULL;
+
+ server->ref_count = 1;
+ server->v250 = v250_settings_create();
+ server->server_io = io;
+ server->modem_path = g_strdup(modem_path);
+ server->user_disconnect = NULL;
+ server->user_disconnect_data = NULL;
+ server->debugf = NULL;
+ server->debug_data = NULL;
+ server->buf = ring_buffer_new(4096);
+
+ if (!server->v250)
+ goto error;
+
+ if (!server->buf)
+ goto error;
+
+ if (!g_at_util_set_io(server->server_io))
+ goto error;
+
+ server->server_watch = g_io_add_watch_full(io,
+ G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ received_data, server, NULL);
+
+ return server;
+
+error:
+ if (server->buf)
+ ring_buffer_free(server->buf);
+
+ if (server->modem_path)
+ g_free(server->modem_path);
+
+ if (server->v250)
+ g_free(server->v250);
+
+ if (server)
+ g_free(server);
+
+ return NULL;
+}
+
+GAtServer *g_at_server_ref(GAtServer *server)
+{
+ if (server == NULL)
+ return NULL;
+
+ g_atomic_int_inc(&server->ref_count);
+
+ return server;
+}
+
+void g_at_server_unref(GAtServer *server)
+{
+ gboolean is_zero;
+
+ if (server == NULL)
+ return;
+
+ is_zero = g_atomic_int_dec_and_test(&server->ref_count);
+
+ if (is_zero == FALSE)
+ return;
+
+ g_at_server_shutdown(server);
+}
+
+gboolean g_at_server_shutdown(GAtServer *server)
+{
+ if (!server)
+ return FALSE;
+
+ if (server->modem_path)
+ g_free(server->modem_path);
+
+ if (server->v250)
+ g_free(server->v250);
+
+ ring_buffer_free(server->buf);
+ server->buf = NULL;
+
+ if (server->server_watch) {
+ g_source_remove(server->server_watch);
+ server->server_watch = 0;
+ }
+
+ if (server->server_io) {
+ g_io_channel_shutdown(server->server_io, FALSE, NULL);
+ g_io_channel_unref(server->server_io);
+ server->server_io = NULL;
+ }
+
+ if (server->user_disconnect)
+ server->user_disconnect(server->user_disconnect_data);
+
+ g_free(server);
+ server = NULL;
+
+ return TRUE;
+}
+
+gboolean g_at_server_set_disconnect_function(GAtServer *server,
+ GAtDisconnectFunc disconnect,
+ gpointer user)
+{
+ if (server == NULL)
+ return FALSE;
+
+ server->user_disconnect = disconnect;
+ server->user_disconnect_data = user;
+
+ return TRUE;
+}
+
+gboolean g_at_server_set_debug(GAtServer *server, GAtDebugFunc func,
+ gpointer user)
+{
+ if (server == NULL)
+ return FALSE;
+
+ server->debugf = func;
+ server->debug_data = user;
+
+ return TRUE;
+}
diff --git a/gatchat/gatserver.h b/gatchat/gatserver.h
new file mode 100644
index 0000000..39916ec
--- /dev/null
+++ b/gatchat/gatserver.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * AT Server library with GLib integration
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GATSERVER_H
+#define __GATSERVER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gatutil.h"
+
+struct _GAtServer;
+
+typedef struct _GAtServer GAtServer;
+
+/* V.250 Table 1/V.250 Result codes */
+enum _GAtServerResultCodes {
+ G_AT_SERVER_RESULT_OK = 0,
+ G_AT_SERVER_RESULT_CONNECT,
+ G_AT_SERVER_RESULT_RING,
+ G_AT_SERVER_RESULT_NO_CARRIER,
+ G_AT_SERVER_RESULT_ERROR,
+ G_AT_SERVER_RESULT_NO_DIALTONE,
+ G_AT_SERVER_RESULT_BUSY,
+ G_AT_SERVER_RESULT_NO_ANSWER,
+ G_AT_SERVER_RESULT_CONNECT_EXT,
+};
+
+GAtServer *g_at_server_new(GIOChannel *io, const char *modem_path);
+
+GAtServer *g_at_server_ref(GAtServer *server);
+void g_at_server_unref(GAtServer *server);
+gboolean g_at_server_shutdown(GAtServer *server);
+
+gboolean g_at_server_set_disconnect_function(GAtServer *server,
+ GAtDisconnectFunc disconnect,
+ gpointer user_data);
+gboolean g_at_server_set_debug(GAtServer *server,
+ GAtDebugFunc func,
+ gpointer user);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GATSERVER_H */
--
1.6.3.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/4] Add AT command parsing support and interface
2010-01-11 10:53 ` [PATCH 2/4] Add GAtServer basic parsing support Zhenhua Zhang
@ 2010-01-11 10:53 ` Zhenhua Zhang
2010-01-11 10:53 ` [PATCH 4/4] Add test-server test application for GAtServer Zhenhua Zhang
2010-01-14 17:24 ` [PATCH 2/4] Add GAtServer basic parsing support Denis Kenzior
1 sibling, 1 reply; 10+ messages in thread
From: Zhenhua Zhang @ 2010-01-11 10:53 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 8676 bytes --]
Add parsing support for server supported AT commands. Also add
APIs to add/remove notification functions.
---
gatchat/gatserver.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++-
gatchat/gatserver.h | 23 +++++
2 files changed, 247 insertions(+), 1 deletions(-)
diff --git a/gatchat/gatserver.c b/gatchat/gatserver.c
index e861e25..602e509 100644
--- a/gatchat/gatserver.c
+++ b/gatchat/gatserver.c
@@ -67,12 +67,24 @@ struct v250_settings {
unsigned int c108; /* set by &D<val> */
};
+/* AT command that server supported */
+struct at_command {
+ int id;
+ char *prefix;
+ gboolean expect_pdu;
+ GAtServerNotifyFunc notify;
+ gpointer user_data;
+ GDestroyNotify destroy_notify;
+};
+
struct _GAtServer {
gint ref_count; /* Ref count */
struct v250_settings *v250; /* V.250 command setting */
GIOChannel *server_io; /* Server IO */
int server_watch; /* Watch for server IO */
char *modem_path; /* Emulated modem path */
+ GHashTable *command_list; /* Server supported commands */
+ gint next_command_id; /* Id for next command */
GAtDisconnectFunc user_disconnect; /* User disconnect func */
gpointer user_disconnect_data; /* User disconnect data */
GAtDebugFunc debugf; /* Debugging output function */
@@ -128,6 +140,112 @@ static gsize skip_space(const char *buf, gsize pos)
return i;
}
+static inline gboolean is_at_command_prefix(const char c)
+{
+ if (c == '&')
+ return FALSE;
+
+ return g_ascii_ispunct(c);
+}
+
+static gchar *get_at_command_prefix(gchar *command, GAtServerRequestType *type)
+{
+ char c = g_ascii_toupper(*command);
+ gchar *prefix;
+ gchar *equal;
+ gchar *question;
+
+ /* Try to match command in ATA, ATD or ATH */
+ if (c == 'A' || c == 'D' || c == 'H') {
+ *type = G_AT_SERVER_REQUEST_TYPE_ACTION;
+
+ prefix = g_strdup(command);
+ } else if (is_at_command_prefix(c)) {
+ command++;
+
+ equal = strchr(command, '=');
+ question = strchr(command, '?');
+
+ /* Try to match AT+XXX=?, AT+XXX=, AT+XXX? or AT+XXX */
+ if (equal) {
+ if (question)
+ *type = G_AT_SERVER_REQUEST_TYPE_SUPPORT;
+ else
+ *type = G_AT_SERVER_REQUEST_TYPE_SET;
+
+ /* It shouldn't happen but we still check it */
+ if (question != equal + 1)
+ return G_AT_SERVER_REQUEST_TYPE_NONE;
+
+ prefix = g_strndup(command, equal - command);
+ } else if (question) {
+ *type = G_AT_SERVER_REQUEST_TYPE_QUERY;
+
+ prefix = g_strndup(command, question - command);
+ } else {
+ *type = G_AT_SERVER_REQUEST_TYPE_ACTION;
+
+ prefix = g_strdup(command);
+ }
+ }
+
+ return prefix;
+}
+
+static int parse_at_command(GAtServer *server, char *buf)
+{
+ int res = G_AT_SERVER_RESULT_ERROR;
+ GAtServerRequestType type = G_AT_SERVER_REQUEST_TYPE_NONE;
+ gchar t = server->v250->s3;
+ gsize i = 0;
+ gchar *command = NULL;
+ gchar *prefix = NULL;
+ struct at_command *node;
+
+ while (buf[i] != t && buf[i] != ';')
+ i++;
+
+ command = g_strndup(buf, i);
+
+ prefix = get_at_command_prefix(command, &type);
+
+ if (G_AT_SERVER_REQUEST_TYPE_NONE == type)
+ goto out;
+
+ node = g_hash_table_lookup(server->command_list, prefix);
+
+ if (node && node->notify) {
+ if (type == G_AT_SERVER_REQUEST_TYPE_SUPPORT)
+ res = G_AT_SERVER_RESULT_OK;
+ else {
+ GAtResult *result = g_try_new0(GAtResult, 1);
+
+ if (!result)
+ goto out;
+
+ result->lines = g_slist_prepend(NULL, command);
+ result->final_or_pdu = NULL;
+
+ res = node->notify(type, result, node->user_data);
+
+ g_free(result);
+ }
+ }
+
+ /* Compound command */
+ if ((res == G_AT_SERVER_RESULT_OK) && (buf[i] == ';'))
+ res = at_server_parse(server, buf + i);
+
+out:
+ if (prefix)
+ g_free(prefix);
+
+ if (command)
+ g_free(command);
+
+ return res;
+}
+
static int parse_v250_settings(GAtServer *server, char *buf)
{
int res = G_AT_SERVER_RESULT_ERROR;
@@ -150,7 +268,9 @@ static int at_server_parse(GAtServer *server, char *buf)
if (c == ';')
c = buf[++i];
- if (g_ascii_isalpha(c) || c == '&')
+ if (is_at_command_prefix(c) || c == 'A' || c == 'D' || c == 'H')
+ res = parse_at_command(server, buf + i);
+ else if (g_ascii_isalpha(c) || c == '&')
res = parse_v250_settings(server, buf + i);
else if (c == v250->s3)
res = G_AT_SERVER_RESULT_OK;
@@ -305,6 +425,8 @@ GAtServer *g_at_server_new(GIOChannel *io, const char *modem_path)
server->v250 = v250_settings_create();
server->server_io = io;
server->modem_path = g_strdup(modem_path);
+ server->command_list = g_hash_table_new(g_str_hash, g_str_equal);
+ server->next_command_id = 1;
server->user_disconnect = NULL;
server->user_disconnect_data = NULL;
server->debugf = NULL;
@@ -331,6 +453,9 @@ error:
if (server->buf)
ring_buffer_free(server->buf);
+ if (server->command_list)
+ g_hash_table_destroy(server->command_list);
+
if (server->modem_path)
g_free(server->modem_path);
@@ -379,6 +504,10 @@ gboolean g_at_server_shutdown(GAtServer *server)
if (server->v250)
g_free(server->v250);
+ g_at_server_remove_all(server);
+
+ g_hash_table_destroy(server->command_list);
+
ring_buffer_free(server->buf);
server->buf = NULL;
@@ -426,3 +555,97 @@ gboolean g_at_server_set_debug(GAtServer *server, GAtDebugFunc func,
return TRUE;
}
+
+guint g_at_server_add_command(GAtServer *server, const char *prefix,
+ gboolean expect_pdu,
+ GAtServerNotifyFunc notify,
+ gpointer user_data,
+ GDestroyNotify destroy_notify)
+{
+ struct at_command *node;
+
+ if (server == NULL || server->command_list == NULL)
+ return 0;
+
+ if (notify == NULL)
+ return 0;
+
+ if (prefix == NULL || strlen(prefix) == 0)
+ return 0;
+
+ node = g_hash_table_lookup(server->command_list, prefix);
+
+ if (node) {
+ g_hash_table_remove(server->command_list, prefix);
+
+ if (node->destroy_notify)
+ node->destroy_notify(node->user_data);
+
+ g_free(node->prefix);
+
+ g_free(node);
+ }
+
+ node = g_try_new0(struct at_command, 1);
+
+ if (!node)
+ return 0;
+
+ node->id = server->next_command_id++;
+ node->prefix = g_strdup(prefix);
+ node->expect_pdu = expect_pdu;
+ node->notify = notify;
+ node->user_data = user_data;
+ node->destroy_notify = destroy_notify;
+
+ g_hash_table_insert(server->command_list, node->prefix, node);
+
+ return node->id;
+}
+
+static gboolean at_server_remove_command(gpointer key, gpointer value,
+ gpointer user)
+{
+ struct at_command *node = value;
+
+ if (node->destroy_notify)
+ node->destroy_notify(node->user_data);
+
+ g_free(node->prefix);
+
+ g_free(node);
+
+ return TRUE;
+}
+
+gboolean g_at_server_remove_command(GAtServer *server, char *prefix)
+{
+ struct at_command *node;
+ gpointer key = prefix;
+
+ if (!server || !server->command_list)
+ return FALSE;
+
+ node = g_hash_table_lookup(server->command_list, key);
+
+ if (!node)
+ return FALSE;
+
+ g_hash_table_remove(server->command_list, key);
+
+ at_server_remove_command(prefix, node, node);
+
+ return TRUE;
+}
+
+gboolean g_at_server_remove_all(GAtServer *server)
+{
+ if (!server || !server->command_list)
+ return FALSE;
+
+ g_hash_table_foreach_remove(server->command_list,
+ at_server_remove_command, server);
+
+ return TRUE;
+}
+
diff --git a/gatchat/gatserver.h b/gatchat/gatserver.h
index 39916ec..7b68d8a 100644
--- a/gatchat/gatserver.h
+++ b/gatchat/gatserver.h
@@ -45,6 +45,21 @@ enum _GAtServerResultCodes {
G_AT_SERVER_RESULT_CONNECT_EXT,
};
+enum _GAtServerRequestType {
+ G_AT_SERVER_REQUEST_TYPE_NONE = 0,
+ G_AT_SERVER_REQUEST_TYPE_SET,
+ G_AT_SERVER_REQUEST_TYPE_SUPPORT,
+ G_AT_SERVER_REQUEST_TYPE_QUERY,
+ G_AT_SERVER_REQUEST_TYPE_ACTION,
+};
+
+typedef enum _GAtServerRequestType GAtServerRequestType;
+
+typedef int (*GAtServerNotifyFunc)(GAtServerRequestType type,
+ GAtResult *result,
+ gpointer user_data);
+
+
GAtServer *g_at_server_new(GIOChannel *io, const char *modem_path);
GAtServer *g_at_server_ref(GAtServer *server);
@@ -58,6 +73,14 @@ gboolean g_at_server_set_debug(GAtServer *server,
GAtDebugFunc func,
gpointer user);
+guint g_at_server_add_command(GAtServer *server, const char *prefix,
+ gboolean expect_pdu,
+ GAtServerNotifyFunc notify,
+ gpointer user_data,
+ GDestroyNotify destroy);
+gboolean g_at_server_remove_command(GAtServer *server, char *prefix);
+gboolean g_at_server_remove_all(GAtServer *server);
+
#ifdef __cplusplus
}
#endif
--
1.6.3.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/4] Add test-server test application for GAtServer
2010-01-11 10:53 ` [PATCH 3/4] Add AT command parsing support and interface Zhenhua Zhang
@ 2010-01-11 10:53 ` Zhenhua Zhang
0 siblings, 0 replies; 10+ messages in thread
From: Zhenhua Zhang @ 2010-01-11 10:53 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 9794 bytes --]
Add test-server application to showcase how to use GAtServer. It
supports TTY, tcp, unix socket to talk with client application.
---
Makefile.am | 6 +-
gatchat/test-server.c | 402 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 407 insertions(+), 1 deletions(-)
create mode 100644 gatchat/test-server.c
diff --git a/Makefile.am b/Makefile.am
index 50dabca..8ab62ca 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -299,12 +299,16 @@ unit_test_idmap_SOURCES = unit/test-idmap.c src/idmap.c
unit_test_idmap_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_idmap_OBJECTS)
-noinst_PROGRAMS += gatchat/gsmdial
+noinst_PROGRAMS += gatchat/gsmdial gatchat/test-server
gatchat_gsmdial_SOURCES = gatchat/gsmdial.c $(gatchat_sources)
gatchat_gsmdial_LDADD = @GLIB_LIBS@
+gatchat_test_server_SOURCES = gatchat/test-server.c $(gatchat_sources)
+
+gatchat_test_server_LDADD = @GLIB_LIBS@ -lutil
+
DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles
diff --git a/gatchat/test-server.c b/gatchat/test-server.c
new file mode 100644
index 0000000..68ddfc4
--- /dev/null
+++ b/gatchat/test-server.c
@@ -0,0 +1,402 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+
+#include <glib.h>
+#include <pty.h>
+
+#include "gatserver.h"
+#include "ringbuffer.h"
+
+#define DEFAULT_TCP_PORT 12346
+#define DEFAULT_SOCK_PATH "./server_sock"
+
+struct sock_server{
+ int server_sock;
+ const char *modem_path;
+};
+
+static GMainLoop *mainloop;
+static GAtServer *server;
+unsigned int server_watch;
+
+static gboolean server_cleanup()
+{
+ if (server_watch)
+ g_source_remove(server_watch);
+
+ g_at_server_unref(server);
+ server = NULL;
+
+ unlink(DEFAULT_SOCK_PATH);
+
+ g_main_loop_quit(mainloop);
+
+ return FALSE;
+}
+
+static void server_debug(const char *str, void *data)
+{
+ g_print("%s: %s\n", (char *) data, str);
+}
+
+static void add_handler(GAtServer *server)
+{
+ g_at_server_set_debug(server, server_debug, "Server");
+}
+
+static void server_destroy(gpointer user)
+{
+ struct sock_server *data = user;
+
+ if (data)
+ g_free(data);
+}
+
+static GAtServer *create_tty(const char *modem_path)
+{
+ int master, slave;
+ char pty_name[256];
+ GIOChannel *io;
+
+ if (!modem_path)
+ return NULL;
+
+ if (openpty(&master, &slave, pty_name, NULL, NULL) < 0)
+ return NULL;
+
+ io = g_io_channel_unix_new(master);
+
+ g_print("new tty is created@%s\n", pty_name);
+
+ server = g_at_server_new(io, modem_path);
+
+ if (!server) {
+ g_io_channel_shutdown(io, FALSE, NULL);
+ g_io_channel_unref(io);
+
+ return NULL;
+ }
+
+ add_handler(server);
+
+ return server;
+}
+
+static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
+ gpointer user)
+{
+ struct sockaddr saddr;
+ unsigned int len = sizeof(saddr);
+ int fd;
+ GIOChannel *client_io = NULL;
+ struct sock_server *data = user;
+
+ if (cond != G_IO_IN)
+ goto error;
+
+ fd = accept(data->server_sock, &saddr, &len);
+ if (fd == -1)
+ goto error;
+
+ client_io = g_io_channel_unix_new(fd);
+
+ server = g_at_server_new(client_io, data->modem_path);
+
+ if (!server) {
+ g_io_channel_shutdown(client_io, FALSE, NULL);
+ g_io_channel_unref(client_io);
+
+ goto error;
+ }
+
+ add_handler(server);
+
+ return TRUE;
+
+error:
+ if (data)
+ g_free(data);
+
+ return FALSE;
+}
+
+static struct sock_server *socket_common(int sk, struct sockaddr *addr,
+ const char *modem_path)
+{
+ struct sock_server *sock;
+
+ if (bind(sk, addr, sizeof(struct sockaddr)) < 0) {
+ g_print("Can't bind socket: %s (%d)", strerror(errno), errno);
+
+ close(sk);
+
+ return NULL;
+ }
+
+ if (listen(sk, 1) < 0) {
+ g_print("Can't listen on socket: %s (%d)",
+ strerror(errno), errno);
+
+ close(sk);
+
+ return NULL;
+ }
+
+ sock = g_try_new0(struct sock_server, 1);
+ if (!sock)
+ return FALSE;
+
+ sock->server_sock = sk;
+ sock->modem_path = g_strdup(modem_path);
+
+ return sock;
+}
+
+static gboolean create_tcp(const char *modem_path, int port)
+{
+ struct sockaddr_in addr;
+ int sk;
+ struct sock_server *server;
+ GIOChannel *server_io;
+
+ if (!modem_path)
+ return FALSE;
+
+ sk = socket(PF_INET, SOCK_STREAM, 0);
+ if (sk < 0) {
+ g_print("Can't create tcp/ip socket: %s (%d)",
+ strerror(errno), errno);
+ return FALSE;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = htons(port);
+
+ server = socket_common(sk, (struct sockaddr *) &addr, modem_path);
+ if (!server)
+ return FALSE;
+
+ g_print("new tcp is created at tcp port %d\n", port);
+
+ server_io = g_io_channel_unix_new(sk);
+
+ g_io_channel_set_close_on_unref(server_io, TRUE);
+
+ server_watch = g_io_add_watch_full(server_io,
+ G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ on_socket_connected, server, server_destroy);
+
+ g_io_channel_unref(server_io);
+
+ return TRUE;
+}
+
+static gboolean create_unix(const char *modem_path, const char *sock_path)
+{
+ struct sockaddr_un addr;
+ int sk;
+ struct sock_server *server;
+ GIOChannel *server_io;
+
+ if (!modem_path)
+ return FALSE;
+
+ sk = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sk < 0) {
+ g_print("Can't create unix socket: %s (%d)",
+ strerror(errno), errno);
+
+ return FALSE;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);
+
+ /* Unlink any existing socket for this session */
+ unlink(addr.sun_path);
+
+ server = socket_common(sk, (struct sockaddr *) &addr, modem_path);
+ if (!server)
+ return FALSE;
+
+ g_print("new unix socket is created at %s\n", sock_path);
+
+ server_io = g_io_channel_unix_new(sk);
+
+ g_io_channel_set_close_on_unref(server_io, TRUE);
+
+ server_watch = g_io_add_watch_full(server_io,
+ G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ on_socket_connected, server, server_destroy);
+
+ g_io_channel_unref(server_io);
+
+ return TRUE;
+}
+
+static void test_server(int type)
+{
+ switch (type) {
+ case 0:
+ server = create_tty("/phonesim1");
+
+ add_handler(server);
+ break;
+ case 1:
+ if (!create_tcp("/phonesim1", DEFAULT_TCP_PORT))
+ exit(-1);
+ break;
+ case 2:
+ if (!create_unix("/phonesim1", DEFAULT_SOCK_PATH))
+ exit(-1);
+ break;
+ }
+}
+
+static gboolean signal_cb(GIOChannel *channel, GIOCondition cond, gpointer data)
+{
+ int signal_fd = GPOINTER_TO_INT(data);
+ struct signalfd_siginfo si;
+ ssize_t res;
+
+ if (cond & (G_IO_NVAL | G_IO_ERR))
+ return FALSE;
+
+ res = read(signal_fd, &si, sizeof(si));
+ if (res != sizeof(si))
+ return FALSE;
+
+ switch (si.ssi_signo) {
+ case SIGINT:
+ server_cleanup();
+ break;
+ case SIGTERM:
+ server_cleanup();
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+static int create_signal_io()
+{
+ sigset_t mask;
+ GIOChannel *signal_io;
+ int signal_fd, signal_source;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGTERM);
+ sigaddset(&mask, SIGINT);
+
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+ g_error("Can't set signal mask");
+ return 1;
+ }
+
+ signal_fd = signalfd(-1, &mask, 0);
+ if (signal_fd < 0) {
+ g_error("Can't create signal filedescriptor");
+ return 1;
+ }
+
+ signal_io = g_io_channel_unix_new(signal_fd);
+
+ g_io_channel_set_close_on_unref(signal_io, TRUE);
+
+ signal_source = g_io_add_watch(signal_io,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ signal_cb, GINT_TO_POINTER(signal_fd));
+
+ g_io_channel_unref(signal_io);
+
+ return signal_source;
+}
+
+static void usage(void)
+{
+ g_print("test-server - AT Server testing\n"
+ "Usage:\n");
+ g_print("\ttest-server [-t type]\n");
+ g_print("Types:\n"
+ "\t0: Pseudo TTY port (default)\n"
+ "\t1: TCP sock at port 12346)\n"
+ "\t2: Unix sock@./server_sock\n");
+}
+
+int main(int argc, char **argv)
+{
+ int opt, signal_source;
+ int type = 0;
+
+ while ((opt = getopt(argc, argv, "ht:")) != EOF) {
+ switch (opt) {
+ case 't':
+ type = atoi(optarg);
+ break;
+ case 'h':
+ usage();
+ exit(1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ test_server(type);
+
+ signal_source = create_signal_io();
+
+ mainloop = g_main_loop_new(NULL, FALSE);
+
+ g_main_loop_run(mainloop);
+
+ g_main_loop_unref(mainloop);
+
+ g_source_remove(signal_source);
+
+ return 0;
+}
--
1.6.3.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer
2010-01-11 10:53 [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Zhenhua Zhang
2010-01-11 10:53 ` [PATCH 2/4] Add GAtServer basic parsing support Zhenhua Zhang
@ 2010-01-14 15:49 ` Denis Kenzior
2010-01-15 1:24 ` Zhang, Zhenhua
1 sibling, 1 reply; 10+ messages in thread
From: Denis Kenzior @ 2010-01-14 15:49 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2427 bytes --]
Hi Zhenhua,
> +gboolean g_at_util_set_io(GIOChannel *io)
Rename this g_at_util_setup_io
> +{
> + GIOFlags io_flags;
> +
> + if (g_io_channel_set_encoding(io, NULL, NULL) !=
> + G_IO_STATUS_NORMAL)
> + return FALSE;
> +
> + io_flags = g_io_channel_get_flags(io);
> +
> + io_flags |= G_IO_FLAG_NONBLOCK;
> + io_flags |= G_IO_FLAG_IS_READABLE;
> + io_flags |= G_IO_FLAG_IS_WRITEABLE;
According to GLib docs the READABLE and WRITEABLE flags are not settable.
Don't see the point in setting them anyway, please get rid of this.
> +
> + if (g_io_channel_set_flags(io, io_flags, NULL) !=
> + G_IO_STATUS_NORMAL)
> + return FALSE;
> +
> + g_io_channel_set_close_on_unref(io, TRUE);
> +
> + return TRUE;
> +}
> +
> diff --git a/gatchat/gatutil.h b/gatchat/gatutil.h
> new file mode 100644
> index 0000000..63bbfff
> --- /dev/null
> +++ b/gatchat/gatutil.h
> @@ -0,0 +1,46 @@
> +/*
> + *
> + * AT chat library with GLib integration
> + *
> + * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
> USA + *
> + */
> +
> +#ifndef __GATUTIL_H
> +#define __GATUTIL_H
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include "gatresult.h"
Get rid of this include
> +
> +typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
> + gpointer user_data);
> +typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);
The GAtNotify and GAtResultFunc should stay in gatchat.h
> +typedef void (*GAtDisconnectFunc)(gpointer user_data);
> +typedef void (*GAtDebugFunc)(const char *str, gpointer user_data);
These don't belong here, create a new file called gat.h and put them there.
Regards,
-Denis
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/4] Add GAtServer basic parsing support
2010-01-11 10:53 ` [PATCH 2/4] Add GAtServer basic parsing support Zhenhua Zhang
2010-01-11 10:53 ` [PATCH 3/4] Add AT command parsing support and interface Zhenhua Zhang
@ 2010-01-14 17:24 ` Denis Kenzior
2010-01-14 21:53 ` Marcel Holtmann
1 sibling, 1 reply; 10+ messages in thread
From: Denis Kenzior @ 2010-01-14 17:24 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 6692 bytes --]
Hi Zhenhua,
> +
> +#include <glib.h>
> +
> +#include "ringbuffer.h"
> +#include "gatresult.h"
Is this include really necessary?
> +#include "gatserver.h"
> +
> +#define DBG(fmt, arg...) g_print("%s:%s() " fmt, __FILE__, __FUNCTION__ ,
> ## arg) +
Move this to gat.h
> +struct _GAtServer {
> + gint ref_count; /* Ref count */
> + struct v250_settings *v250; /* V.250 command setting */
This one doesn't need to be a pointer.
> + GIOChannel *server_io; /* Server IO */
> + int server_watch; /* Watch for server IO */
> + char *modem_path; /* Emulated modem path */
Get rid of this, there's no purpose for it.
> +static int at_server_parse(GAtServer *server, char *buf)
> +{
> + int res = G_AT_SERVER_RESULT_ERROR;
> + struct v250_settings *v250 = server->v250;
> + gsize i = 0;
> + char c;
> +
> + /* skip space after "AT" or previous command */
> + i = skip_space(buf, i);
> +
> + c = buf[i];
> + /* skip semicolon */
> + if (c == ';')
> + c = buf[++i];
> +
> + if (g_ascii_isalpha(c) || c == '&')
> + res = parse_v250_settings(server, buf + i);
This part makes no sense
> + else if (c == v250->s3)
> + res = G_AT_SERVER_RESULT_OK;
> +
> + return res;
> +}
> +
> +static void parse_buffer(GAtServer *server, unsigned int len)
> +{
> + int res = G_AT_SERVER_RESULT_ERROR;
> + gsize i = 0;
> + char *buf = NULL;
> +
> + g_at_server_ref(server);
Lets get rid of this part for now. It was a necessary evil inside GAtChat
since the client can close the channel in the command result callback. I
don't think this is relevant for GAtServer. If it ever becomes relevant we
can add this back in.
> +
> + buf = g_try_new0(char, len+1);
You're leaking the buf memory in this function.
> +
> + if (!buf)
> + goto out;
> +
> + if (-1 == ring_buffer_read(server->buf, buf, len))
> + goto out;
> +
> + buf[len] = '\0';
> +
> + DBG("received %s\n", buf);
> +
> + /* skip header space */
> + buf += skip_space(buf, i);
> +
> + /* Make sure the command line prefix is "AT" or "at" */
> + if (g_str_has_prefix(buf, "AT") ||
> + g_str_has_prefix(buf, "at"))
> + res = at_server_parse(server, (char *) buf + 2);
> +
> + g_at_server_send_result_code(server, res);
> +
> +out:
> + /* We're overflowing the buffer, shutdown the socket */
> + if (server->buf && ring_buffer_avail(server->buf) == 0)
> + g_at_server_shutdown(server);
> +
> + g_at_server_unref(server);
Same here, see above.
> +}
> +
> +static gboolean received_data(GIOChannel *chan, GIOCondition cond,
> + gpointer data)
> +{
> + GAtServer *server = data;
> + struct v250_settings *v250 = server->v250;
> + GIOError err;
> + gsize rbytes;
> + gsize total_read = 0;
> + unsigned char *total_buf = ring_buffer_write_ptr(server->buf);
You're totally abusing the ring buffer concept here, the fact that this works
is pure luck.
> + static gsize total_len;
> +
> + if (cond & G_IO_NVAL)
> + return FALSE;
> +
> + if (cond & (G_IO_HUP | G_IO_ERR)) {
> + g_at_server_shutdown(server);
> +
> + return FALSE;
> + }
> +
> + /* Regardless of condition, try to read all the data available */
> + do {
> + unsigned char *buf;
> + gsize toread;
> +
> + rbytes = 0;
> +
> + toread = ring_buffer_avail_no_wrap(server->buf);
> +
> + if (toread == 0)
> + break;
> +
> + buf = ring_buffer_write_ptr(server->buf);
> +
> + err = g_io_channel_read(chan, (char *) buf, toread, &rbytes);
> +
> + total_read += rbytes;
> +
> + if (rbytes > 0)
> + ring_buffer_write_advance(server->buf, rbytes);
> +
> + } while (err == G_IO_ERROR_NONE && rbytes > 0);
> +
> + g_at_util_debug_chat(server->debugf, TRUE, (char *) total_buf,
> + total_read, server->debug_data);
> +
> + if (total_read == 0) {
> + g_at_server_shutdown(server);
You should be checking rbytes == 0 && err != EAGAIN here. Your check below is
also redundant.
> +
> + return FALSE;
> + }
> +
> + total_len += total_read;
> +
> + /* Add '\0' to perform strchr */
> + total_buf[total_read] = '\0';
> +
> + /* Parse buffer until we meet the terminator so that
> + * all preceding characters will be processed
> + */
> + if (strchr((char *) total_buf, v250->s3)) {
> + parse_buffer(server, total_len);
> +
> + total_len = 0;
> + }
Should this be inside a while loop? Several commands can come in at once.
> +
> + if (err != G_IO_ERROR_NONE && err != G_IO_ERROR_AGAIN)
> + return FALSE;
> +
> + return TRUE;
> +}
> +
> +GAtServer *g_at_server_new(GIOChannel *io, const char *modem_path)
Get rid of modem_path
> +{
> + GAtServer *server;
> +
> + if (!io || !modem_path)
> + return NULL;
> +
> + server = g_try_new0(GAtServer, 1);
> + if (!server)
> + return NULL;
> +
> + server->ref_count = 1;
> + server->v250 = v250_settings_create();
> + server->server_io = io;
> + server->modem_path = g_strdup(modem_path);
And here
> + server->user_disconnect = NULL;
> + server->user_disconnect_data = NULL;
> + server->debugf = NULL;
> + server->debug_data = NULL;
> + server->buf = ring_buffer_new(4096);
> +
> + if (!server->v250)
> + goto error;
> +
> + if (!server->buf)
> + goto error;
> +
> + if (!g_at_util_set_io(server->server_io))
> + goto error;
> +
> + server->server_watch = g_io_add_watch_full(io,
> + G_PRIORITY_DEFAULT,
> + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
> + received_data, server, NULL);
> +
> + return server;
> +
> +error:
> + if (server->buf)
> + ring_buffer_free(server->buf);
> +
> + if (server->modem_path)
> + g_free(server->modem_path);
And here
> +
> + if (server->v250)
> + g_free(server->v250);
> +
> + if (server)
> + g_free(server);
> +
> + return NULL;
> +}
> +
> +gboolean g_at_server_shutdown(GAtServer *server)
> +{
> + if (!server)
> + return FALSE;
> +
> + if (server->modem_path)
> + g_free(server->modem_path);
> +
> + if (server->v250)
> + g_free(server->v250);
> +
> + ring_buffer_free(server->buf);
> + server->buf = NULL;
> +
> + if (server->server_watch) {
> + g_source_remove(server->server_watch);
> + server->server_watch = 0;
> + }
> +
> + if (server->server_io) {
> + g_io_channel_shutdown(server->server_io, FALSE, NULL);
> + g_io_channel_unref(server->server_io);
> + server->server_io = NULL;
> + }
> +
> + if (server->user_disconnect)
> + server->user_disconnect(server->user_disconnect_data);
We should not trigger a user_disconnect if we're shutting down normally. The
purpose is to detect when the remote side has disconnected the connection.
Regards,
-Denis
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/4] Add GAtServer basic parsing support
2010-01-14 21:53 ` Marcel Holtmann
@ 2010-01-14 20:57 ` Denis Kenzior
0 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2010-01-14 20:57 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 363 bytes --]
Hi Marcel,
> Hi Denis,
>
> > > +#include "gatserver.h"
> > > +
> > > +#define DBG(fmt, arg...) g_print("%s:%s() " fmt, __FILE__,
> > > __FUNCTION__ , ## arg) +
> >
> > Move this to gat.h
>
> can we actually not be using DBG inside gatchat. Why is that suddenly
> needed?
Actually good point. I agree this should be removed.
Regards,
-Denis
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/4] Add GAtServer basic parsing support
2010-01-14 17:24 ` [PATCH 2/4] Add GAtServer basic parsing support Denis Kenzior
@ 2010-01-14 21:53 ` Marcel Holtmann
2010-01-14 20:57 ` Denis Kenzior
0 siblings, 1 reply; 10+ messages in thread
From: Marcel Holtmann @ 2010-01-14 21:53 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 278 bytes --]
Hi Denis,
> > +#include "gatserver.h"
> > +
> > +#define DBG(fmt, arg...) g_print("%s:%s() " fmt, __FILE__, __FUNCTION__ ,
> > ## arg) +
>
> Move this to gat.h
can we actually not be using DBG inside gatchat. Why is that suddenly
needed?
Regards
Marcel
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer
2010-01-14 15:49 ` [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Denis Kenzior
@ 2010-01-15 1:24 ` Zhang, Zhenhua
2010-01-20 20:23 ` Denis Kenzior
0 siblings, 1 reply; 10+ messages in thread
From: Zhang, Zhenhua @ 2010-01-15 1:24 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 465 bytes --]
Hi Denis,
Denis Kenzior wrote:
> Hi Zhenhua,
>
>> +gboolean g_at_util_set_io(GIOChannel *io)
>
> Rename this g_at_util_setup_io
>
>> +typedef void (*GAtDisconnectFunc)(gpointer user_data); typedef void
>> +(*GAtDebugFunc)(const char *str, gpointer user_data);
>
> These don't belong here, create a new file called gat.h and put them
> there.
>
> Regards,
> -Denis
Thanks for your comments. Updated patch is attached.
Regards,
Zhenhua
[-- Attachment #2: 0001-Add-gatutil.c-to-share-common-APIs-with-GAtServer.patch --]
[-- Type: application/octet-stream, Size: 11673 bytes --]
From 05f4611e5a3f0353fc79a341ef4be07e515a48eb Mon Sep 17 00:00:00 2001
From: Zhenhua Zhang <zhenhua.zhang@intel.com>
Date: Fri, 15 Jan 2010 09:15:38 +0800
Subject: [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer
Add gatutil.c/h gat.h and move shared typedef and APIs into it.
So that they can be shared by GAtServer and GAtChat.
---
Makefile.am | 4 +-
gatchat/gat.h | 36 +++++++++++++++
gatchat/gatchat.c | 98 +++-------------------------------------
gatchat/gatchat.h | 3 +-
gatchat/gatutil.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++
gatchat/gatutil.h | 40 ++++++++++++++++
6 files changed, 215 insertions(+), 95 deletions(-)
create mode 100644 gatchat/gat.h
create mode 100644 gatchat/gatutil.c
create mode 100644 gatchat/gatutil.h
diff --git a/Makefile.am b/Makefile.am
index 276b478..b6776bd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,7 +51,9 @@ gatchat_sources = gatchat/gatchat.h gatchat/gatchat.c \
gatchat/ringbuffer.h gatchat/ringbuffer.c \
gatchat/gatmux.h gatchat/gatmux.c \
gatchat/gsm0710.h gatchat/gsm0710.c \
- gatchat/gattty.h gatchat/gattty.c
+ gatchat/gattty.h gatchat/gattty.c \
+ gatchat/gatutil.h gatchat/gatutil.c \
+ gatchat/gat.h
udev_files = plugins/ofono.rules
diff --git a/gatchat/gat.h b/gatchat/gat.h
new file mode 100644
index 0000000..6696e7d
--- /dev/null
+++ b/gatchat/gat.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GAT_H
+#define __GAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*GAtDisconnectFunc)(gpointer user_data);
+typedef void (*GAtDebugFunc)(const char *str, gpointer user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GAT_H */
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c
index 8af927e..b5627b3 100644
--- a/gatchat/gatchat.c
+++ b/gatchat/gatchat.c
@@ -40,7 +40,6 @@
static const char *none_prefix[] = { NULL };
static void g_at_chat_wakeup_writer(GAtChat *chat);
-static void debug_chat(GAtChat *chat, gboolean in, const char *str, gsize len);
struct at_command {
char *cmd;
@@ -686,81 +685,6 @@ static void new_bytes(GAtChat *p)
g_at_chat_unref(p);
}
-static void debug_chat(GAtChat *chat, gboolean in, const char *str, gsize len)
-{
- char type = in ? '<' : '>';
- gsize escaped = 2; /* Enough for '<', ' ' */
- char *escaped_str;
- const char *esc = "<ESC>";
- gsize esc_size = strlen(esc);
- const char *ctrlz = "<CtrlZ>";
- gsize ctrlz_size = strlen(ctrlz);
- gsize i;
-
- if (!chat->debugf || !len)
- return;
-
- for (i = 0; i < len; i++) {
- char c = str[i];
-
- if (isprint(c))
- escaped += 1;
- else if (c == '\r' || c == '\t' || c == '\n')
- escaped += 2;
- else if (c == 26)
- escaped += ctrlz_size;
- else if (c == 25)
- escaped += esc_size;
- else
- escaped += 4;
- }
-
- escaped_str = g_malloc(escaped + 1);
- escaped_str[0] = type;
- escaped_str[1] = ' ';
- escaped_str[2] = '\0';
- escaped_str[escaped] = '\0';
-
- for (escaped = 2, i = 0; i < len; i++) {
- char c = str[i];
-
- switch (c) {
- case '\r':
- escaped_str[escaped++] = '\\';
- escaped_str[escaped++] = 'r';
- break;
- case '\t':
- escaped_str[escaped++] = '\\';
- escaped_str[escaped++] = 't';
- break;
- case '\n':
- escaped_str[escaped++] = '\\';
- escaped_str[escaped++] = 'n';
- break;
- case 26:
- strncpy(&escaped_str[escaped], ctrlz, ctrlz_size);
- escaped += ctrlz_size;
- break;
- case 25:
- strncpy(&escaped_str[escaped], esc, esc_size);
- escaped += esc_size;
- break;
- default:
- if (isprint(c))
- escaped_str[escaped++] = c;
- else {
- escaped_str[escaped++] = '\\';
- escaped_str[escaped++] = '0' + ((c >> 6) & 07);
- escaped_str[escaped++] = '0' + ((c >> 3) & 07);
- escaped_str[escaped++] = '0' + (c & 07);
- }
- }
- }
-
- chat->debugf(escaped_str, chat->debug_data);
- g_free(escaped_str);
-}
-
static gboolean received_data(GIOChannel *channel, GIOCondition cond,
gpointer data)
{
@@ -786,7 +710,8 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
buf = ring_buffer_write_ptr(chat->buf);
err = g_io_channel_read(channel, (char *) buf, toread, &rbytes);
- debug_chat(chat, TRUE, (char *)buf, rbytes);
+ g_at_util_debug_chat(chat->debugf, TRUE, (char *)buf, rbytes,
+ chat->debug_data);
total_read += rbytes;
@@ -932,8 +857,9 @@ static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
return FALSE;
}
- debug_chat(chat, FALSE, cmd->cmd + chat->cmd_bytes_written,
- bytes_written);
+ g_at_util_debug_chat(chat->debugf, FALSE,
+ cmd->cmd + chat->cmd_bytes_written,
+ bytes_written, chat->debug_data);
chat->cmd_bytes_written += bytes_written;
if (bytes_written < towrite)
@@ -961,7 +887,6 @@ static void g_at_chat_wakeup_writer(GAtChat *chat)
GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax)
{
GAtChat *chat;
- GIOFlags io_flags;
if (!channel)
return NULL;
@@ -992,20 +917,9 @@ GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax)
chat->notify_list = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, (GDestroyNotify)at_notify_destroy);
- if (g_io_channel_set_encoding(channel, NULL, NULL) !=
- G_IO_STATUS_NORMAL)
- goto error;
-
- io_flags = g_io_channel_get_flags(channel);
-
- io_flags |= G_IO_FLAG_NONBLOCK;
-
- if (g_io_channel_set_flags(channel, io_flags, NULL) !=
- G_IO_STATUS_NORMAL)
+ if (!g_at_util_setup_io(channel))
goto error;
- g_io_channel_set_close_on_unref(channel, TRUE);
-
chat->channel = channel;
chat->read_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
diff --git a/gatchat/gatchat.h b/gatchat/gatchat.h
index 999b92d..f76fc42 100644
--- a/gatchat/gatchat.h
+++ b/gatchat/gatchat.h
@@ -28,6 +28,7 @@ extern "C" {
#include "gatresult.h"
#include "gatsyntax.h"
+#include "gatutil.h"
struct _GAtChat;
@@ -36,8 +37,6 @@ typedef struct _GAtChat GAtChat;
typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
gpointer user_data);
typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);
-typedef void (*GAtDisconnectFunc)(gpointer user_data);
-typedef void (*GAtDebugFunc)(const char *str, gpointer user_data);
GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax);
diff --git a/gatchat/gatutil.c b/gatchat/gatutil.c
new file mode 100644
index 0000000..6bc5dcb
--- /dev/null
+++ b/gatchat/gatutil.c
@@ -0,0 +1,129 @@
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+#include <glib.h>
+
+#include "gatutil.h"
+
+void g_at_util_debug_chat(GAtDebugFunc debugf, gboolean in, const char *str,
+ gsize len, gpointer user_data)
+{
+ char type = in ? '<' : '>';
+ gsize escaped = 2; /* Enough for '<', ' ' */
+ char *escaped_str;
+ const char *esc = "<ESC>";
+ gsize esc_size = strlen(esc);
+ const char *ctrlz = "<CtrlZ>";
+ gsize ctrlz_size = strlen(ctrlz);
+ gsize i;
+
+ if (!debugf || !len)
+ return;
+
+ for (i = 0; i < len; i++) {
+ char c = str[i];
+
+ if (isprint(c))
+ escaped += 1;
+ else if (c == '\r' || c == '\t' || c == '\n')
+ escaped += 2;
+ else if (c == 26)
+ escaped += ctrlz_size;
+ else if (c == 25)
+ escaped += esc_size;
+ else
+ escaped += 4;
+ }
+
+ escaped_str = g_malloc(escaped + 1);
+ escaped_str[0] = type;
+ escaped_str[1] = ' ';
+ escaped_str[2] = '\0';
+ escaped_str[escaped] = '\0';
+
+ for (escaped = 2, i = 0; i < len; i++) {
+ char c = str[i];
+
+ switch (c) {
+ case '\r':
+ escaped_str[escaped++] = '\\';
+ escaped_str[escaped++] = 'r';
+ break;
+ case '\t':
+ escaped_str[escaped++] = '\\';
+ escaped_str[escaped++] = 't';
+ break;
+ case '\n':
+ escaped_str[escaped++] = '\\';
+ escaped_str[escaped++] = 'n';
+ break;
+ case 26:
+ strncpy(&escaped_str[escaped], ctrlz, ctrlz_size);
+ escaped += ctrlz_size;
+ break;
+ case 25:
+ strncpy(&escaped_str[escaped], esc, esc_size);
+ escaped += esc_size;
+ break;
+ default:
+ if (isprint(c))
+ escaped_str[escaped++] = c;
+ else {
+ escaped_str[escaped++] = '\\';
+ escaped_str[escaped++] = '0' + ((c >> 6) & 07);
+ escaped_str[escaped++] = '0' + ((c >> 3) & 07);
+ escaped_str[escaped++] = '0' + (c & 07);
+ }
+ }
+ }
+
+ debugf(escaped_str, user_data);
+ g_free(escaped_str);
+}
+
+gboolean g_at_util_setup_io(GIOChannel *io)
+{
+ GIOFlags io_flags;
+
+ if (g_io_channel_set_encoding(io, NULL, NULL) !=
+ G_IO_STATUS_NORMAL)
+ return FALSE;
+
+ io_flags = g_io_channel_get_flags(io);
+
+ io_flags |= G_IO_FLAG_NONBLOCK;
+
+ if (g_io_channel_set_flags(io, io_flags, NULL) !=
+ G_IO_STATUS_NORMAL)
+ return FALSE;
+
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ return TRUE;
+}
+
diff --git a/gatchat/gatutil.h b/gatchat/gatutil.h
new file mode 100644
index 0000000..b17dad4
--- /dev/null
+++ b/gatchat/gatutil.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * AT chat library with GLib integration
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GATUTIL_H
+#define __GATUTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gat.h"
+
+void g_at_util_debug_chat(GAtDebugFunc debugf, gboolean in, const char *str,
+ gsize len, gpointer user_data);
+
+gboolean g_at_util_setup_io(GIOChannel *io);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GATUTIL_H */
--
1.6.3.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer
2010-01-15 1:24 ` Zhang, Zhenhua
@ 2010-01-20 20:23 ` Denis Kenzior
0 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2010-01-20 20:23 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 551 bytes --]
Hi Zhenhua,
> Hi Denis,
>
> Denis Kenzior wrote:
> > Hi Zhenhua,
> >
> >> +gboolean g_at_util_set_io(GIOChannel *io)
> >
> > Rename this g_at_util_setup_io
> >
> >> +typedef void (*GAtDisconnectFunc)(gpointer user_data); typedef void
> >> +(*GAtDebugFunc)(const char *str, gpointer user_data);
> >
> > These don't belong here, create a new file called gat.h and put them
> > there.
> >
> > Regards,
> > -Denis
>
> Thanks for your comments. Updated patch is attached.
>
Patch has been applied. Thanks.
Regards,
-Denis
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2010-01-20 20:23 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-01-11 10:53 [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Zhenhua Zhang
2010-01-11 10:53 ` [PATCH 2/4] Add GAtServer basic parsing support Zhenhua Zhang
2010-01-11 10:53 ` [PATCH 3/4] Add AT command parsing support and interface Zhenhua Zhang
2010-01-11 10:53 ` [PATCH 4/4] Add test-server test application for GAtServer Zhenhua Zhang
2010-01-14 17:24 ` [PATCH 2/4] Add GAtServer basic parsing support Denis Kenzior
2010-01-14 21:53 ` Marcel Holtmann
2010-01-14 20:57 ` Denis Kenzior
2010-01-14 15:49 ` [PATCH 1/4] Add gatutil.c to share common APIs with GAtServer Denis Kenzior
2010-01-15 1:24 ` Zhang, Zhenhua
2010-01-20 20:23 ` Denis Kenzior
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.