]> Pileus Git - ~andy/csm213a-hw/blob - hw2/serial_irq.c
Add serial transmit call
[~andy/csm213a-hw] / hw2 / serial_irq.c
1 #include <MKL46Z4.h>\r
2 \r
3 #include <stdint.h>\r
4 #include <stdio.h>\r
5 #include "serial_api.h"\r
6 #include "serial_irq.h"\r
7 #include "timer_dma.h"\r
8 \r
9 /* Defines */\r
10 #define SIRQ_LEN  1024\r
11 \r
12 /* Port structure */\r
13 typedef struct {\r
14         int     rix;\r
15         int     wix;\r
16         uint8_t buf[SIRQ_LEN];\r
17 } queue_t;\r
18 \r
19 struct sirq_t {\r
20         serial_t uart;\r
21         queue_t  xmt;\r
22         queue_t  rcv;\r
23         int      irq;\r
24         int      buffered;\r
25 };\r
26 \r
27 /* Port data */\r
28 static sirq_t sirq_ports[SIRQ_NUM_UART];\r
29 \r
30 /* Receive handler */\r
31 void sirq_handler(uint32_t _port, SerialIrq event)\r
32 {\r
33         sirq_t *port = (sirq_t *)_port;\r
34 \r
35         // Handle transmit\r
36         //   note: mbed seems to call TxIrq even it is not enabled,\r
37         //   so we need to manually prevent transmitting when the\r
38         //   port is set to buffered mode.\r
39         if (event == TxIrq && (port->irq || !port->buffered)) {\r
40                 if (port->xmt.rix != port->xmt.wix) {\r
41                         int byte = port->xmt.buf[port->xmt.rix];\r
42                         serial_putc(&port->uart, byte);\r
43                         port->xmt.rix = (port->xmt.rix+1) % SIRQ_LEN;\r
44                 } else {\r
45                         serial_irq_set(&port->uart, TxIrq, 0);\r
46                         port->irq = 0;\r
47                 }\r
48         }\r
49 \r
50         // Handle receive\r
51         if (event == RxIrq) {\r
52                 int byte = serial_getc(&port->uart);\r
53                 port->rcv.buf[port->rcv.wix] = byte;\r
54                 port->rcv.wix = (port->rcv.wix+1) % SIRQ_LEN;\r
55         }\r
56 }\r
57 \r
58 /* Open port */\r
59 sirq_t *sirq_open(sirq_uart_t uart, PinName tx, PinName rx, int baud, int buffered)\r
60 {\r
61         // Allocate port\r
62         sirq_t *port = &sirq_ports[uart];\r
63 \r
64         // Buffered ports only transmit on demand\r
65         port->buffered = buffered;\r
66 \r
67         // Configure port\r
68         serial_init(&port->uart, tx, rx);\r
69         serial_baud(&port->uart, baud);\r
70 \r
71         // Set IRQ handlers\r
72         serial_irq_handler(&port->uart, sirq_handler, (uint32_t)port);\r
73         serial_irq_set(&port->uart, RxIrq, 1);\r
74 \r
75         return port;\r
76 }\r
77 \r
78 /* Write byte to the port */\r
79 void sirq_putc(sirq_t *port, int byte)\r
80 {\r
81         port->xmt.buf[port->xmt.wix] = byte;\r
82         port->xmt.wix = (port->xmt.wix+1) % SIRQ_LEN;\r
83         if (!port->buffered)\r
84                 sirq_transmit(port);\r
85 }\r
86 \r
87 /* Read byte from the port */\r
88 int sirq_getc(sirq_t *port)\r
89 {\r
90         int byte = 0;\r
91         if (port->rcv.rix != port->rcv.wix) {\r
92                 byte = port->rcv.buf[port->rcv.rix];\r
93                 port->rcv.rix = (port->rcv.rix+1) % SIRQ_LEN;\r
94         }\r
95         return byte;\r
96 }\r
97 \r
98 /* Enable transmitter */\r
99 void sirq_transmit(sirq_t *port)\r
100 {\r
101         if (port->xmt.rix != port->xmt.wix && !port->irq) {\r
102                 port->irq = 1;\r
103                 serial_irq_set(&port->uart, TxIrq, 1);\r
104         }\r
105 }\r
106 \r
107 /* Buffered write */\r
108 void sirq_write(sirq_t *port, void *data, int len)\r
109 {\r
110         uint8_t *bytes = (uint8_t*)data;\r
111         for (int i = 0; i < len; i++)\r
112                 sirq_putc(port, bytes[i]);\r
113 }\r
114 \r
115 /* Check if port is writable */\r
116 int sirq_ready(sirq_t *port)\r
117 {\r
118         return port->rcv.rix != port->rcv.wix;\r
119 }\r
120 \r
121 /* Debug print */\r
122 void sirq_debug(sirq_t *port)\r
123 {\r
124         sirq_printf("xmt  - wix:%03x rix:%03x\r\n", port->xmt.wix, port->xmt.rix);\r
125         sirq_printf("rcv  - wix:%03x rix:%03x\r\n", port->rcv.wix, port->rcv.rix);\r
126         sirq_printf("irq  - ??\r\n");\r
127         sirq_printf("uart - ??\r\n");\r
128 \r
129         // __IO uint8_t BDH;     \r
130         // __IO uint8_t BDL;     \r
131         // __IO uint8_t C1;      \r
132         // __IO uint8_t C2;      \r
133         // __IO uint8_t S1;      \r
134         // __IO uint8_t S2;      \r
135         // __IO uint8_t C3;      \r
136         // __IO uint8_t D;       \r
137         // __IO uint8_t MA1;     \r
138         // __IO uint8_t MA2;     \r
139         // __IO uint8_t C4;      \r
140         // __IO uint8_t C5;      \r
141 }\r
142 \r
143 /* Write ASCII data to the output queue */\r
144 void sirq_vprintf(const char *fmt, va_list ap)\r
145 {\r
146         static char buf[512];\r
147         int len = vsnprintf(buf, sizeof(buf), fmt, ap);\r
148         for (int i = 0; i < len; i++)\r
149                 sirq_putc(&sirq_ports[0], buf[i]);\r
150 }\r
151 \r
152 void sirq_printf(const char *fmt, ...)\r
153 {\r
154         va_list ap;\r
155         va_start(ap, fmt);\r
156         sirq_vprintf(fmt, ap);\r
157         va_end(ap);\r
158 }\r