#include "serial.h" /* Line Control * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | * |dla| | parity | s | data | */ enum LineControlRegister : uint8_t { d5bit = 0b00000000, // data bits d6bit = 0b00000001, d7bit = 0b00000010, d8bit = 0b00000011, none = 0b00000000, // parity bits odd = 0b00001000, even = 0b00011000, mark = 0b00101000, space = 0b00111000, s1bit = 0b00000000, // stop bits s2bit = 0b00000100, // 1.5 for 5bit data; 2 otherwise dlab = 0b10000000, // divisor latch access bit }; /* Line Status Register */ enum LineStatusRegister : uint8_t { DR = 0b00000001, // data ready: see if there is data to read OE = 0b00000010, // overrun error: see if there has been data lost PE = 0b00000100, // parity error: see if there was error in transmission FE = 0b00001000, // framing error: see if a stop bit was missing BI = 0b00010000, // break indicator: see if there is a break in data input THRE = 0b00100000, // transmitter holding register empty: see if transmission buffer is empty TEMT = 0b01000000, // transmitter empty: see if transmitter is not doing anything ERRO = 0b10000000, // impending error: see if there is an error with a word in the input buffer }; // TODO InterruptControlRegister // TODO FifoControlRegister // TODO ModemControlRegister SerialPort::SerialPort() { /* * The serial controller (UART) has a baud rate of 115200 ticks per second; to limit the speed of the port set the * divisor: * 1. set DLAB on LineControl * 2. set BaudDiv_l * 3. set BaudDiv_h * 4. clear LineControl */ port.write(0x00, InterruptControl); // disable all interrupts port.write(dlab, LineControl); port.write(0x03, BaudDiv_l); // div_l: 0x03 38400 baud port.write(0x00, BaudDiv_h); // div_h: 0x00 port.write(d8bit | none | s1bit, LineControl); // 8 bits, no parity, one stop bit port.write(0xc7, FifoControl); // enable FIFO, clear, with 14-byte threshold port.write(0x0b, ModemControl); // IRQ enabled, RTS/DSR set // test serial port port.write(0x1e, ModemControl); // set in loopback mode port.write(0xae); // write 0xae to port self_check_okay = (port.read() == 0xae); // if not faulty, set in normal operation mode if (self_check_okay) { port.write(0x0f, ModemControl); } } bool SerialPort::ready_read() { return (port.read(LineStatus) & DR); } uint8_t SerialPort::read() { while (!ready_read()) asm volatile("nop"); return port.read(); } bool SerialPort::ready_write() { return (port.read(LineStatus) & THRE); } void SerialPort::write(char c) { while (!ready_write()) asm volatile("nop"); switch (c) { case '\n': port.write('\n'); port.write('\r'); break; default: port.write(static_cast(c)); } }