* [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 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 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 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 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 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.