Initial import of v2 goggles that use ws2812 rings from adafruit
[goggles] / serial.c
1 /***
2  *** Serial Port driver for 16f1455 and kin
3  ***/
4
5 #include "user.h"
6 #include <stdint.h>
7 #include <stdbool.h>
8
9 /* outgoing text buffer */
10 char outbuff[3];
11 char * outp = 0;
12 uint8_t outlen = 0;
13
14 /* incoming text buffer */
15 char inbuff[1];
16 uint8_t inlen = 0;
17
18
19 void serial_init(void)
20 {
21     /* Enabling transmitter 26.1.1.1 page 259 - TX/CK I/O pin */
22     TXSTAbits.TXEN = 1;
23     TXSTAbits.SYNC = 0;
24     RCSTAbits.SPEN = 1;
25     /* Enabling receiver 26.1.2 page 262 - RX/DT I/O pin */
26     RCSTAbits.CREN = 1;
27         
28     /* Switch serial port to alternate pins */
29     APFCON0bits.RXDTSEL = 1;
30     APFCON0bits.TXCKSEL = 1;
31
32     ANSELAbits.ANSA4 = 0;
33     
34     /* Select pins 4&5 as the uart - page 102 */
35     TRISAbits.TRISA4 = 0;   /* RA4 as TX output  */
36     TRISAbits.TRISA5 = 1;   /* RA5 as RX input */
37
38 #if _XTAL_FREQ != 32000000L
39 #error "Adjust serial port baudrate settings"
40 #endif
41     
42     /* assume 32MHz clock, 19k2 baud */
43     TXSTAbits.BRGH = 0;
44     BAUDCONbits.BRG16 = 1;
45     SPBRGL = 103;
46
47     /* Enable interrupts */
48     INTCONbits.GIE = 1;
49     INTCONbits.PEIE = 1;
50
51     /* enable uart receiver interupt */
52     PIE1bits.RCIE = 1;
53 }
54
55
56 /* is the queue empty yet */
57 bool msg_empty(void)
58 {
59     if (outp == 0) return 1;
60     return 0;
61 }
62
63 /* new message in the queue */
64 void msg_write(const char *msg)
65 {
66     char * p = outbuff + outlen;
67     while (outlen < sizeof(outbuff) && *msg != 0) {
68         *(p++) = *(msg++);
69         outlen++;
70     }
71     *p = 0;
72     if (outp == 0) {
73         outp = outbuff;
74         PIE1bits.TXIE = 1;
75     }
76 }
77
78 void msg_writebyte(const char msg)
79 {
80     if (outlen+1 >= (uint8_t)sizeof(outbuff)) return;
81     outbuff[outlen++] = msg;
82     outbuff[outlen] = 0;
83     if (outp == 0) {
84         outp = outbuff;
85         PIE1bits.TXIE = 1;
86     }
87 }
88
89 /* some library functions will use this if defined, eg printf */
90 void putch(char data)
91 {
92     msg_writebyte(data);
93 }
94
95 /* called from interrupt routine to send next char */
96 void msg_sendnext(void)
97 {
98     /* we have finished, turn off the iterrupt */
99     if (outp == 0 || *outp == 0) {
100         PIE1bits.TXIE = 0;
101         outp = 0;
102         outlen = 0;
103         return;
104     }
105     TXREG = *outp;
106     outp++;
107 }
108
109 /* called from interrupt routine to receive next byte */
110 void msg_recvnext(void)
111 {
112     while (PIR1bits.RCIF) {
113         /* bad char, skip it */
114         if (RCSTAbits.FERR) {
115             RCREG==0?0:0; // discard by reading
116             continue;
117         }
118
119         /* our input buffer has overflowed */
120         if (inlen > sizeof(inbuff)) {
121             RCREG==0?0:0; // discard by reading
122             return;
123         }
124
125         /* keep this one */
126         inbuff[inlen++] = RCREG;
127     }
128 }
129
130 /* is there text waiting to be read */
131 bool msg_recvready(void)
132 {
133     if (inlen > 0) return 1;
134     return 0;
135 }
136
137 /* read next byte from inpout buffer */
138 char msg_recv(void)
139 {
140     if (inlen == 0) return 0;
141
142     /* record and disable the interupt */
143     bool in = PIE1bits.RCIE;
144     PIE1bits.RCIE = 0;
145
146     char new = inbuff[0];
147     inlen--;
148
149     /* shuffle them down one */
150     for (char i=0;i<inlen;i++)
151         inbuff[i] = inbuff[i+1];
152
153     /* restore the interupt */
154     PIE1bits.RCIE = in;
155     return new;
156 }
157
158 inline void msg_flush(void)
159 {
160     while (!msg_empty());
161 }