Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (14.5 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

    
85
#define UART_INT_PEND                           (BIT(3)|BIT(2)|BIT(1))
86

    
87
#define UART_GET_IF_INT_PEND(n)                 (!((n)&1))
88
typedef enum {
89
    uart_int_receiver_line_stat = (         BIT(1) | BIT(0)),
90
    uart_int_rx                 = (         BIT(1)         ),
91
    uart_int_char_timeout_fifo  = (BIT(2) | BIT(1)         ),
92
    uart_int_tx                 = (                  BIT(0)),
93
    uart_int_modem_stat         = (0)
94
} uart_int_code;
95
#define UART_GET_INT_PEND(n)                    ((uart_int_code)(((n)&UART_INT_PEND)>>UART_INT_PEND_POS))
96

    
97
int (subscribe_uart_interrupt)(uint8_t interrupt_bit, int *interrupt_id) {
98
    if (interrupt_id == NULL) return 1;
99
    *interrupt_id = interrupt_bit;
100
    return (sys_irqsetpolicy(COM1_IRQ, IRQ_REENABLE | IRQ_EXCLUSIVE, interrupt_id));
101
}
102

    
103
static void uart_parse_config(uart_config *config){
104
    /// LCR
105
    config->bits_per_char          = UART_GET_BITS_PER_CHAR     (config->lcr);
106
    config->stop_bits              = UART_GET_STOP_BITS         (config->lcr);
107
    config->parity                 = UART_GET_PARITY            (config->lcr); if((config->parity & BIT(0)) == 0) config->parity = uart_parity_none;
108
    config->break_control          = UART_GET_BREAK_CONTROL     (config->lcr);
109
    config->dlab                   = UART_GET_DLAB              (config->lcr);
110
    /// IER
111
    config->received_data_int      = UART_GET_INT_EN_RX                (config->ier);
112
    config->transmitter_empty_int  = UART_GET_INT_EN_TX                (config->ier);
113
    config->receiver_line_stat_int = UART_GET_INT_EN_RECEIVER_LINE_STAT(config->ier);
114
    config->modem_stat_int         = UART_GET_INT_EN_MODEM_STAT        (config->ier);
115
    /// DIV LATCH
116
    config->divisor_latch          = UART_GET_DIV_LATCH(config->dlm, config->dll);
117
}
118

    
119
static int uart_get_lcr(int base_addr, uint8_t *p){
120
    return util_sys_inb(base_addr+UART_LCR, p);
121
}
122
static int uart_set_lcr(int base_addr, uint8_t config){
123
    if(sys_outb(base_addr+UART_LCR, config)) return WRITE_ERROR;
124
    return SUCCESS;
125
}
126
static int uart_get_lsr(int base_addr, uint8_t *p){
127
    return util_sys_inb(base_addr+UART_LSR, p);
128
}
129
static int uart_get_iir(int base_addr, uint8_t *p){
130
    return util_sys_inb(base_addr+UART_IIR, p);
131
}
132

    
133
static int uart_enable_divisor_latch(int base_addr){
134
    int ret = SUCCESS;
135
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
136
    return uart_set_lcr(base_addr, conf | UART_DLAB);
137
}
138
static int uart_disable_divisor_latch(int base_addr){
139
    int ret = SUCCESS;
140
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
141
    return uart_set_lcr(base_addr, conf & (~UART_DLAB));
142
}
143

    
144
static int uart_get_ier(int base_addr, uint8_t *p){
145
    int ret;
146
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
147
    return util_sys_inb(base_addr+UART_IER, p);
148
}
149
static int uart_set_ier(int base_addr, uint8_t n){
150
    int ret;
151
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
152
    if(sys_outb(base_addr+UART_IER, n)) return WRITE_ERROR;
153
    return SUCCESS;
154
}
155

    
156
int uart_get_config(int base_addr, uart_config *config){
157
    int ret = SUCCESS;
158

    
159
    config->base_addr = base_addr;
160

    
161
    if((ret = uart_get_lcr(base_addr, &config->lcr))) return ret;
162

    
163
    if((ret = uart_get_ier(base_addr, &config->ier))) return ret;
164

    
165
    if((ret = uart_enable_divisor_latch (base_addr))) return ret;
166
    if((ret = util_sys_inb(base_addr+UART_DLL, &config->dll   ))) return ret;
167
    if((ret = util_sys_inb(base_addr+UART_DLM, &config->dlm   ))) return ret;
168
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
169

    
170
    uart_parse_config(config);
171
    return ret;
172
}
173
void uart_print_config(uart_config config){
174

    
175
    printf("%s configuration:\n", (config.base_addr == COM1_ADDR ? "COM1" : "COM2"));
176
    printf("\tLCR = 0x%X: %d bits per char\t %d stop bits\t", config.lcr, config.bits_per_char, config.stop_bits);
177
    if((config.parity&BIT(0)) == 0) printf("NO parity\n");
178
    else switch(config.parity){
179
        case uart_parity_odd : printf("ODD parity\n"     ); break;
180
        case uart_parity_even: printf("EVEN parity\n"    ); break;
181
        case uart_parity_par1: printf("parity bit is 1\n"); break;
182
        case uart_parity_par0: printf("parity bit is 0\n"); break;
183
        default              : printf("invalid\n"        ); break;
184
    }
185
    printf("\tDLM = 0x%02X DLL=0x%02X: bitrate = %d bps\n", config.dlm, config.dll, UART_BITRATE/config.divisor_latch);
186
    printf("\tIER = 0x%02X: Rx interrupts: %s\tTx interrupts: %s\n", config.ier,
187
        (config.received_data_int     ? "ENABLED":"DISABLED"),
188
        (config.transmitter_empty_int ? "ENABLED":"DISABLED"));
189
}
190

    
191
int uart_set_bits_per_character(int base_addr, uint8_t bits_per_char){
192
    if(bits_per_char < 5 || bits_per_char > 8) return INVALID_ARG;
193
    int ret = SUCCESS;
194
    bits_per_char = (bits_per_char-5)&0x3;
195
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
196
    conf = (conf & (~UART_BITS_PER_CHAR)) | bits_per_char;
197
    return uart_set_lcr(base_addr, conf);
198
}
199
int uart_set_stop_bits(int base_addr, uint8_t stop){
200
    if(stop != 1 && stop != 2) return INVALID_ARG;
201
    int ret = SUCCESS;
202
    stop -= 1;
203
    stop = (stop&1)<<2;
204
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
205
    conf = (conf & (~UART_STOP_BITS)) | stop;
206
    return uart_set_lcr(base_addr, conf);
207
}
208
int uart_set_parity(int base_addr, uart_parity par){
209
    int ret = SUCCESS;
210
    uint8_t parity = par << 3;
211
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
212
    conf = (conf & (~UART_PARITY)) | parity;
213
    return uart_set_lcr(base_addr, conf);
214
}
215
int uart_set_bit_rate(int base_addr, float bit_rate){
216
    int ret = SUCCESS;
217
    uint16_t latch = UART_BITRATE/bit_rate;
218
    uint8_t dll = UART_GET_DLL(latch);
219
    uint8_t dlm = UART_GET_DLM(latch);
220
    if((ret = uart_enable_divisor_latch(base_addr))) return ret;
221
    if(sys_outb(base_addr+UART_DLL, dll)) return WRITE_ERROR;
222
    if(sys_outb(base_addr+UART_DLM, dlm)) return WRITE_ERROR;
223
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
224
    return SUCCESS;
225
}
226

    
227
static int uart_get_char(int base_addr, uint8_t *p){
228
    int ret;
229
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
230
    return util_sys_inb(base_addr+UART_RBR, p);
231
}
232
static int uart_send_char(int base_addr, uint8_t c){
233
    int ret;
234
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
235
    if(sys_outb(base_addr+UART_THR, c)) return WRITE_ERROR;
236
    return SUCCESS;
237
}
238
static int uart_receiver_ready(int base_addr){
239
    uint8_t lsr;
240
    if(uart_get_lsr(base_addr, &lsr)) return false;
241
    return UART_GET_RECEIVER_READY(lsr);
242
}
243
static int uart_transmitter_empty(int base_addr){
244
    uint8_t lsr;
245
    if(uart_get_lsr(base_addr, &lsr)) return false;
246
    return UART_GET_TRANSMITTER_EMPTY(lsr);
247
}
248

    
249
int uart_enable_int_rx(int base_addr){
250
    int ret;
251
    uint8_t ier;
252
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
253
    ier |= UART_INT_EN_RX;
254
    return uart_set_ier(base_addr, ier);
255
}
256
int uart_disable_int_rx(int base_addr){
257
    int ret;
258
    uint8_t ier;
259
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
260
    ier &= ~UART_INT_EN_RX;
261
    return uart_set_ier(base_addr, ier);
262
}
263
int uart_enable_int_tx(int base_addr){
264
    int ret;
265
    uint8_t ier;
266
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
267
    ier |= UART_INT_EN_TX;
268
    return uart_set_ier(base_addr, ier);
269
}
270
int uart_disable_int_tx(int base_addr){
271
    int ret;
272
    uint8_t ier;
273
    if((ret = uart_get_ier(base_addr, &ier))) return ret;
274
    ier &= ~UART_INT_EN_TX;
275
    return uart_set_ier(base_addr, ier);
276
}
277

    
278
/// NCTP
279

    
280
#define NCTP_START      0x80
281
#define NCTP_END        0xFF
282
#define NCTP_OK         0xFF
283
#define NCTP_NOK        0x00
284

    
285
queue_t *out = NULL;
286
queue_t *in  = NULL;
287
void (*process)(const uint8_t*, const size_t) = NULL;
288

    
289
int nctp_init(void){
290
    out = queue_ctor(); if(out == NULL) return NULL_PTR;
291
    in  = queue_ctor(); if(in  == NULL) return NULL_PTR;
292
    return SUCCESS;
293
}
294
int nctp_dump(void){
295
    int ret;
296
    if((ret = nctp_free())) return ret;
297
    return nctp_init();
298
}
299
int nctp_set_processor(void (*proc_func)(const uint8_t*, const size_t)){
300
    process = proc_func;
301
    return SUCCESS;
302
}
303
int nctp_free(void){
304
    while(!queue_empty(out)){
305
        free(queue_top(out));
306
        queue_pop(out);
307
    }
308
    while(!queue_empty(in)){
309
        free(queue_top(in));
310
        queue_pop(in);
311
    }
312
    return SUCCESS;
313
}
314

    
315
int nctp_send(size_t num, uint8_t* ptr[], size_t sz[]){
316
    {
317
        size_t cnt = 0;
318
        for(size_t i = 0; i < num; ++i){
319
            cnt += sz[i];
320
            if(cnt > queue_max_size) return TRANS_REFUSED;
321
        }
322
    }
323
    int ret;
324
    uint8_t *tmp;
325
    tmp = malloc(sizeof(uint8_t)); *tmp = NCTP_START; queue_push(out, tmp);
326
    for(size_t i = 0; i < num; ++i){
327
        uint8_t *p = ptr[i]; size_t s = sz[i];
328
        for(size_t j = 0; j < s; ++j, ++p){
329
            tmp = malloc(sizeof(uint8_t)); *tmp = *p; queue_push(out, tmp);
330
        }
331
    }
332
    tmp = malloc(sizeof(uint8_t)); *tmp = NCTP_END; queue_push(out, tmp);
333
    if(uart_transmitter_empty(COM1_ADDR)){
334
        if((ret = uart_send_char(COM1_ADDR, *(uint8_t*)queue_top(out)))) return ret;
335
        queue_pop(out);
336
    }
337
    return SUCCESS;
338
}
339
static int nctp_transmit(void){
340
    if(!queue_empty(out)){
341
        int ret = uart_send_char(COM1_ADDR, *(uint8_t*)queue_top(out));
342
        queue_pop(out);
343
        return ret;
344
    }else return SUCCESS;
345
}
346

    
347
static void nctp_process_received(){
348
    free(queue_top(in)); queue_pop(in);
349
    size_t sz = 1024; uint8_t *p = malloc(sz*sizeof(uint8_t));
350
    size_t i = 0;
351
    while(*(uint8_t*)queue_top(in) != NCTP_END){
352
        //printf("%c\n", *(uint8_t*)queue_top(in));
353
        p[i++] = *(uint8_t*)queue_top(in);
354
        free(queue_top(in)); queue_pop(in);
355
        if(i >= sz) p = realloc(p, sz=2*sz);
356
    }
357
    free(queue_top(in)); queue_pop(in);
358
    if(process != NULL) process(p, i);
359
    free(p);
360
}
361
static int nctp_receive(void){
362
    int ret;
363
    uint8_t c;
364
    int num_ends = 0;
365
    while(uart_receiver_ready(COM1_ADDR)){
366
        if((ret = uart_get_char(COM1_ADDR, &c))) return ret;
367
        uint8_t *tmp = malloc(sizeof(uint8_t)); *tmp = c;
368
        queue_push(in, tmp);
369
        if(c == NCTP_END) ++num_ends;
370
    }
371
    while(num_ends-- > 0) nctp_process_received();
372
    return SUCCESS;
373
}
374

    
375
int nctp_ih_err = SUCCESS;
376
void nctp_ih(void){
377
    uint8_t iir;
378
    if((nctp_ih_err = uart_get_iir(COM1_ADDR, &iir))) return;
379
    if(UART_GET_IF_INT_PEND(iir)){
380
        switch(UART_GET_INT_PEND(iir)){
381
            case uart_int_rx: nctp_receive (); break;
382
            case uart_int_tx: nctp_transmit(); break;
383
            default: break;
384
        }
385
    }
386
}