summaryrefslogtreecommitdiff
path: root/gatchat/gathdlc.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2010-04-23 17:18:30 +0200
committerMarcel Holtmann <marcel@holtmann.org>2010-04-23 17:18:30 +0200
commita31870f54255b1e3ac0832d30a114ea415ee9698 (patch)
tree8a82a055236ba81020b8574ec42f98ab8544f741 /gatchat/gathdlc.c
parentfa5e8cf56b92f5000501f9391c14e94b0ab2cd76 (diff)
downloadofono-a31870f54255b1e3ac0832d30a114ea415ee9698.tar.gz
Add support for wrapping of HDLC receive ring buffer
Diffstat (limited to 'gatchat/gathdlc.c')
-rw-r--r--gatchat/gathdlc.c55
1 files changed, 34 insertions, 21 deletions
diff --git a/gatchat/gathdlc.c b/gatchat/gathdlc.c
index 19df9c60..e0605560 100644
--- a/gatchat/gathdlc.c
+++ b/gatchat/gathdlc.c
@@ -32,6 +32,15 @@
#define BUFFER_SIZE 2048
+#define HDLC_FLAG 0x7e /* Flag sequence */
+#define HDLC_ESCAPE 0x7d /* Asynchronous control escape */
+#define HDLC_TRANS 0x20 /* Asynchronous transparency modifier */
+
+#define HDLC_INITFCS 0xffff /* Initial FCS value */
+#define HDLC_GOODFCS 0xf0b8 /* Good final FCS value */
+
+#define HDLC_FCS(fcs, c) crc_ccitt_byte(fcs, c)
+
struct _GAtHDLC {
gint ref_count;
GIOChannel *channel;
@@ -43,6 +52,7 @@ struct _GAtHDLC {
unsigned char *decode_buffer;
guint decode_offset;
guint16 decode_fcs;
+ gboolean decode_escape;
GAtReceiveFunc receive_func;
gpointer receive_data;
GAtDebugFunc debugf;
@@ -52,38 +62,40 @@ struct _GAtHDLC {
static void new_bytes(GAtHDLC *hdlc)
{
unsigned int len = ring_buffer_len(hdlc->read_buffer);
+ unsigned int wrap = ring_buffer_len_no_wrap(hdlc->read_buffer);
unsigned char *buf = ring_buffer_read_ptr(hdlc->read_buffer, 0);
- unsigned char val;
unsigned int pos = 0;
while (pos < len) {
- if (buf[pos] == 0x7e) {
+ if (hdlc->decode_escape == TRUE) {
+ unsigned char val = *buf ^ HDLC_TRANS;
+
+ hdlc->decode_buffer[hdlc->decode_offset++] = val;
+ hdlc->decode_fcs = HDLC_FCS(hdlc->decode_fcs, val);
+
+ hdlc->decode_escape = FALSE;
+ } else if (*buf == HDLC_ESCAPE) {
+ hdlc->decode_escape = TRUE;
+ } else if (*buf == HDLC_FLAG) {
if (hdlc->receive_func && hdlc->decode_offset > 2 &&
- hdlc->decode_fcs == 0xf0b8) {
+ hdlc->decode_fcs == HDLC_GOODFCS) {
hdlc->receive_func(hdlc->decode_buffer,
hdlc->decode_offset - 2,
hdlc->receive_data);
}
- hdlc->decode_fcs = 0xffff;
+ hdlc->decode_fcs = HDLC_INITFCS;
hdlc->decode_offset = 0;
- pos++;
- continue;
+ } else {
+ hdlc->decode_buffer[hdlc->decode_offset++] = *buf;
+ hdlc->decode_fcs = HDLC_FCS(hdlc->decode_fcs, *buf);
}
- if (buf[pos] == 0x7d) {
- if (pos + 2 > len)
- break;
- pos++;
- val = buf[pos] ^ 0x20;
- } else
- val = buf[pos];
-
- hdlc->decode_buffer[hdlc->decode_offset] = val;
- hdlc->decode_fcs = crc_ccitt_byte(hdlc->decode_fcs, val);
-
- hdlc->decode_offset++;
+ buf++;
pos++;
+
+ if (pos == wrap)
+ buf = ring_buffer_read_ptr(hdlc->read_buffer, pos);
}
ring_buffer_drain(hdlc->read_buffer, pos);
@@ -158,8 +170,9 @@ GAtHDLC *g_at_hdlc_new(GIOChannel *channel)
return NULL;
hdlc->ref_count = 1;
- hdlc->decode_fcs = 0xffff;
+ hdlc->decode_fcs = HDLC_INITFCS;
hdlc->decode_offset = 0;
+ hdlc->decode_escape = FALSE;
hdlc->max_read_attempts = 8;
hdlc->read_buffer = ring_buffer_new(BUFFER_SIZE);
@@ -319,7 +332,7 @@ gboolean g_at_hdlc_send(GAtHDLC *hdlc, const unsigned char *data, gsize size)
{
unsigned char *buf;
unsigned int space, i = 0;
- guint16 fcs = 0xffff;
+ guint16 fcs = HDLC_INITFCS;
gsize pos;
do {
@@ -335,7 +348,7 @@ gboolean g_at_hdlc_send(GAtHDLC *hdlc, const unsigned char *data, gsize size)
hdlc_put(hdlc, buf, &pos, data[i++]);
}
- fcs ^= 0xffff;
+ fcs ^= HDLC_INITFCS;
hdlc_put(hdlc, buf, &pos, fcs & 0xff);
hdlc_put(hdlc, buf, &pos, fcs >> 8);