diff --git a/core/dev/serial-line.c b/core/dev/serial-line.c index 77a41fe27..b1ed3854c 100644 --- a/core/dev/serial-line.c +++ b/core/dev/serial-line.c @@ -28,23 +28,29 @@ * * This file is part of the Contiki operating system. * - * @(#)$Id: serial-line.c,v 1.1 2009/03/17 15:56:33 adamdunkels Exp $ + * @(#)$Id: serial-line.c,v 1.2 2009/10/27 16:20:31 fros4943 Exp $ */ #include "dev/serial-line.h" #include /* for memcpy() */ +#include "lib/ringbuf.h" + #ifdef SERIAL_LINE_CONF_BUFSIZE #define BUFSIZE SERIAL_LINE_CONF_BUFSIZE #else /* SERIAL_LINE_CONF_BUFSIZE */ -#define BUFSIZE 80 +#define BUFSIZE 128 #endif /* SERIAL_LINE_CONF_BUFSIZE */ +#if (BUFSIZE & (BUFSIZE - 1)) != 0 +#error SERIAL_LINE_CONF_BUFSIZE must be a power of two (i.e., 1, 2, 4, 8, 16, 32, 64, ...). +#error Change SERIAL_LINE_CONF_BUFSIZE in contiki-conf.h. +#endif + #define IGNORE_CHAR(c) (c == 0x0d) #define END 0x0a -static char buffer[BUFSIZE], appbuffer[BUFSIZE]; -static volatile unsigned char bufwptr; -static volatile char buffer_full = 0; +static struct ringbuf rxbuf; +static uint8_t rxbuf_data[BUFSIZE]; PROCESS(serial_line_process, "Serial driver"); @@ -55,18 +61,31 @@ process_event_t serial_line_event_message; int serial_line_input_byte(unsigned char c) { - if(!buffer_full && !IGNORE_CHAR(c)) { - if(c == END) { - /* terminate the string */ - buffer[bufwptr++] = '\0'; - buffer_full++; - process_poll(&serial_line_process); - return 1; + static uint8_t overflow = 0; /* Buffer overflow: ignore until END */ + + if(!IGNORE_CHAR(c)) { + if(!overflow) { + /* Add character */ + if(ringbuf_put(&rxbuf, c) == 0) { + /* Buffer overflow: ignore the rest of the line */ + overflow = 1; + process_poll(&serial_line_process); + } + } else { + /* Buffer overflowed: + * Only (try to) add terminator characters, otherwise skip */ + if(c == END && ringbuf_put(&rxbuf, c) != 0) { + overflow = 0; + } else { + process_poll(&serial_line_process); + } } - /* reserve space for the terminating zero character */ - if(bufwptr < (BUFSIZE - 1)) { - buffer[bufwptr++] = c; + if(c == END && !overflow) { + /* Tell process at least one (potentially cropped due to overflow) + * line exists in the buffer */ + process_poll(&serial_line_process); + return 1; } } return 0; @@ -74,21 +93,40 @@ serial_line_input_byte(unsigned char c) /*---------------------------------------------------------------------------*/ PROCESS_THREAD(serial_line_process, ev, data) { + static char buf[128]; + static int ptr; + PROCESS_BEGIN(); - bufwptr = 0; - buffer_full = 0; - serial_line_event_message = process_alloc_event(); + ptr=0; while(1) { - PROCESS_YIELD(); - - if(buffer_full) { - memcpy(appbuffer, buffer, bufwptr); - process_post(PROCESS_BROADCAST, serial_line_event_message, appbuffer); - bufwptr = 0; - buffer_full = 0; + + /* Fill application buffer until newline or empty */ + int c = ringbuf_get(&rxbuf); + if(c == -1) { + /* Buffer empty, wait for poll */ + PROCESS_YIELD(); + } else { + if(c != END) { + buf[ptr++] = (uint8_t)c; + } else { + /* Terminate */ + buf[ptr++] = (uint8_t)'\0'; + + if (ptr > 1) { + /* Broadcast event */ + process_post(PROCESS_BROADCAST, serial_line_event_message, buf); + + /* Wait until all processes have handled the serial line event */ + if(PROCESS_ERR_OK == + process_post(PROCESS_CURRENT(), PROCESS_EVENT_CONTINUE, NULL)) { + PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_CONTINUE); + } + } + ptr = 0; + } } } @@ -98,6 +136,7 @@ PROCESS_THREAD(serial_line_process, ev, data) void serial_line_init(void) { + ringbuf_init(&rxbuf, rxbuf_data, sizeof(rxbuf_data)); process_start(&serial_line_process, NULL); } /*---------------------------------------------------------------------------*/