#include #include "config.h" #include "serial.h" volatile uint8_t stq[STQ_SIZE], stq_start, stq_len; volatile uint8_t bank1 srq[SRQ_SIZE], srq_start, srq_len; /* * Initialization */ void serial_init(void) { /* Set up serial transmit queue and serial receive queue */ stq_start = stq_len = 0; srq_start = srq_len = 0; /* Initialize serial port with baudrate specified in config.h */ TRISRX = 1; TRISTX = 1; BRGH = 1; #define BRG (((FOSC + (8 * BAUDRATE - 1)) /(16 * BAUDRATE)) - 1) #if (BRG < 1) || (BRG > 255) #error Cannot achieve baudrate #endif #define ACT_BR (FOSC / (16 * (BRG + 1))) #if ((ACT_BR * 100 / BAUDRATE) > 105) || ((ACT_BR * 100 / BAUDRATE) < 94) #error Actual baudrate is too far from requested baudrate. Ratio is #error FOSC/(16*floor((FOSC+(8*BAUDRATE-1))/(16*BAUDRATE)))/BAUDRATE #endif SPBRG = BRG; SYNC = 0; SPEN = 1; CREN = 1; SREN = 0; TX9 = 0; RX9 = 0; TXEN = 1; /* Enable serial port interrupts. To avoid being interrupted all the time, TXIE is kept off until we have data to transmit. */ TXIE = 0; RCIE = 1; PEIE = 1; } /* * Interrupt handling */ /* Get a byte from the transmit queue and send it */ void serial_interrupt_tx(void) { if(stq_len != 0) { TXREG = stq[stq_start]; stq_start = (stq_start + 1) & STQ_MASK; stq_len--; } /* If queue is empty, disable interrupt */ if(stq_len == 0) TXIE = 0; } /* Receive a byte and write it to the receive queue. */ void serial_interrupt_rx(void) { if(FERR) { /* Framing error: discard byte */ (void) RCREG; return; } if(OERR) { /* Overflow error, clear it */ CREN = 0; CREN = 1; return; } if(!(srq_len & SRQ_SIZE)) { srq[(srq_start + srq_len) & SRQ_MASK] = RCREG; srq_len++; } else { /* Queue is full; discard data */ (void) RCREG; } } /* * Userspace interface */ /* Send byte to PC. Blocks iff transmit queue is full. */ void serial_put(uint8_t x) { while(!serial_can_put()) continue; GIE = 0; stq[(stq_start + stq_len) & STQ_MASK] = x; stq_len++; TXIE = 1; GIE = 1; } /* Get byte from PC. Blocks iff receive queue is empty. */ uint8_t serial_get(void) { uint8_t x; while(!serial_can_get()) continue; x = srq[srq_start]; GIE = 0; srq_start = (srq_start + 1) & SRQ_MASK; srq_len--; GIE = 1; return x; } /* * I/O helpers */ void serial_put_string(const uint8_t *s) { while(s && *s) serial_put(*s++); } const uint8_t hex[16]={'0','1','2','3','4','5','6','7', '8','9','a','b','c','d','e','f'}; void serial_put_hex(uint8_t x) { serial_put(hex[x >> 4]); serial_put(hex[x & 15]); } void serial_put_hex32(uint32_t x) { serial_put_hex((x >> 24) & 0xFF); serial_put_hex((x >> 16) & 0xFF); serial_put_hex((x >> 8) & 0xFF); serial_put_hex((x) & 0xFF); } void serial_crlf(void) { serial_put('\r'); serial_put('\n'); }