From: Marcel Holtmann Date: Sun, 11 Apr 2010 05:01:14 +0000 (+0200) Subject: Use a ring buffer for non-blocking HDLC output streams X-Git-Tag: 0.21~415 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=46e77907b37d18a78b5f76b8e0b8f2d76331444f;p=platform%2Fupstream%2Fofono.git Use a ring buffer for non-blocking HDLC output streams --- diff --git a/gatchat/gathdlc.c b/gatchat/gathdlc.c index 2dbc67e..19df9c6 100644 --- a/gatchat/gathdlc.c +++ b/gatchat/gathdlc.c @@ -36,7 +36,9 @@ struct _GAtHDLC { gint ref_count; GIOChannel *channel; guint read_watch; + guint write_watch; struct ring_buffer *read_buffer; + struct ring_buffer *write_buffer; guint max_read_attempts; unsigned char *decode_buffer; guint decode_offset; @@ -47,13 +49,6 @@ struct _GAtHDLC { gpointer debug_data; }; -static void read_watch_destroy(gpointer user_data) -{ - GAtHDLC *hdlc = user_data; - - hdlc->read_watch = 0; -} - static void new_bytes(GAtHDLC *hdlc) { unsigned int len = ring_buffer_len(hdlc->read_buffer); @@ -144,6 +139,13 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond, return TRUE; } +static void read_watch_destroy(gpointer user_data) +{ + GAtHDLC *hdlc = user_data; + + hdlc->read_watch = 0; +} + GAtHDLC *g_at_hdlc_new(GIOChannel *channel) { GAtHDLC *hdlc; @@ -164,6 +166,10 @@ GAtHDLC *g_at_hdlc_new(GIOChannel *channel) if (!hdlc->read_buffer) goto error; + hdlc->write_buffer = ring_buffer_new(BUFFER_SIZE * 2); + if (!hdlc->write_buffer) + goto error; + hdlc->decode_buffer = g_try_malloc(BUFFER_SIZE * 2); if (!hdlc->decode_buffer) goto error; @@ -185,6 +191,9 @@ error: if (hdlc->read_buffer) ring_buffer_free(hdlc->read_buffer); + if (hdlc->write_buffer) + ring_buffer_free(hdlc->write_buffer); + if (hdlc->decode_buffer) g_free(hdlc->decode_buffer); @@ -217,6 +226,7 @@ void g_at_hdlc_unref(GAtHDLC *hdlc) g_io_channel_unref(hdlc->channel); ring_buffer_free(hdlc->read_buffer); + ring_buffer_free(hdlc->write_buffer); g_free(hdlc->decode_buffer); } @@ -239,6 +249,59 @@ void g_at_hdlc_set_receive(GAtHDLC *hdlc, GAtReceiveFunc func, hdlc->receive_data = user_data; } +static gboolean can_write_data(GIOChannel *channel, GIOCondition cond, + gpointer user_data) +{ + GAtHDLC *hdlc = user_data; + GIOError err; + unsigned int len; + unsigned char *buf; + gsize bytes_written; + + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) + return FALSE; + + len = ring_buffer_len_no_wrap(hdlc->write_buffer); + buf = ring_buffer_read_ptr(hdlc->write_buffer, 0); + + err = g_io_channel_write(hdlc->channel, (const char *) buf, + len, &bytes_written); + + if (err != G_IO_ERROR_NONE) { + g_source_remove(hdlc->read_watch); + return FALSE; + } + + g_at_util_debug_dump(FALSE, buf, bytes_written, + hdlc->debugf, hdlc->debug_data); + + ring_buffer_drain(hdlc->write_buffer, bytes_written); + + if (ring_buffer_len(hdlc->write_buffer) > 0) + return TRUE; + + return FALSE; +} + +static void write_watch_destroy(gpointer user_data) +{ + GAtHDLC *hdlc = user_data; + + hdlc->write_watch = 0; +} + +static void wakeup_write(GAtHDLC *hdlc) +{ + GIOChannel *channel = hdlc->channel; + + if (hdlc->write_watch > 0) + return; + + hdlc->write_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, + G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + can_write_data, hdlc, write_watch_destroy); +} + static inline void hdlc_put(GAtHDLC *hdlc, guint8 *buf, gsize *pos, guint8 c) { gsize i = *pos; @@ -252,31 +315,36 @@ static inline void hdlc_put(GAtHDLC *hdlc, guint8 *buf, gsize *pos, guint8 c) *pos = i; } -gboolean g_at_hdlc_send(GAtHDLC *hdlc, const unsigned char *buf, gsize len) +gboolean g_at_hdlc_send(GAtHDLC *hdlc, const unsigned char *data, gsize size) { - unsigned char newbuf[BUFFER_SIZE * 2]; - GIOError err; - gsize bytes_written; - gsize pos = 0, i = 0; + unsigned char *buf; + unsigned int space, i = 0; guint16 fcs = 0xffff; + gsize pos; - newbuf[pos++] = 0x7e; + do { + space = ring_buffer_avail_no_wrap(hdlc->write_buffer); + if (space == 0) + break; - while (len--) { - fcs = crc_ccitt_byte(fcs, buf[i]); - hdlc_put(hdlc, newbuf, &pos, buf[i++]); - } + buf = ring_buffer_write_ptr(hdlc->write_buffer); + pos = 0; - fcs ^= 0xffff; - hdlc_put(hdlc, newbuf, &pos, fcs & 0xff); - hdlc_put(hdlc, newbuf, &pos, fcs >> 8); + while (size--) { + fcs = crc_ccitt_byte(fcs, data[i]); + hdlc_put(hdlc, buf, &pos, data[i++]); + } - newbuf[pos++] = 0x7e; + fcs ^= 0xffff; + hdlc_put(hdlc, buf, &pos, fcs & 0xff); + hdlc_put(hdlc, buf, &pos, fcs >> 8); - err = g_io_channel_write(hdlc->channel, (const char *) newbuf, - pos, &bytes_written); - g_at_util_debug_dump(FALSE, newbuf, bytes_written, - hdlc->debugf, hdlc->debug_data); + buf[pos++] = 0x7e; + + ring_buffer_write_advance(hdlc->write_buffer, pos); + } while (0); + + wakeup_write(hdlc); return TRUE; } diff --git a/gatchat/gathdlc.h b/gatchat/gathdlc.h index 2b7166a..a295f08 100644 --- a/gatchat/gathdlc.h +++ b/gatchat/gathdlc.h @@ -41,7 +41,7 @@ void g_at_hdlc_set_debug(GAtHDLC *hdlc, GAtDebugFunc func, gpointer user_data); void g_at_hdlc_set_receive(GAtHDLC *hdlc, GAtReceiveFunc func, gpointer user_data); -gboolean g_at_hdlc_send(GAtHDLC *hdlc, const unsigned char *buf, gsize len); +gboolean g_at_hdlc_send(GAtHDLC *hdlc, const unsigned char *data, gsize size); #ifdef __cplusplus }