Project

General

Profile

Statistics
| Revision:

root / proj / src / uart.c @ 267

History | View | Annotate | Download (14.2 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 263 up20180642
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 252 up20180642
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 235 up20180642
int uart_get_config(int base_addr, uart_config *config){
138
    int ret = SUCCESS;
139
140
    config->base_addr = base_addr;
141
142 252 up20180642
    if((ret = uart_get_lcr(base_addr, &config->lcr))) return ret;
143 235 up20180642
144 252 up20180642
    if((ret = uart_get_ier(base_addr, &config->ier))) return ret;
145 242 up20180642
146
    if((ret = uart_enable_divisor_latch (base_addr))) return ret;
147 235 up20180642
    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 242 up20180642
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
150 235 up20180642
151
    uart_parse_config(config);
152
    return ret;
153
}
154
void uart_print_config(uart_config config){
155 249 up20180642
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 235 up20180642
    else switch(config.parity){
160 249 up20180642
        case uart_parity_odd : printf("ODD parity\n"     ); break;
161
        case uart_parity_even: printf("EVEN parity\n"    ); break;
162 235 up20180642
        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 249 up20180642
    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 235 up20180642
}
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 252 up20180642
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
177 235 up20180642
    conf = (conf & (~UART_BITS_PER_CHAR)) | bits_per_char;
178 252 up20180642
    return uart_set_lcr(base_addr, conf);
179 235 up20180642
}
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 252 up20180642
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
186 235 up20180642
    conf = (conf & (~UART_STOP_BITS)) | stop;
187 252 up20180642
    return uart_set_lcr(base_addr, conf);
188 235 up20180642
}
189
int uart_set_parity(int base_addr, uart_parity par){
190
    int ret = SUCCESS;
191
    uint8_t parity = par << 3;
192 252 up20180642
    uint8_t conf; if((ret = uart_get_lcr(base_addr, &conf))) return ret;
193 235 up20180642
    conf = (conf & (~UART_PARITY)) | parity;
194 252 up20180642
    return uart_set_lcr(base_addr, conf);
195 235 up20180642
}
196 241 up20180642
int uart_set_bit_rate(int base_addr, float bit_rate){
197 235 up20180642
    int ret = SUCCESS;
198
    uint16_t latch = UART_BITRATE/bit_rate;
199 241 up20180642
    uint8_t dll = UART_GET_DLL(latch);
200
    uint8_t dlm = UART_GET_DLM(latch);
201 235 up20180642
    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 249 up20180642
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
205 235 up20180642
    return SUCCESS;
206
}
207 249 up20180642
208 252 up20180642
static int uart_get_char(int base_addr, uint8_t *p){
209 249 up20180642
    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 252 up20180642
static int uart_send_char(int base_addr, uint8_t c){
214 249 up20180642
    int ret;
215
    if((ret = uart_disable_divisor_latch(base_addr))) return ret;
216 252 up20180642
    if(sys_outb(base_addr+UART_THR, c)) return WRITE_ERROR;
217 249 up20180642
    return SUCCESS;
218
}
219 252 up20180642
static int uart_receiver_ready(int base_addr){
220 249 up20180642
    uint8_t lsr;
221
    if(uart_get_lsr(base_addr, &lsr)) return false;
222
    return UART_GET_RECEIVER_READY(lsr);
223
}
224 252 up20180642
static int uart_transmitter_empty(int base_addr){
225 249 up20180642
    uint8_t lsr;
226
    if(uart_get_lsr(base_addr, &lsr)) return false;
227
    return UART_GET_TRANSMITTER_EMPTY(lsr);
228
}
229 252 up20180642
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 261 up20180642
static int uart_has_communication_error(int base_addr){
260 249 up20180642
    int ret;
261 261 up20180642
    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 249 up20180642
    return SUCCESS;
355
}
356 261 up20180642
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 249 up20180642
    int ret;
366 261 up20180642
    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 249 up20180642
    return SUCCESS;
379
}