root / proj / src / uart.c @ 261
History | View | Annotate | Download (14 KB)
1 | 235 | up20180642 | #include <lcom/lcf.h> |
---|---|---|---|
2 | |||
3 | #include "uart.h" |
||
4 | |||
5 | #include "errors.h" |
||
6 | |||
7 | 249 | up20180642 | #define UART_BITRATE 115200 |
8 | #define UART_WAIT 20 //microseconds |
||
9 | 241 | up20180642 | |
10 | 249 | up20180642 | #define UART_RBR 0 |
11 | #define UART_THR 0 |
||
12 | #define UART_IER 1 |
||
13 | #define UART_IIR 2 |
||
14 | #define UART_FCR 2 |
||
15 | #define UART_LCR 3 |
||
16 | #define UART_MCR 4 |
||
17 | #define UART_LSR 5 |
||
18 | #define UART_MSR 6 |
||
19 | #define UART_SR 7 |
||
20 | 241 | up20180642 | |
21 | 249 | up20180642 | #define UART_DLL 0 |
22 | #define UART_DLM 1 |
||
23 | 241 | up20180642 | |
24 | 249 | up20180642 | /// LCR
|
25 | #define UART_BITS_PER_CHAR_POS 0 |
||
26 | #define UART_STOP_BITS_POS 2 |
||
27 | #define UART_PARITY_POS 3 |
||
28 | #define UART_BREAK_CONTROL_POS 6 |
||
29 | #define UART_DLAB_POS 7 |
||
30 | 241 | up20180642 | |
31 | 249 | up20180642 | #define UART_BITS_PER_CHAR (BIT(0) | BIT(1)) |
32 | #define UART_STOP_BITS (BIT(2)) |
||
33 | #define UART_PARITY (BIT(3) | BIT(4) | BIT(5)) |
||
34 | #define UART_BREAK_CONTROL (BIT(6)) |
||
35 | #define UART_DLAB (BIT(7)) |
||
36 | 241 | up20180642 | |
37 | 249 | up20180642 | #define UART_GET_BITS_PER_CHAR(n) (((n)&UART_BITS_PER_CHAR) + 5) |
38 | #define UART_GET_STOP_BITS(n) (((n)&UART_STOP_BITS)? 2 : 1) |
||
39 | #define UART_GET_PARITY(n) (((n)&UART_PARITY )>>UART_PARITY_POS )
|
||
40 | #define UART_GET_BREAK_CONTROL(n) (((n)&UART_BREAK_CONTROL)>>UART_BREAK_CONTROL_POS)
|
||
41 | #define UART_GET_DLAB(n) (((n)&UART_DLAB )>>UART_DLAB_POS )
|
||
42 | #define UART_GET_DIV_LATCH(m,l) ((m)<<8 | (l)) |
||
43 | #define UART_GET_DLL(n) ((n)&0xFF) |
||
44 | #define UART_GET_DLM(n) (((n)>>8)&0xFF) |
||
45 | 242 | up20180642 | |
46 | 249 | up20180642 | /// IER
|
47 | 252 | up20180642 | #define UART_INT_EN_RX_POS 0 |
48 | #define UART_INT_EN_TX_POS 1 |
||
49 | 249 | up20180642 | #define UART_INT_EN_RECEIVER_LINE_STAT_POS 2 |
50 | #define UART_INT_EN_MODEM_STAT_POS 3 |
||
51 | 242 | up20180642 | |
52 | 252 | up20180642 | #define UART_INT_EN_RX (BIT(0)) |
53 | #define UART_INT_EN_TX (BIT(1)) |
||
54 | 249 | up20180642 | #define UART_INT_EN_RECEIVER_LINE_STAT (BIT(2)) |
55 | #define UART_INT_EN_MODEM_STAT (BIT(3)) |
||
56 | 242 | up20180642 | |
57 | 252 | up20180642 | #define UART_GET_INT_EN_RX(n) (((n)&UART_INT_EN_RX )>>UART_INT_EN_RX_POS )
|
58 | #define UART_GET_INT_EN_TX(n) (((n)&UART_INT_EN_TX )>>UART_INT_EN_TX_POS )
|
||
59 | #define UART_GET_INT_EN_RECEIVER_LINE_STAT(n) (((n)&UART_INT_EN_RECEIVER_LINE_STAT)>>UART_INT_EN_RECEIVER_LINE_STAT_POS)
|
||
60 | #define UART_GET_INT_EN_MODEM_STAT(n) (((n)&UART_INT_EN_MODEM_STAT )>>UART_INT_EN_MODEM_STAT_POS )
|
||
61 | 249 | up20180642 | |
62 | /// LSR
|
||
63 | #define UART_RECEIVER_READY_POS 0 |
||
64 | 261 | up20180642 | #define UART_OVERRUN_ERROR_POS 1 |
65 | #define UART_PARITY_ERROR_POS 2 |
||
66 | #define UART_FRAMING_ERROR_POS 3 |
||
67 | 249 | up20180642 | #define UART_TRANSMITTER_EMPTY_POS 5 |
68 | |||
69 | #define UART_RECEIVER_READY (BIT(0)) |
||
70 | 261 | up20180642 | #define UART_OVERRUN_ERROR (BIT(1)) |
71 | #define UART_PARITY_ERROR (BIT(2)) |
||
72 | #define UART_FRAMING_ERROR (BIT(3)) |
||
73 | 249 | up20180642 | #define UART_TRANSMITTER_EMPTY (BIT(5)) |
74 | |||
75 | #define UART_GET_RECEIVER_READY(n) (((n)&UART_RECEIVER_READY )>>UART_RECEIVER_READY_POS )
|
||
76 | 261 | up20180642 | #define UART_GET_OVERRUN_ERROR (((n)&UART_OVERRUN_ERROR )>>UART_OVERRUN_ERROR_POS )
|
77 | #define UART_GET_PARITY_ERROR (((n)&UART_PARITY_ERROR )>>UART_PARITY_ERROR_POS )
|
||
78 | #define UART_GET_FRAMING_ERROR (((n)&UART_FRAMING_ERROR )>>UART_FRAMING_ERROR_POS )
|
||
79 | 249 | up20180642 | #define UART_GET_TRANSMITTER_EMPTY(n) (((n)&UART_TRANSMITTER_EMPTY )>>UART_TRANSMITTER_EMPTY_POS )
|
80 | |||
81 | 252 | up20180642 | static void uart_parse_config(uart_config *config){ |
82 | /// LCR
|
||
83 | config->bits_per_char = UART_GET_BITS_PER_CHAR (config->lcr); |
||
84 | config->stop_bits = UART_GET_STOP_BITS (config->lcr); |
||
85 | config->parity = UART_GET_PARITY (config->lcr); if((config->parity & BIT(0)) == 0) config->parity = uart_parity_none; |
||
86 | config->break_control = UART_GET_BREAK_CONTROL (config->lcr); |
||
87 | config->dlab = UART_GET_DLAB (config->lcr); |
||
88 | /// IER
|
||
89 | config->received_data_int = UART_GET_INT_EN_RX (config->ier); |
||
90 | config->transmitter_empty_int = UART_GET_INT_EN_TX (config->ier); |
||
91 | config->receiver_line_stat_int = UART_GET_INT_EN_RECEIVER_LINE_STAT(config->ier); |
||
92 | config->modem_stat_int = UART_GET_INT_EN_MODEM_STAT (config->ier); |
||
93 | /// DIV LATCH
|
||
94 | config->divisor_latch = UART_GET_DIV_LATCH(config->dlm, config->dll); |
||
95 | } |
||
96 | |||
97 | static int uart_get_lcr(int base_addr, uint8_t *p){ |
||
98 | return util_sys_inb(base_addr+UART_LCR, p);
|
||
99 | } |
||
100 | static int uart_set_lcr(int base_addr, uint8_t config){ |
||
101 | if(sys_outb(base_addr+UART_LCR, config)) return WRITE_ERROR; |
||
102 | return SUCCESS;
|
||
103 | } |
||
104 | static int uart_get_lsr(int base_addr, uint8_t *p){ |
||
105 | return util_sys_inb(base_addr+UART_LSR, p);
|
||
106 | } |
||
107 | |||
108 | static int uart_enable_divisor_latch(int base_addr){ |
||
109 | int ret = SUCCESS;
|
||
110 | uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret; |
||
111 | return uart_set_lcr(base_addr, conf | UART_DLAB);
|
||
112 | } |
||
113 | static int uart_disable_divisor_latch(int base_addr){ |
||
114 | int ret = SUCCESS;
|
||
115 | uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret; |
||
116 | return uart_set_lcr(base_addr, conf & (~UART_DLAB));
|
||
117 | } |
||
118 | |||
119 | static int uart_get_ier(int base_addr, uint8_t *p){ |
||
120 | int ret;
|
||
121 | if((ret = uart_disable_divisor_latch(base_addr))) return ret; |
||
122 | return util_sys_inb(base_addr+UART_IER, p);
|
||
123 | } |
||
124 | static int uart_set_ier(int base_addr, uint8_t n){ |
||
125 | int ret;
|
||
126 | if((ret = uart_disable_divisor_latch(base_addr))) return ret; |
||
127 | if(sys_outb(base_addr+UART_IER, n)) return WRITE_ERROR; |
||
128 | return SUCCESS;
|
||
129 | } |
||
130 | |||
131 | 235 | up20180642 | int uart_get_config(int base_addr, uart_config *config){ |
132 | int ret = SUCCESS;
|
||
133 | |||
134 | config->base_addr = base_addr; |
||
135 | |||
136 | 252 | up20180642 | if((ret = uart_get_lcr(base_addr, &config->lcr))) return ret; |
137 | 235 | up20180642 | |
138 | 252 | up20180642 | if((ret = uart_get_ier(base_addr, &config->ier))) return ret; |
139 | 242 | up20180642 | |
140 | if((ret = uart_enable_divisor_latch (base_addr))) return ret; |
||
141 | 235 | up20180642 | if((ret = util_sys_inb(base_addr+UART_DLL, &config->dll ))) return ret; |
142 | if((ret = util_sys_inb(base_addr+UART_DLM, &config->dlm ))) return ret; |
||
143 | 242 | up20180642 | if((ret = uart_disable_divisor_latch(base_addr))) return ret; |
144 | 235 | up20180642 | |
145 | uart_parse_config(config); |
||
146 | return ret;
|
||
147 | } |
||
148 | void uart_print_config(uart_config config){
|
||
149 | 249 | up20180642 | |
150 | printf("%s configuration:\n", (config.base_addr == COM1_ADDR ? "COM1" : "COM2")); |
||
151 | printf("\tLCR = 0x%X: %d bits per char\t %d stop bits\t", config.lcr, config.bits_per_char, config.stop_bits);
|
||
152 | if((config.parity&BIT(0)) == 0) printf("NO parity\n"); |
||
153 | 235 | up20180642 | else switch(config.parity){ |
154 | 249 | up20180642 | case uart_parity_odd : printf("ODD parity\n" ); break; |
155 | case uart_parity_even: printf("EVEN parity\n" ); break; |
||
156 | 235 | up20180642 | case uart_parity_par1: printf("parity bit is 1\n"); break; |
157 | case uart_parity_par0: printf("parity bit is 0\n"); break; |
||
158 | default : printf("invalid\n" ); break; |
||
159 | } |
||
160 | 249 | up20180642 | printf("\tDLM = 0x%02X DLL=0x%02X: bitrate = %d bps\n", config.dlm, config.dll, UART_BITRATE/config.divisor_latch);
|
161 | printf("\tIER = 0x%02X: Rx interrupts: %s\tTx interrupts: %s\n", config.ier,
|
||
162 | (config.received_data_int ? "ENABLED":"DISABLED"), |
||
163 | (config.transmitter_empty_int ? "ENABLED":"DISABLED")); |
||
164 | 235 | up20180642 | } |
165 | |||
166 | int uart_set_bits_per_character(int base_addr, uint8_t bits_per_char){ |
||
167 | if(bits_per_char < 5 || bits_per_char > 8) return INVALID_ARG; |
||
168 | int ret = SUCCESS;
|
||
169 | bits_per_char = (bits_per_char-5)&0x3; |
||
170 | 252 | up20180642 | uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret; |
171 | 235 | up20180642 | conf = (conf & (~UART_BITS_PER_CHAR)) | bits_per_char; |
172 | 252 | up20180642 | return uart_set_lcr(base_addr, conf);
|
173 | 235 | up20180642 | } |
174 | int uart_set_stop_bits(int base_addr, uint8_t stop){ |
||
175 | if(stop != 1 && stop != 2) return INVALID_ARG; |
||
176 | int ret = SUCCESS;
|
||
177 | stop -= 1;
|
||
178 | stop = (stop&1)<<2; |
||
179 | 252 | up20180642 | uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret; |
180 | 235 | up20180642 | conf = (conf & (~UART_STOP_BITS)) | stop; |
181 | 252 | up20180642 | return uart_set_lcr(base_addr, conf);
|
182 | 235 | up20180642 | } |
183 | int uart_set_parity(int base_addr, uart_parity par){ |
||
184 | int ret = SUCCESS;
|
||
185 | uint8_t parity = par << 3;
|
||
186 | 252 | up20180642 | uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret; |
187 | 235 | up20180642 | conf = (conf & (~UART_PARITY)) | parity; |
188 | 252 | up20180642 | return uart_set_lcr(base_addr, conf);
|
189 | 235 | up20180642 | } |
190 | 241 | up20180642 | int uart_set_bit_rate(int base_addr, float bit_rate){ |
191 | 235 | up20180642 | int ret = SUCCESS;
|
192 | uint16_t latch = UART_BITRATE/bit_rate; |
||
193 | 241 | up20180642 | uint8_t dll = UART_GET_DLL(latch); |
194 | uint8_t dlm = UART_GET_DLM(latch); |
||
195 | 235 | up20180642 | if((ret = uart_enable_divisor_latch(base_addr))) return ret; |
196 | if(sys_outb(base_addr+UART_DLL, dll)) return WRITE_ERROR; |
||
197 | if(sys_outb(base_addr+UART_DLM, dlm)) return WRITE_ERROR; |
||
198 | 249 | up20180642 | if((ret = uart_disable_divisor_latch(base_addr))) return ret; |
199 | 235 | up20180642 | return SUCCESS;
|
200 | } |
||
201 | 249 | up20180642 | |
202 | 252 | up20180642 | static int uart_get_char(int base_addr, uint8_t *p){ |
203 | 249 | up20180642 | int ret;
|
204 | if((ret = uart_disable_divisor_latch(base_addr))) return ret; |
||
205 | return util_sys_inb(base_addr+UART_RBR, p);
|
||
206 | } |
||
207 | 252 | up20180642 | static int uart_send_char(int base_addr, uint8_t c){ |
208 | 249 | up20180642 | int ret;
|
209 | if((ret = uart_disable_divisor_latch(base_addr))) return ret; |
||
210 | 252 | up20180642 | if(sys_outb(base_addr+UART_THR, c)) return WRITE_ERROR; |
211 | 249 | up20180642 | return SUCCESS;
|
212 | } |
||
213 | 252 | up20180642 | static int uart_receiver_ready(int base_addr){ |
214 | 249 | up20180642 | uint8_t lsr; |
215 | if(uart_get_lsr(base_addr, &lsr)) return false; |
||
216 | return UART_GET_RECEIVER_READY(lsr);
|
||
217 | } |
||
218 | 252 | up20180642 | static int uart_transmitter_empty(int base_addr){ |
219 | 249 | up20180642 | uint8_t lsr; |
220 | if(uart_get_lsr(base_addr, &lsr)) return false; |
||
221 | return UART_GET_TRANSMITTER_EMPTY(lsr);
|
||
222 | } |
||
223 | 252 | up20180642 | |
224 | int uart_enable_int_rx(int base_addr){ |
||
225 | int ret;
|
||
226 | uint8_t ier; |
||
227 | if((ret = uart_get_ier(base_addr, &ier))) return ret; |
||
228 | ier |= UART_INT_EN_RX; |
||
229 | return uart_set_ier(base_addr, ier);
|
||
230 | } |
||
231 | int uart_disable_int_rx(int base_addr){ |
||
232 | int ret;
|
||
233 | uint8_t ier; |
||
234 | if((ret = uart_get_ier(base_addr, &ier))) return ret; |
||
235 | ier &= ~UART_INT_EN_RX; |
||
236 | return uart_set_ier(base_addr, ier);
|
||
237 | } |
||
238 | int uart_enable_int_tx(int base_addr){ |
||
239 | int ret;
|
||
240 | uint8_t ier; |
||
241 | if((ret = uart_get_ier(base_addr, &ier))) return ret; |
||
242 | ier |= UART_INT_EN_TX; |
||
243 | return uart_set_ier(base_addr, ier);
|
||
244 | } |
||
245 | int uart_disable_int_tx(int base_addr){ |
||
246 | int ret;
|
||
247 | uint8_t ier; |
||
248 | if((ret = uart_get_ier(base_addr, &ier))) return ret; |
||
249 | ier &= ~UART_INT_EN_TX; |
||
250 | return uart_set_ier(base_addr, ier);
|
||
251 | } |
||
252 | |||
253 | 261 | up20180642 | static int uart_has_communication_error(int base_addr){ |
254 | 249 | up20180642 | int ret;
|
255 | 261 | up20180642 | uint8_t lsr; |
256 | if((ret = uart_get_lsr(base_addr, &lsr))) return 1; |
||
257 | lsr &= (UART_OVERRUN_ERROR & |
||
258 | UART_PARITY_ERROR & |
||
259 | UART_FRAMING_ERROR); |
||
260 | return (lsr ? 1 : 0); |
||
261 | } |
||
262 | |||
263 | #include "nctp.h" |
||
264 | |||
265 | #define NCTP_START 0x80 |
||
266 | #define NCTP_END 0xFF |
||
267 | #define NCTP_TRIES 3 |
||
268 | #define NCTP_OK 0xFF |
||
269 | #define NCTP_NOK 0x00 |
||
270 | #define NCTP_MAX_SIZE 1024 //in bytes |
||
271 | |||
272 | int nctp_send_char_poll(int base_addr, uint8_t c){ |
||
273 | for(int i = 0; i < NCTP_TRIES; ++i) |
||
274 | if(uart_transmitter_empty(base_addr))
|
||
275 | return uart_send_char(base_addr, c);
|
||
276 | return TIMEOUT_ERROR;
|
||
277 | } |
||
278 | int nctp_get_char_poll (int base_addr, uint8_t *p){ |
||
279 | for(int i = 0; i < NCTP_TRIES; ++i) |
||
280 | if(uart_receiver_ready(base_addr))
|
||
281 | return uart_get_char(base_addr, p);
|
||
282 | return TIMEOUT_ERROR;
|
||
283 | } |
||
284 | |||
285 | int nctp_expect_ok(int base_addr){ |
||
286 | int ret;
|
||
287 | uint8_t ok; |
||
288 | if((ret = nctp_get_char_poll(base_addr, &ok))) return ret; |
||
289 | int cnt = 0; |
||
290 | while(ok){
|
||
291 | cnt += ok&1;
|
||
292 | ok >>= 1;
|
||
293 | } |
||
294 | if(cnt > 4) return SUCCESS; |
||
295 | else return NOK; |
||
296 | } |
||
297 | |||
298 | int nctp_send_char_try(int base_addr, uint8_t c){ |
||
299 | int ret;
|
||
300 | for(size_t k = 0; k < NCTP_TRIES; ++k){ |
||
301 | if((ret = nctp_send_char_poll(base_addr, c))) return ret; |
||
302 | if(nctp_expect_ok(base_addr) == SUCCESS) return SUCCESS; |
||
303 | } |
||
304 | return TRANS_FAILED;
|
||
305 | } |
||
306 | int nctp_get_char_try (int base_addr, uint8_t *p){ |
||
307 | int ret;
|
||
308 | for(size_t k = 0; k < NCTP_TRIES; ++k){ |
||
309 | if((ret = nctp_get_char_poll (base_addr, p))) return ret; |
||
310 | if(!uart_has_communication_error(base_addr))
|
||
311 | return nctp_send_char_try(base_addr, NCTP_OK ); //If it does not have any errors |
||
312 | } |
||
313 | if((ret = nctp_send_char_poll(base_addr, NCTP_NOK))) return ret; |
||
314 | return TRANS_FAILED;
|
||
315 | } |
||
316 | |||
317 | int nctp_send(int port, size_t num, uint8_t* ptr[], size_t sz[]){ |
||
318 | { |
||
319 | int cnt = 0; |
||
320 | for(size_t i = 0; i < num; ++i){ |
||
321 | cnt += sz[i]; |
||
322 | if(cnt > NCTP_MAX_SIZE) return TRANS_REFUSED; |
||
323 | } |
||
324 | } |
||
325 | |||
326 | int base_addr;{
|
||
327 | switch(port){
|
||
328 | case 1: base_addr = COM1_ADDR; break; |
||
329 | case 2: base_addr = COM2_ADDR; break; |
||
330 | default: return INVALID_ARG; |
||
331 | } |
||
332 | } |
||
333 | |||
334 | int ret;
|
||
335 | |||
336 | if((ret = uart_disable_int_rx(base_addr))) return ret; |
||
337 | if((ret = uart_disable_int_tx(base_addr))) return ret; |
||
338 | |||
339 | if((ret = nctp_send_char_try(base_addr, NCTP_START))) return ret; |
||
340 | for(size_t i = 0; i < num; ++i){ |
||
341 | uint8_t *p = ptr[i]; size_t s = sz[i]; |
||
342 | for(size_t j = 0; j < s; ++j, ++p) |
||
343 | if((ret = nctp_send_char_try(base_addr, *p)))
|
||
344 | return ret;
|
||
345 | } |
||
346 | if((ret = nctp_send_char_try(base_addr, NCTP_END))) return ret; |
||
347 | |||
348 | 249 | up20180642 | return SUCCESS;
|
349 | } |
||
350 | 261 | up20180642 | int ntcp_get(int port, uint8_t *dest){ |
351 | int base_addr;{
|
||
352 | switch(port){
|
||
353 | case 1: base_addr = COM1_ADDR; break; |
||
354 | case 2: base_addr = COM2_ADDR; break; |
||
355 | default: return INVALID_ARG; |
||
356 | } |
||
357 | } |
||
358 | |||
359 | 249 | up20180642 | int ret;
|
360 | 261 | up20180642 | free(dest); |
361 | dest = malloc(NCTP_MAX_SIZE*sizeof(uint8_t)); size_t i = 0; |
||
362 | if(dest == NULL) return NULL_PTR; |
||
363 | uint8_t c; |
||
364 | if((ret = nctp_get_char_try (base_addr, &c ))) return ret; |
||
365 | while(true){ |
||
366 | if(i >= NCTP_MAX_SIZE) return TRANS_REFUSED; |
||
367 | if((ret = nctp_get_char_try (base_addr, &c))) return ret; |
||
368 | if(c == NCTP_END) break; |
||
369 | else dest[i] = c;
|
||
370 | ++i; |
||
371 | } |
||
372 | 249 | up20180642 | return SUCCESS;
|
373 | } |