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