mirror of git://git.sysmocom.de/ofono
gatchat: port gatchat to use gatio
This commit is contained in:
parent
43c30e2292
commit
7b8f4f5dc8
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "gatchat.h"
|
#include "gatchat.h"
|
||||||
|
#include "gatio.h"
|
||||||
|
|
||||||
/* #define WRITE_SCHEDULER_DEBUG 1 */
|
/* #define WRITE_SCHEDULER_DEBUG 1 */
|
||||||
|
|
||||||
|
@ -68,18 +69,16 @@ struct _GAtChat {
|
||||||
gint ref_count; /* Ref count */
|
gint ref_count; /* Ref count */
|
||||||
guint next_cmd_id; /* Next command id */
|
guint next_cmd_id; /* Next command id */
|
||||||
guint next_notify_id; /* Next notify id */
|
guint next_notify_id; /* Next notify id */
|
||||||
guint read_watch; /* GSource read id, 0 if none */
|
|
||||||
guint write_watch; /* GSource write id, 0 if none */
|
guint write_watch; /* GSource write id, 0 if none */
|
||||||
gboolean use_write_watch; /* watch usage for non blocking */
|
gboolean use_write_watch; /* watch usage for non blocking */
|
||||||
GIOChannel *channel; /* channel */
|
GIOChannel *channel; /* channel */
|
||||||
|
GAtIO *io; /* AT IO */
|
||||||
GQueue *command_queue; /* Command queue */
|
GQueue *command_queue; /* Command queue */
|
||||||
guint cmd_bytes_written; /* bytes written from cmd */
|
guint cmd_bytes_written; /* bytes written from cmd */
|
||||||
GHashTable *notify_list; /* List of notification reg */
|
GHashTable *notify_list; /* List of notification reg */
|
||||||
GAtDisconnectFunc user_disconnect; /* user disconnect func */
|
GAtDisconnectFunc user_disconnect; /* user disconnect func */
|
||||||
gpointer user_disconnect_data; /* user disconnect data */
|
gpointer user_disconnect_data; /* user disconnect data */
|
||||||
struct ring_buffer *buf; /* Current read buffer */
|
|
||||||
guint read_so_far; /* Number of bytes processed */
|
guint read_so_far; /* Number of bytes processed */
|
||||||
guint max_read_attempts; /* max number of read attempts */
|
|
||||||
GAtDebugFunc debugf; /* debugging output function */
|
GAtDebugFunc debugf; /* debugging output function */
|
||||||
gpointer debug_data; /* Data to pass to debug func */
|
gpointer debug_data; /* Data to pass to debug func */
|
||||||
char *pdu_notify; /* Unsolicited Resp w/ PDU */
|
char *pdu_notify; /* Unsolicited Resp w/ PDU */
|
||||||
|
@ -233,9 +232,6 @@ static void g_at_chat_cleanup(GAtChat *chat)
|
||||||
{
|
{
|
||||||
struct at_command *c;
|
struct at_command *c;
|
||||||
|
|
||||||
ring_buffer_free(chat->buf);
|
|
||||||
chat->buf = NULL;
|
|
||||||
|
|
||||||
/* Cleanup pending commands */
|
/* Cleanup pending commands */
|
||||||
while ((c = g_queue_pop_head(chat->command_queue)))
|
while ((c = g_queue_pop_head(chat->command_queue)))
|
||||||
at_command_destroy(c);
|
at_command_destroy(c);
|
||||||
|
@ -276,6 +272,7 @@ static void g_at_chat_cleanup(GAtChat *chat)
|
||||||
chat->syntax = NULL;
|
chat->syntax = NULL;
|
||||||
|
|
||||||
chat->channel = NULL;
|
chat->channel = NULL;
|
||||||
|
chat->io = NULL;
|
||||||
|
|
||||||
if (chat->terminator_list) {
|
if (chat->terminator_list) {
|
||||||
g_slist_foreach(chat->terminator_list,
|
g_slist_foreach(chat->terminator_list,
|
||||||
|
@ -285,18 +282,16 @@ static void g_at_chat_cleanup(GAtChat *chat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_watcher_destroy_notify(gpointer user_data)
|
static void io_disconnect(gpointer user_data)
|
||||||
{
|
{
|
||||||
GAtChat *chat = user_data;
|
GAtChat *chat = user_data;
|
||||||
|
|
||||||
|
g_at_io_set_read_handler(chat->io, NULL, NULL);
|
||||||
|
g_at_io_unref(chat->io);
|
||||||
g_at_chat_cleanup(chat);
|
g_at_chat_cleanup(chat);
|
||||||
chat->read_watch = 0;
|
|
||||||
|
|
||||||
if (chat->user_disconnect)
|
if (chat->user_disconnect)
|
||||||
chat->user_disconnect(chat->user_disconnect_data);
|
chat->user_disconnect(chat->user_disconnect_data);
|
||||||
|
|
||||||
if (chat->destroyed)
|
|
||||||
g_free(chat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_watcher_destroy_notify(gpointer user_data)
|
static void write_watcher_destroy_notify(gpointer user_data)
|
||||||
|
@ -592,11 +587,11 @@ error:
|
||||||
g_free(pdu);
|
g_free(pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *extract_line(GAtChat *p)
|
static char *extract_line(GAtChat *p, struct ring_buffer *rbuf)
|
||||||
{
|
{
|
||||||
unsigned int wrap = ring_buffer_len_no_wrap(p->buf);
|
unsigned int wrap = ring_buffer_len_no_wrap(rbuf);
|
||||||
unsigned int pos = 0;
|
unsigned int pos = 0;
|
||||||
unsigned char *buf = ring_buffer_read_ptr(p->buf, pos);
|
unsigned char *buf = ring_buffer_read_ptr(rbuf, pos);
|
||||||
int strip_front = 0;
|
int strip_front = 0;
|
||||||
int line_length = 0;
|
int line_length = 0;
|
||||||
char *line;
|
char *line;
|
||||||
|
@ -614,29 +609,30 @@ static char *extract_line(GAtChat *p)
|
||||||
pos += 1;
|
pos += 1;
|
||||||
|
|
||||||
if (pos == wrap)
|
if (pos == wrap)
|
||||||
buf = ring_buffer_read_ptr(p->buf, pos);
|
buf = ring_buffer_read_ptr(rbuf, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
line = g_try_new(char, line_length + 1);
|
line = g_try_new(char, line_length + 1);
|
||||||
if (!line) {
|
if (!line) {
|
||||||
ring_buffer_drain(p->buf, p->read_so_far);
|
ring_buffer_drain(rbuf, p->read_so_far);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ring_buffer_drain(p->buf, strip_front);
|
ring_buffer_drain(rbuf, strip_front);
|
||||||
ring_buffer_read(p->buf, line, line_length);
|
ring_buffer_read(rbuf, line, line_length);
|
||||||
ring_buffer_drain(p->buf, p->read_so_far - strip_front - line_length);
|
ring_buffer_drain(rbuf, p->read_so_far - strip_front - line_length);
|
||||||
|
|
||||||
line[line_length] = '\0';
|
line[line_length] = '\0';
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void new_bytes(GAtChat *p)
|
static void new_bytes(struct ring_buffer *rbuf, gpointer user_data)
|
||||||
{
|
{
|
||||||
unsigned int len = ring_buffer_len(p->buf);
|
GAtChat *p = user_data;
|
||||||
unsigned int wrap = ring_buffer_len_no_wrap(p->buf);
|
unsigned int len = ring_buffer_len(rbuf);
|
||||||
unsigned char *buf = ring_buffer_read_ptr(p->buf, p->read_so_far);
|
unsigned int wrap = ring_buffer_len_no_wrap(rbuf);
|
||||||
|
unsigned char *buf = ring_buffer_read_ptr(rbuf, p->read_so_far);
|
||||||
|
|
||||||
GAtSyntaxResult result;
|
GAtSyntaxResult result;
|
||||||
|
|
||||||
|
@ -650,7 +646,7 @@ static void new_bytes(GAtChat *p)
|
||||||
p->read_so_far += rbytes;
|
p->read_so_far += rbytes;
|
||||||
|
|
||||||
if (p->read_so_far == wrap) {
|
if (p->read_so_far == wrap) {
|
||||||
buf = ring_buffer_read_ptr(p->buf, p->read_so_far);
|
buf = ring_buffer_read_ptr(rbuf, p->read_so_far);
|
||||||
wrap = len;
|
wrap = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -660,20 +656,20 @@ static void new_bytes(GAtChat *p)
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case G_AT_SYNTAX_RESULT_LINE:
|
case G_AT_SYNTAX_RESULT_LINE:
|
||||||
case G_AT_SYNTAX_RESULT_MULTILINE:
|
case G_AT_SYNTAX_RESULT_MULTILINE:
|
||||||
have_line(p, extract_line(p));
|
have_line(p, extract_line(p, rbuf));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case G_AT_SYNTAX_RESULT_PDU:
|
case G_AT_SYNTAX_RESULT_PDU:
|
||||||
have_pdu(p, extract_line(p));
|
have_pdu(p, extract_line(p, rbuf));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case G_AT_SYNTAX_RESULT_PROMPT:
|
case G_AT_SYNTAX_RESULT_PROMPT:
|
||||||
g_at_chat_wakeup_writer(p);
|
g_at_chat_wakeup_writer(p);
|
||||||
ring_buffer_drain(p->buf, p->read_so_far);
|
ring_buffer_drain(rbuf, p->read_so_far);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ring_buffer_drain(p->buf, p->read_so_far);
|
ring_buffer_drain(rbuf, p->read_so_far);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,63 +678,9 @@ static void new_bytes(GAtChat *p)
|
||||||
p->read_so_far = 0;
|
p->read_so_far = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We're overflowing the buffer, shutdown the socket */
|
|
||||||
if (p->buf && ring_buffer_avail(p->buf) == 0)
|
|
||||||
g_source_remove(p->read_watch);
|
|
||||||
|
|
||||||
g_at_chat_unref(p);
|
g_at_chat_unref(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean received_data(GIOChannel *channel, GIOCondition cond,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
unsigned char *buf;
|
|
||||||
GAtChat *chat = data;
|
|
||||||
GIOError err;
|
|
||||||
gsize rbytes;
|
|
||||||
gsize toread;
|
|
||||||
gsize total_read = 0;
|
|
||||||
guint read_count = 0;
|
|
||||||
|
|
||||||
if (cond & G_IO_NVAL)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
/* Regardless of condition, try to read all the data available */
|
|
||||||
do {
|
|
||||||
toread = ring_buffer_avail_no_wrap(chat->buf);
|
|
||||||
|
|
||||||
if (toread == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
rbytes = 0;
|
|
||||||
buf = ring_buffer_write_ptr(chat->buf, 0);
|
|
||||||
|
|
||||||
err = g_io_channel_read(channel, (char *) buf, toread, &rbytes);
|
|
||||||
g_at_util_debug_chat(TRUE, (char *)buf, rbytes,
|
|
||||||
chat->debugf, chat->debug_data);
|
|
||||||
|
|
||||||
read_count++;
|
|
||||||
|
|
||||||
total_read += rbytes;
|
|
||||||
|
|
||||||
if (rbytes > 0)
|
|
||||||
ring_buffer_write_advance(chat->buf, rbytes);
|
|
||||||
|
|
||||||
} while (err == G_IO_ERROR_NONE && rbytes > 0 &&
|
|
||||||
read_count < chat->max_read_attempts);
|
|
||||||
|
|
||||||
if (total_read > 0)
|
|
||||||
new_bytes(chat);
|
|
||||||
|
|
||||||
if (cond & (G_IO_HUP | G_IO_ERR))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (read_count > 0 && rbytes == 0 && err != G_IO_ERROR_AGAIN)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wakeup_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
static void wakeup_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||||
{
|
{
|
||||||
GAtChat *chat = user_data;
|
GAtChat *chat = user_data;
|
||||||
|
@ -863,7 +805,7 @@ static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
|
||||||
&bytes_written);
|
&bytes_written);
|
||||||
|
|
||||||
if (err != G_IO_ERROR_NONE) {
|
if (err != G_IO_ERROR_NONE) {
|
||||||
g_source_remove(chat->read_watch);
|
io_disconnect(chat);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,17 +862,17 @@ static GAtChat *create_chat(GIOChannel *channel, GIOFlags flags,
|
||||||
|
|
||||||
if (flags & G_IO_FLAG_NONBLOCK) {
|
if (flags & G_IO_FLAG_NONBLOCK) {
|
||||||
chat->use_write_watch = TRUE;
|
chat->use_write_watch = TRUE;
|
||||||
chat->max_read_attempts = 3;
|
chat->io = g_at_io_new(channel);
|
||||||
} else {
|
} else {
|
||||||
chat->use_write_watch = FALSE;
|
chat->use_write_watch = FALSE;
|
||||||
chat->max_read_attempts = 1;
|
chat->io = g_at_io_new_blocking(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
chat->buf = ring_buffer_new(4096);
|
if (!chat->io)
|
||||||
|
|
||||||
if (!chat->buf)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
g_at_io_set_disconnect_function(chat->io, io_disconnect, chat);
|
||||||
|
|
||||||
chat->command_queue = g_queue_new();
|
chat->command_queue = g_queue_new();
|
||||||
|
|
||||||
if (!chat->command_queue)
|
if (!chat->command_queue)
|
||||||
|
@ -943,18 +885,15 @@ static GAtChat *create_chat(GIOChannel *channel, GIOFlags flags,
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
chat->channel = channel;
|
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,
|
g_at_io_set_read_handler(chat->io, new_bytes, chat);
|
||||||
received_data, chat,
|
|
||||||
read_watcher_destroy_notify);
|
|
||||||
|
|
||||||
chat->syntax = g_at_syntax_ref(syntax);
|
chat->syntax = g_at_syntax_ref(syntax);
|
||||||
|
|
||||||
return chat;
|
return chat;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (chat->buf)
|
g_at_io_unref(chat->io);
|
||||||
ring_buffer_free(chat->buf);
|
|
||||||
|
|
||||||
if (chat->command_queue)
|
if (chat->command_queue)
|
||||||
g_queue_free(chat->command_queue);
|
g_queue_free(chat->command_queue);
|
||||||
|
@ -1007,33 +946,21 @@ void g_at_chat_unref(GAtChat *chat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_at_chat_shutdown(chat);
|
g_at_chat_shutdown(chat);
|
||||||
|
g_free(chat);
|
||||||
/* glib delays the destruction of the watcher until it exits, this
|
|
||||||
* means we can't free the data just yet, even though we've been
|
|
||||||
* destroyed already. We have to wait until the read_watcher
|
|
||||||
* destroy function gets called
|
|
||||||
*/
|
|
||||||
if (chat->read_watch != 0)
|
|
||||||
chat->destroyed = TRUE;
|
|
||||||
else
|
|
||||||
g_free(chat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean g_at_chat_shutdown(GAtChat *chat)
|
gboolean g_at_chat_shutdown(GAtChat *chat)
|
||||||
{
|
{
|
||||||
if (chat->channel == NULL)
|
if (chat->io == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Don't trigger user disconnect on shutdown */
|
|
||||||
chat->user_disconnect = NULL;
|
|
||||||
chat->user_disconnect_data = NULL;
|
|
||||||
|
|
||||||
if (chat->read_watch)
|
|
||||||
g_source_remove(chat->read_watch);
|
|
||||||
|
|
||||||
if (chat->write_watch)
|
if (chat->write_watch)
|
||||||
g_source_remove(chat->write_watch);
|
g_source_remove(chat->write_watch);
|
||||||
|
|
||||||
|
g_at_io_set_read_handler(chat->io, NULL, NULL);
|
||||||
|
g_at_io_unref(chat->io);
|
||||||
|
g_at_chat_cleanup(chat);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1058,6 +985,8 @@ gboolean g_at_chat_set_debug(GAtChat *chat,
|
||||||
chat->debugf = func;
|
chat->debugf = func;
|
||||||
chat->debug_data = user_data;
|
chat->debug_data = user_data;
|
||||||
|
|
||||||
|
g_at_io_set_debug(chat->io, func, user_data);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue