terom@53: /** Serial modes */ terom@52: static enum { terom@52: SERIAL_MODE_ASYNC = 0b00, terom@52: } serial_mode = SERIAL_MODE_ASYNC; terom@52: terom@52: static enum { terom@52: SERIAL_BAUD_9600 = 103, terom@52: } serial_baud = SERIAL_BAUD_9600; terom@52: terom@52: static enum { terom@52: SERIAL_PARITY_N = 0b00, terom@52: } serial_parity = SERIAL_PARITY_N; terom@52: terom@52: static enum { terom@52: SERIAL_STOPBITS_1 = 0b0, terom@52: } serial_stopbits = SERIAL_STOPBITS_1; terom@52: terom@52: static enum { terom@52: SERIAL_CHARS_8 = 0b011, terom@52: } serial_chars = SERIAL_CHARS_8; terom@52: terom@53: /** Serial state */ terom@69: #define SERIAL_BUF 64 terom@69: terom@69: struct serial { terom@69: char buf[SERIAL_BUF]; terom@69: byte in, out; terom@69: } serial_rx; terom@69: terom@53: char serial_tx = 0; terom@53: terom@53: void serial_enable (char rx, char tx); terom@53: terom@52: /* terom@52: * Setup the UART for serial mode. terom@52: */ terom@52: void serial_init () terom@52: { terom@52: UCSR0A = ( terom@52: // Double the USART Transmission Speed terom@52: (0b0 << U2X0) // single speed terom@52: terom@52: // Multi-processor Communication Mode terom@52: | (0b0 << MPCM0) // off terom@52: ); terom@52: UCSR0B = ( terom@52: // Character Size terom@52: ((serial_chars >> 2) << UCSZ02) // standard character sizes terom@52: ); terom@52: UCSR0C = ( terom@52: // USART Mode Select terom@52: (serial_mode << UMSEL00) // async terom@52: terom@52: // Parity Mode terom@52: | (serial_parity << UPM00) terom@52: terom@52: // Stop Bit Select terom@52: | (serial_stopbits << USBS0) terom@52: terom@52: // Character Size terom@52: | ((serial_chars & 0b11) << UCSZ00) terom@52: terom@52: // Clock Polarity terom@52: | (0b0 << UCPOL0) terom@52: ); terom@52: UBRR0 = serial_baud; terom@53: terom@53: // active RX, idle TX terom@53: serial_enable(1, 0); terom@52: } terom@52: terom@53: void serial_enable (char rx, char tx) terom@52: { terom@52: UCSR0B = ( terom@53: // RX Complete Interrupt Enable terom@53: (!!rx << RXCIE0) terom@53: terom@53: // USART Data Register Empty Interrupt Enable terom@53: | (!!tx << UDRIE0) terom@53: terom@52: // Receiver Enable terom@53: | (0b1 << RXEN0) // enabled terom@52: terom@52: // Transmitter Enable terom@52: | (0b1 << TXEN0) // enabled terom@52: terom@52: // Character Size terom@52: | ((serial_chars >> 2) << UCSZ02) // standard character sizes terom@52: ); terom@52: } terom@52: terom@53: /* terom@53: * Read incoming into buffer. terom@53: */ terom@53: ISR(USART_RX_vect) terom@53: { terom@69: serial_rx.buf[serial_rx.in++] = UDR0; terom@69: terom@69: if (serial_rx.in >= SERIAL_BUF) terom@69: serial_rx.in = 0; terom@53: } terom@53: terom@53: /* terom@53: * Write outgoing buffer. terom@53: */ terom@53: ISR(USART_UDRE_vect) terom@53: { terom@53: UDR0 = serial_tx; terom@53: terom@53: // tx buffer consumed terom@53: serial_tx = 0; terom@53: terom@53: // idle tx terom@53: serial_enable(1, 0); terom@53: } terom@53: terom@52: char serial_read () terom@52: { terom@69: if (serial_rx.out == serial_rx.in) terom@69: return 0; terom@52: terom@69: char rx = serial_rx.buf[serial_rx.out++]; terom@69: terom@69: if (serial_rx.out >= SERIAL_BUF) terom@69: serial_rx.out = 0; terom@53: terom@53: return rx; terom@52: } terom@52: terom@52: void serial_write (char c) terom@52: { terom@53: // XXX: atomic? terom@53: if (tbi(&UCSR0A, UDRE0)) { terom@53: // direct terom@53: UDR0 = c; terom@53: } else { terom@53: // buffered terom@53: serial_tx = c; terom@53: serial_enable(1, 1); terom@53: } terom@52: }