--- a/src/serial.c Thu Apr 03 19:44:53 2014 +0300
+++ b/src/serial.c Thu Apr 03 20:25:12 2014 +0300
@@ -1,27 +1,30 @@
-
+/** Serial modes */
static enum {
SERIAL_MODE_ASYNC = 0b00,
} serial_mode = SERIAL_MODE_ASYNC;
static enum {
SERIAL_BAUD_9600 = 103,
-
} serial_baud = SERIAL_BAUD_9600;
static enum {
SERIAL_PARITY_N = 0b00,
-
} serial_parity = SERIAL_PARITY_N;
static enum {
SERIAL_STOPBITS_1 = 0b0,
-
} serial_stopbits = SERIAL_STOPBITS_1;
static enum {
SERIAL_CHARS_8 = 0b011,
} serial_chars = SERIAL_CHARS_8;
+/** Serial state */
+char serial_rx = 0;
+char serial_tx = 0;
+
+void serial_enable (char rx, char tx);
+
/*
* Setup the UART for serial mode.
*/
@@ -55,13 +58,22 @@
| (0b0 << UCPOL0)
);
UBRR0 = serial_baud;
+
+ // active RX, idle TX
+ serial_enable(1, 0);
}
-void serial_enable ()
+void serial_enable (char rx, char tx)
{
UCSR0B = (
+ // RX Complete Interrupt Enable
+ (!!rx << RXCIE0)
+
+ // USART Data Register Empty Interrupt Enable
+ | (!!tx << UDRIE0)
+
// Receiver Enable
- (0b1 << RXEN0) // enabled
+ | (0b1 << RXEN0) // enabled
// Transmitter Enable
| (0b1 << TXEN0) // enabled
@@ -71,18 +83,47 @@
);
}
+/*
+ * Read incoming into buffer.
+ */
+ISR(USART_RX_vect)
+{
+ serial_rx = UDR0;
+}
+
+/*
+ * Write outgoing buffer.
+ */
+ISR(USART_UDRE_vect)
+{
+ UDR0 = serial_tx;
+
+ // tx buffer consumed
+ serial_tx = 0;
+
+ // idle tx
+ serial_enable(1, 0);
+}
+
char serial_read ()
{
- while (!tbi(&UCSR0A, RXC0))
- ;
+ char rx = serial_rx;
- return UDR0;
+ // rx buffer consumed
+ serial_rx = 0;
+
+ return rx;
}
void serial_write (char c)
{
- while (!tbi(&UCSR0A, UDRE0))
- ;
-
- UDR0 = c;
+ // XXX: atomic?
+ if (tbi(&UCSR0A, UDRE0)) {
+ // direct
+ UDR0 = c;
+ } else {
+ // buffered
+ serial_tx = c;
+ serial_enable(1, 1);
+ }
}