Project

General

Profile

Statistics
| Revision:

root / proj / src / libs / uart / src / uart.c @ 385

History | View | Annotate | Download (18 KB)

1
#include <lcom/lcf.h>
2

    
3
#include "uart.h"
4

    
5
#include "queue.h"
6
#include "errors.h"
7

    
8
#define UART_BITRATE                            115200
9
#define UART_WAIT                               20 //microseconds
10

    
11
#define UART_RBR                                0
12
#define UART_THR                                0
13
#define UART_IER                                1
14
#define UART_IIR                                2
15
#define UART_FCR                                2
16
#define UART_LCR                                3
17
#define UART_MCR                                4
18
#define UART_LSR                                5
19
#define UART_MSR                                6
20
#define UART_SR                                 7
21

    
22
#define UART_DLL                                0
23
#define UART_DLM                                1
24

    
25
/// LCR
26
#define UART_BITS_PER_CHAR_POS                  0
27
#define UART_STOP_BITS_POS                      2
28
#define UART_PARITY_POS                         3
29
#define UART_BREAK_CONTROL_POS                  6
30
#define UART_DLAB_POS                           7
31

    
32
#define UART_BITS_PER_CHAR                      (BIT(0) | BIT(1))
33
#define UART_STOP_BITS                          (BIT(2))
34
#define UART_PARITY                             (BIT(3) | BIT(4) | BIT(5))
35
#define UART_BREAK_CONTROL                      (BIT(6))
36
#define UART_DLAB                               (BIT(7))
37

    
38
#define UART_GET_BITS_PER_CHAR(n)               (((n)&UART_BITS_PER_CHAR) + 5)
39
#define UART_GET_STOP_BITS(n)                   (((n)&UART_STOP_BITS)? 2 : 1)
40
#define UART_GET_PARITY(n)                      (((n)&UART_PARITY       )>>UART_PARITY_POS       )
41
#define UART_GET_BREAK_CONTROL(n)               (((n)&UART_BREAK_CONTROL)>>UART_BREAK_CONTROL_POS)
42
#define UART_GET_DLAB(n)                        (((n)&UART_DLAB         )>>UART_DLAB_POS         )
43
#define UART_GET_DIV_LATCH(m,l)                 ((m)<<8 | (l))
44
#define UART_GET_DLL(n)                         ((n)&0xFF)
45
#define UART_GET_DLM(n)                         (((n)>>8)&0xFF)
46

    
47
/// IER
48
#define UART_INT_EN_RX_POS                      0
49
#define UART_INT_EN_TX_POS                      1
50
#define UART_INT_EN_RECEIVER_LINE_STAT_POS      2
51
#define UART_INT_EN_MODEM_STAT_POS              3
52

    
53
#define UART_INT_EN_RX                          (BIT(0))
54
#define UART_INT_EN_TX                          (BIT(1))
55
#define UART_INT_EN_RECEIVER_LINE_STAT          (BIT(2))
56
#define UART_INT_EN_MODEM_STAT                  (BIT(3))
57

    
58
#define UART_GET_INT_EN_RX(n)                   (((n)&UART_INT_EN_RX                )>>UART_INT_EN_RX_POS                )
59
#define UART_GET_INT_EN_TX(n)                   (((n)&UART_INT_EN_TX                )>>UART_INT_EN_TX_POS                )
60
#define UART_GET_INT_EN_RECEIVER_LINE_STAT(n)   (((n)&UART_INT_EN_RECEIVER_LINE_STAT)>>UART_INT_EN_RECEIVER_LINE_STAT_POS)
61
#define UART_GET_INT_EN_MODEM_STAT(n)           (((n)&UART_INT_EN_MODEM_STAT        )>>UART_INT_EN_MODEM_STAT_POS        )
62

    
63
/// LSR
64
#define UART_RECEIVER_READY_POS                 0
65
#define UART_OVERRUN_ERROR_POS                  1
66
#define UART_PARITY_ERROR_POS                   2
67
#define UART_FRAMING_ERROR_POS                  3
68
#define UART_TRANSMITTER_EMPTY_POS              5
69

    
70
#define UART_RECEIVER_READY                     (BIT(0))
71
#define UART_OVERRUN_ERROR                      (BIT(1))
72
#define UART_PARITY_ERROR                       (BIT(2))
73
#define UART_FRAMING_ERROR                      (BIT(3))
74
#define UART_TRANSMITTER_EMPTY                  (BIT(5))
75

    
76
#define UART_GET_RECEIVER_READY(n)              (((n)&UART_RECEIVER_READY           )>>UART_RECEIVER_READY_POS           )
77
#define UART_GET_OVERRUN_ERROR                  (((n)&UART_OVERRUN_ERROR            )>>UART_OVERRUN_ERROR_POS            )
78
#define UART_GET_PARITY_ERROR                   (((n)&UART_PARITY_ERROR             )>>UART_PARITY_ERROR_POS             )
79
#define UART_GET_FRAMING_ERROR                  (((n)&UART_FRAMING_ERROR            )>>UART_FRAMING_ERROR_POS            )
80
#define UART_GET_TRANSMITTER_EMPTY(n)           (((n)&UART_TRANSMITTER_EMPTY        )>>UART_TRANSMITTER_EMPTY_POS        )
81

    
82
/// IIR
83
#define UART_INT_PEND_POS                       1
84
#define UART_INT_PEND                           (BIT(3)|BIT(2)|BIT(1))
85

    
86
/// FCR
87
#define UART_EN_FIFOS_POS                       0
88
#define UART_CLEAR_RCVR_POS                     1
89
#define UART_CLEAR_XMIT_POS                     2
90
#define UART_FIFO_TRIGGER_POS                   6
91

    
92
#define UART_EN_FIFOS                           (BIT(0))
93
#define UART_CLEAR_RCVR                         (BIT(1))
94
#define UART_CLEAR_XMIT                         (BIT(2))
95
#define UART_FIFO_TRIGGER                       (BIT(6)|BIT(7))
96

    
97
#define UART_TRIGGER_LEVEL01                    (0<<UART_FIFO_TRIGGER_POS)
98
#define UART_TRIGGER_LEVEL04                    (1<<UART_FIFO_TRIGGER_POS)
99
#define UART_TRIGGER_LEVEL08                    (2<<UART_FIFO_TRIGGER_POS)
100
#define UART_TRIGGER_LEVEL14                    (3<<UART_FIFO_TRIGGER_POS)
101

    
102
#define UART_GET_IF_INT_PEND(n)                 (!((n)&1))
103
typedef enum {
104
    uart_int_receiver_line_stat = (         BIT(1) | BIT(0)),
105
    uart_int_rx                 = (         BIT(1)         ),
106
    uart_int_char_timeout_fifo  = (BIT(2) | BIT(1)         ),
107
    uart_int_tx                 = (                  BIT(0)),
108
    uart_int_modem_stat         = (0)
109
} uart_int_code;
110
#define UART_GET_INT_PEND(n)                    ((uart_int_code)(((n)&UART_INT_PEND)>>UART_INT_PEND_POS))
111

    
112
int (subscribe_uart_interrupt)(uint8_t interrupt_bit, int *interrupt_id) {
113
    if (interrupt_id == NULL) return 1;
114
    *interrupt_id = interrupt_bit;
115
    return (sys_irqsetpolicy(COM1_IRQ, IRQ_REENABLE | IRQ_EXCLUSIVE, interrupt_id));
116
}
117

    
118
static void uart_parse_config(uart_config *config){
119
    /// LCR
120
    config->bits_per_char          = UART_GET_BITS_PER_CHAR     (config->lcr);
121
    config->stop_bits              = UART_GET_STOP_BITS         (config->lcr);
122
    config->parity                 = UART_GET_PARITY            (config->lcr); if((config->parity & BIT(0)) == 0) config->parity = uart_parity_none;
123
    config->break_control          = UART_GET_BREAK_CONTROL     (config->lcr);
124
    config->dlab                   = UART_GET_DLAB              (config->lcr);
125
    /// IER
126
    config->received_data_int      = UART_GET_INT_EN_RX                (config->ier);
127
    config->transmitter_empty_int  = UART_GET_INT_EN_TX                (config->ier);
128
    config->receiver_line_stat_int = UART_GET_INT_EN_RECEIVER_LINE_STAT(config->ier);
129
    config->modem_stat_int         = UART_GET_INT_EN_MODEM_STAT        (config->ier);
130
    /// DIV LATCH
131
    config->divisor_latch          = (uint16_t)UART_GET_DIV_LATCH(config->dlm, config->dll);
132
}
133

    
134
static int uart_get_lcr(int base_addr, uint8_t *p){
135
    return util_sys_inb(base_addr+UART_LCR, p);
136
}
137
static int uart_set_lcr(int base_addr, uint8_t config){
138
    if(sys_outb(base_addr+UART_LCR, config)) return WRITE_ERROR;
139
    return SUCCESS;
140
}
141
static int uart_get_lsr(int base_addr, uint8_t *p){
142
    return util_sys_inb(base_addr+UART_LSR, p);
143
}
144
static int uart_get_iir(int base_addr, uint8_t *p){
145
    return util_sys_inb(base_addr+UART_IIR, p);
146
}
147

    
148
static int uart_enable_divisor_latch(int base_addr){
149
    int ret = SUCCESS;
150
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
151
    return uart_set_lcr(base_addr, conf | UART_DLAB);
152
}
153
static int uart_disable_divisor_latch(int base_addr){
154
    int ret = SUCCESS;
155
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
156
    return uart_set_lcr(base_addr, conf & (~UART_DLAB));
157
}
158

    
159
static int uart_get_ier(int base_addr, uint8_t *p){
160
    int ret;
161
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
162
    return util_sys_inb(base_addr+UART_IER, p);
163
}
164
static int uart_set_ier(int base_addr, uint8_t n){
165
    int ret;
166
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
167
    if(sys_outb(base_addr+UART_IER, n)) return WRITE_ERROR;
168
    return SUCCESS;
169
}
170

    
171
int uart_get_config(int base_addr, uart_config *config){
172
    int ret = SUCCESS;
173

    
174
    config->base_addr = base_addr;
175

    
176
    if((ret = uart_get_lcr(base_addr, &config->lcr))) return ret;
177

    
178
    if((ret = uart_get_ier(base_addr, &config->ier))) return ret;
179

    
180
    if((ret = uart_enable_divisor_latch (base_addr))) return ret;
181
    if((ret = util_sys_inb(base_addr+UART_DLL, &config->dll   ))) return ret;
182
    if((ret = util_sys_inb(base_addr+UART_DLM, &config->dlm   ))) return ret;
183
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
184

    
185
    uart_parse_config(config);
186
    return ret;
187
}
188
void uart_print_config(uart_config config){
189

    
190
    printf("%s configuration:\n", (config.base_addr == COM1_ADDR ? "COM1" : "COM2"));
191
    printf("\tLCR = 0x%X: %d bits per char\t %d stop bits\t", config.lcr, config.bits_per_char, config.stop_bits);
192
    if((config.parity&BIT(0)) == 0) printf("NO parity\n");
193
    else switch(config.parity){
194
        case uart_parity_none: printf("NO parity\n"      ); break;
195
        case uart_parity_odd : printf("ODD parity\n"     ); break;
196
        case uart_parity_even: printf("EVEN parity\n"    ); break;
197
        case uart_parity_par1: printf("parity bit is 1\n"); break;
198
        case uart_parity_par0: printf("parity bit is 0\n"); break;
199
        //default              : printf("invalid\n"        ); break;
200
    }
201
    printf("\tDLM = 0x%02X DLL=0x%02X: bitrate = %d bps\n", config.dlm, config.dll, UART_BITRATE/config.divisor_latch);
202
    printf("\tIER = 0x%02X: Rx interrupts: %s\tTx interrupts: %s\n", config.ier,
203
        (config.received_data_int     ? "ENABLED":"DISABLED"),
204
        (config.transmitter_empty_int ? "ENABLED":"DISABLED"));
205
}
206

    
207
int uart_set_bits_per_character(int base_addr, uint8_t bits_per_char){
208
    if(bits_per_char < 5 || bits_per_char > 8) return INVALID_ARG;
209
    int ret = SUCCESS;
210
    bits_per_char = (bits_per_char-5)&0x3;
211
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
212
    conf = (conf & (~UART_BITS_PER_CHAR)) | bits_per_char;
213
    return uart_set_lcr(base_addr, conf);
214
}
215
int uart_set_stop_bits(int base_addr, uint8_t stop){
216
    if(stop != 1 && stop != 2) return INVALID_ARG;
217
    int ret = SUCCESS;
218
    stop -= 1;
219
    stop = (uint8_t)((stop&1)<<2);
220
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
221
    conf = (conf & (~UART_STOP_BITS)) | stop;
222
    return uart_set_lcr(base_addr, conf);
223
}
224
int uart_set_parity(int base_addr, uart_parity par){
225
    int ret = SUCCESS;
226
    uint8_t parity = (uint8_t)(par << 3);
227
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
228
    conf = (conf & (~UART_PARITY)) | parity;
229
    return uart_set_lcr(base_addr, conf);
230
}
231
int uart_set_bit_rate(int base_addr, uint32_t bit_rate){
232
    int ret = SUCCESS;
233
    uint16_t latch = (uint16_t)(UART_BITRATE/bit_rate);
234
    uint8_t dll = UART_GET_DLL(latch);
235
    uint8_t dlm = UART_GET_DLM(latch);
236
    if((ret = uart_enable_divisor_latch(base_addr))) return ret;
237
    if(sys_outb(base_addr+UART_DLL, dll)) return WRITE_ERROR;
238
    if(sys_outb(base_addr+UART_DLM, dlm)) return WRITE_ERROR;
239
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
240
    return SUCCESS;
241
}
242

    
243
static int uart_get_char(int base_addr, uint8_t *p){
244
    int ret;
245
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
246
    return util_sys_inb(base_addr+UART_RBR, p);
247
}
248
static int uart_send_char(int base_addr, uint8_t c){
249
    int ret;
250
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
251
    if(sys_outb(base_addr+UART_THR, c)) return WRITE_ERROR;
252
    return SUCCESS;
253
}
254
static int uart_receiver_ready(int base_addr){
255
    uint8_t lsr;
256
    if(uart_get_lsr(base_addr, &lsr)) return false;
257
    return UART_GET_RECEIVER_READY(lsr);
258
}
259
static int uart_transmitter_empty(int base_addr){
260
    uint8_t lsr;
261
    if(uart_get_lsr(base_addr, &lsr)) return false;
262
    return UART_GET_TRANSMITTER_EMPTY(lsr);
263
}
264

    
265
int uart_enable_int_rx(int base_addr){
266
    int ret;
267
    uint8_t ier;
268
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
269
    ier |= UART_INT_EN_RX;
270
    return uart_set_ier(base_addr, ier);
271
}
272
int uart_disable_int_rx(int base_addr){
273
    int ret;
274
    uint8_t ier;
275
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
276
    ier &= ~UART_INT_EN_RX;
277
    return uart_set_ier(base_addr, ier);
278
}
279
int uart_enable_int_tx(int base_addr){
280
    int ret;
281
    uint8_t ier;
282
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
283
    ier |= UART_INT_EN_TX;
284
    return uart_set_ier(base_addr, ier);
285
}
286
int uart_disable_int_tx(int base_addr){
287
    int ret;
288
    uint8_t ier;
289
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
290
    ier &= ~UART_INT_EN_TX;
291
    return uart_set_ier(base_addr, ier);
292
}
293

    
294
static int uart_set_fcr(int base_addr, uint8_t n){
295
    if(sys_outb(base_addr+UART_FCR, n)) return WRITE_ERROR;
296
    return SUCCESS;
297
}
298
static int uart_enable_fifos(int base_addr, uint8_t trigger_lvl){
299
    uint8_t fcr = UART_EN_FIFOS | UART_CLEAR_RCVR | UART_CLEAR_XMIT;
300
    switch(trigger_lvl){
301
        case  1: fcr |= UART_TRIGGER_LEVEL01; break;
302
        case  4: fcr |= UART_TRIGGER_LEVEL04; break;
303
        case  8: fcr |= UART_TRIGGER_LEVEL08; break;
304
        case 14: fcr |= UART_TRIGGER_LEVEL14; break;
305
        default: return INVALID_ARG;
306
    }
307
    return uart_set_fcr(base_addr, fcr);
308
}
309
static int uart_disable_fifos(int base_addr){
310
    return uart_set_fcr(base_addr, UART_CLEAR_RCVR | UART_CLEAR_XMIT);
311
}
312

    
313
/// NCTP
314

    
315
//#define NCTP_START      0x80
316
//#define NCTP_END        0xFF
317
#define NCTP_OK         0xFF
318
#define NCTP_NOK        0x00
319
#define NCTP_ALIGN      4
320
#define NCTP_FILLER     0x4E
321

    
322
static queue_t *out = NULL;
323
static queue_t *in  = NULL;
324
static void (*process)(const uint8_t*, const size_t) = NULL;
325

    
326
int nctp_init(void){
327
    out = queue_ctor(); if(out == NULL) return NULL_PTR;
328
    in  = queue_ctor(); if(in  == NULL) return NULL_PTR;
329
    //return SUCCESS;
330
    return uart_enable_fifos(COM1_ADDR, NCTP_ALIGN);
331
}
332
int nctp_dump(void){
333
    int ret;
334
    if((ret = nctp_free())) return ret;
335
    return nctp_init();
336
}
337
int nctp_set_processor(void (*proc_func)(const uint8_t*, const size_t)){
338
    process = proc_func;
339
    return SUCCESS;
340
}
341
int nctp_free(void){
342
    int ret = SUCCESS; int r;
343
    while(!queue_empty(out)){
344
        free(queue_top(out));
345
        queue_pop(out);
346
    } queue_dtor(out);
347
    while(!queue_empty(in)){
348
        free(queue_top(in));
349
        queue_pop(in);
350
    } queue_dtor(in);
351
    if((r = uart_disable_fifos(COM1_ADDR))) ret = r;
352
    return ret;
353
}
354

    
355
int nctp_send(size_t num, const uint8_t *const *ptr, const size_t *const sz){
356
    int ret;
357
    uint16_t sz_total = 0;{
358
        for(size_t i = 0; i < num; ++i)
359
            sz_total += sz[i];
360
    }
361
    uint8_t *tmp;
362
    tmp = malloc(sizeof(uint8_t)); *tmp = *((uint8_t*)(&sz_total)+0); queue_push(out, tmp);
363
    tmp = malloc(sizeof(uint8_t)); *tmp = *((uint8_t*)(&sz_total)+1); queue_push(out, tmp);
364
    for(size_t i = 0; i < num; ++i){
365
        const uint8_t *p = ptr[i]; const size_t s = sz[i];
366
        for(size_t j = 0; j < s; ++j, ++p){
367
            tmp = malloc(sizeof(uint8_t)); *tmp = *p; queue_push(out, tmp);
368
        }
369
    }
370
    uint32_t total_message = sz_total+2;
371
    uint32_t num_fillers = (NCTP_ALIGN - total_message%NCTP_ALIGN)%NCTP_ALIGN;
372
    for(size_t i = 0; i < num_fillers; ++i){
373
        tmp = malloc(sizeof(uint8_t)); *tmp = NCTP_FILLER; queue_push(out, tmp);
374
    }
375

    
376
    if(uart_transmitter_empty(COM1_ADDR)){
377
        if((ret = uart_send_char(COM1_ADDR, *(uint8_t*)queue_top(out)))) return ret;
378
        queue_pop(out);
379
    }
380
    return SUCCESS;
381
}
382
static int nctp_transmit(void){
383
    while(!queue_empty(out) && uart_transmitter_empty(COM1_ADDR)){
384
        int ret = uart_send_char(COM1_ADDR, *(uint8_t*)queue_top(out));
385
        queue_pop(out);
386
        if(ret) return ret;
387
        //return ret;
388
    }/*else*/ return SUCCESS;
389
}
390

    
391
static void nctp_process_received(){
392
    uint16_t sz = 0;{
393
        uint8_t sz0 = *(uint8_t*)queue_top(in); free(queue_top(in)); queue_pop(in);
394
        uint8_t sz1 = *(uint8_t*)queue_top(in); free(queue_top(in)); queue_pop(in);
395
        *((uint8_t*)(&sz)+0) = sz0;
396
        *((uint8_t*)(&sz)+1) = sz1;
397
    }
398
    uint8_t *p = malloc(sz*sizeof(uint8_t));
399
    for(uint16_t i = 0; i < sz; ++i){
400
        p[i] = *(uint8_t*)queue_top(in);
401
        free(queue_top(in)); queue_pop(in);
402
    }
403
    if(process != NULL) process(p, sz);
404
    free(p);
405
}
406

    
407
static int num_bytes_to_receive = 0;
408
static uint16_t szbytes_to_receive = 0;
409
static uint8_t size0 = 0;
410
static uint8_t received_so_far = 0;
411
static int nctp_receive(void){
412
    int ret;
413
    uint8_t c;
414
    int counter_to_process = 0;
415

    
416
    while(uart_receiver_ready(COM1_ADDR)){
417
        if((ret = uart_get_char(COM1_ADDR, &c))) return ret;
418
        uint8_t *tmp = malloc(sizeof(uint8_t)); *tmp = c;
419

    
420
        if       (szbytes_to_receive){ // gotta receive 2nd size byte and update num_bytes
421
            *((uint8_t*)(&num_bytes_to_receive)+0) = size0;
422
            *((uint8_t*)(&num_bytes_to_receive)+1) = c;
423
            szbytes_to_receive = 0;
424
        } else if(num_bytes_to_receive > 0){
425
            /* Now I know there are no more size bytes to receive.
426
             * If there are normal bytes to receive, do this*/
427
             --num_bytes_to_receive;
428
             if(num_bytes_to_receive == 0) ++counter_to_process;
429
        } else {
430
            /* Now I know I am not expecting anything.
431
             * The fact I received something means it is a filler, or the 1st size byte.
432
             * If received_so_far == 0, then it is not a filler, but rather the 1st size byte. */
433
             if(received_so_far == 0){
434
                 size0 = c;
435
                 szbytes_to_receive = 1;
436
             }else{
437
                 received_so_far = (received_so_far+1)%NCTP_ALIGN;
438
                 continue;
439
             }
440
        }
441
        queue_push(in, tmp);
442
        received_so_far = (received_so_far+1)%NCTP_ALIGN;
443
    }
444
    while(counter_to_process-- > 0) nctp_process_received();
445
    return SUCCESS;
446
}
447

    
448
static int nctp_ih_err = SUCCESS;
449
int (nctp_get_ih_error)(void){ return nctp_ih_err; }
450
void nctp_ih(void){
451
    uint8_t iir;
452
    if((nctp_ih_err = uart_get_iir(COM1_ADDR, &iir))) return;
453
    if(UART_GET_IF_INT_PEND(iir)){
454
        switch(UART_GET_INT_PEND(iir)){
455
            case uart_int_rx: nctp_receive (); break;
456
            case uart_int_tx: nctp_transmit(); break;
457
            case uart_int_receiver_line_stat: break;
458
            case uart_int_modem_stat: break;
459
            case uart_int_char_timeout_fifo: nctp_receive (); break;
460
            //default: break;
461
        }
462
    }
463
}