|
- #include <pic.h>
- #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');
- }
|