-#include "comm.h"
-#include "vend.h"
-
-#define DLAB_SET() bset((void*)&_uart_regs[UART_LINE_CTL], LC_DLAB);
-#define DLAB_CLR() bclr((void*)&_uart_regs[UART_LINE_CTL], LC_DLAB);
-
-char tx_buffer[TX_BUFFER_LEN+2];
-volatile char rx_buffer[RX_BUFFER_LEN+1];
-volatile u8 rx_buf_pos; /* -ve denotes not sending/receiving */
-volatile char msg_buf[RX_BUFFER_LEN+1]; /* rx_buffer copied here without \n */
-volatile u8 rx_queue_state, tx_queue_state;
-volatile bool packet_is_bad;
-
-/* If we were controlling a modem we'd probably do a lot more such as toggling
- * the control lines (DTR,RTS etc). But given this is a very stripped down
- * version talking over merely TX/RX, we don't care about these control lines.
- *
- * This code speak 8 data bits, No parity, 1 Stop bit, at the baud rate specified
- * in comm.h (should be 9600 bps)
- */
-
-u8 uart_init() {
- /*
- * Because in our daughterboard circuit we are not connecting the reset line
- * to the CPU's, we can not make any assumptions about the state of the UART.
- * Hence we initialize all registers and flush the FIFOs
- */
-
- u16 divisor;
- lock(); /* disable interrupts for this */
-
- /* set baud rate */
- divisor = UART_SPEED / BAUD_RATE;
- DLAB_SET();
- _uart_regs[UART_DLAB_MSB] = (u8)(divisor >> 8);
- _uart_regs[UART_DLAB_LSB] = (u8)(divisor & 0xff);
- DLAB_CLR();
-
- /* set RX, TX & LS interrupts */
- _uart_regs[UART_INT_ENABLE] =
- IE_RECEIVER_READY | IE_TRANSMITTER_READY | IE_LINE_STATUS_CHANGE;
-
- /* Enable the FIFO and empty them */
- _uart_regs[UART_FIFO_CTL] =
- FIFO_ENABLE | FIFO_RX_CLEAR | FIFO_TX_CLEAR | FIFO_LVL_1;
-
- /* 8 data bits, 1 stop bit, no parity. */
- _uart_regs[UART_LINE_CTL] = LC_8BITS;
-
- /* modem controls: clear them all */
- _uart_regs[UART_MODEM_CTL] = 0;
-
- rx_queue_state = 0;
- tx_queue_state = 0;
- rx_buf_pos = 0;
-
- unlock();
- return 1;
-}
-
-/*******************************************************************************
- * Interrupt handler for UART.
- *
- * This actually consists of several functions, rolled into one.
- */
-
-extern inline void rx_int() {
- char c = _uart_regs[UART_RX_BUFFER];
- if (rx_queue_state == 2) return; /* buffers full. too bad */
-
- if (rx_buf_pos < RX_BUFFER_LEN) {
- rx_buffer[rx_buf_pos] = c;
-
- if (c == '\n') {
- rx_buf_pos = 0;
- if (packet_is_bad) {
- packet_is_bad = 0;
- /* just forget this packet ever happened */
- } else {
- rx_buffer[rx_buf_pos] = 0;
- switch (rx_queue_state) {
- case 0:
- my_strncpy((char*)msg_buf, (char*)rx_buffer, RX_BUFFER_LEN);
- rx_queue_state++;
- case 1:
- /* we can't copy it in yet. will be done from msg_clr() */
- rx_queue_state++;
- break;
- case 2: /* another weird case? */
- default:
- break;
- }
- }
- } else
- rx_buf_pos++;
- } /* else drop it (buffer full) - probably a corrupt packet */
-}
-
-extern inline void tx_int() {
- /* this interrupt is called with the precondition that the TX fifo of the UART
- * is completely empty and will hold a complete message (of less than 14 chars)
- */
- if (tx_queue_state & 0x01) { /* msg to be sent pending */
- /* load it in */
- int i;
- for (i=0; tx_buffer[i]; i++)
- _uart_regs[UART_TX_BUFFER] = tx_buffer[i];
- bclr((void*)&tx_queue_state, 0x01);
- } else
- bclr((void*)&tx_queue_state, 0x02); /* mark the FIFO as free */
-}
-
-void uart_interrupt() {
- u8 status;
- while (1) {
- status = _uart_regs[UART_INT_IDENT];
- switch (status) {
- case IS_FIFO_TIMEOUT:
- case IS_RECEIVER_READY:
- rx_int();
- break;
- case IS_TRANSMITTER_READY:
- tx_int();
- break;
- case IS_MODEM_STATUS_CHANGE:
- /* read the modem status register to clear the interrupt */
- (void)_uart_regs[UART_MODEM_STATUS];
- break;
- case IS_LINE_STATUS_CHANGE:
- status = _uart_regs[UART_LINE_STATUS];
- if (status & LS_OVERRUN_ERR) packet_is_bad = 1;
- if (status & LS_PARITY_ERR) packet_is_bad = 1;
- if (status & LS_FRAMING_ERR) packet_is_bad = 1;
- /* LS_BREAK_INTERRUPT ignored for now. Do we want it? */
- break;
- default:
- return;
- }
- }
-}
-
-/*******************************************************************************
- * End of interrupt handler
- */
-
-void send_ack() {
- wait_for_tx_free();
- tx_buffer[0] = '!';
- tx_buffer[1] = '\n';
- tx_buffer[2] = 0;
- send_packet();
-}
-
-void send_nack() {
- wait_for_tx_free();
- tx_buffer[0] = '?';
- tx_buffer[1] = '\n';
- tx_buffer[2] = 0;
- send_packet();
-}
-
-/* sends the packet in tx_buffer and doesn't return until it's been sent */
-void send_packet() {
- bset((void*)&tx_queue_state, 0x01);
- lock();
- tx_int();
- unlock();
- while (tx_queue_state & 0x01); /* wait for completion */
-}
-
-void msg_clr() {
- /* called when a msg in msg_buf has been read */
- switch (rx_queue_state) {
- case 0: /* this shouldn't happen */
- break;
- case 1:
- lock();
- rx_queue_state = 0;
- unlock();
- break;
- case 2:
- /* copy the rx_buffer into msg_buf */
- my_strncpy((char*)msg_buf, (char*)rx_buffer, RX_BUFFER_LEN);
- lock();
- rx_queue_state = 1;
- unlock();
- break;
- default:
- lock();
- rx_queue_state = 0;
- unlock();
- }
-}
-
-
-void comm_init() {
- uart_init();
- lock();
- tx_buffer[0] = rx_buffer[0] = msg_buf[0] = 0;
- packet_is_bad = 0;
- unlock();
-}