Project

General

Profile

Statistics
| Revision:

root / proj / src / uart.c @ 276

History | View | Annotate | Download (13.8 KB)

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