Handout
This commit is contained in:
196
kernel/arch/serial.h
Normal file
196
kernel/arch/serial.h
Normal file
@@ -0,0 +1,196 @@
|
||||
/*! \file
|
||||
* \brief Communication via the \ref Serial interface (RS-232)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
|
||||
/*! \brief Serial interface.
|
||||
* \ingroup io
|
||||
*
|
||||
* This class provides a serial interface (COM1 - COM4) for communication with
|
||||
* the outside world.
|
||||
*
|
||||
* The first IBM PC used the external chip [8250
|
||||
* UART](https://de.wikipedia.org/wiki/NSC_8250), whereas, in today's systems,
|
||||
* this functionality is commonly integrated into the motherboard chipset, but
|
||||
* remained compatible.
|
||||
*
|
||||
* \see [PC8250A Data Sheet](uart-8250a.pdf#page=11) (Registers on page 11)
|
||||
* \see [PC16550D Data Sheet](uart-16550d.pdf#page=16) (Successor, for optional
|
||||
* FIFO buffer, page 16)
|
||||
*/
|
||||
|
||||
class Serial {
|
||||
public:
|
||||
/*! \brief COM-Port
|
||||
*
|
||||
* The serial interface and its hardware addresses. Modern desktop PCs
|
||||
* have, at most, a single, physical COM-port (`COM1`)
|
||||
*/
|
||||
enum class ComPort : uint16_t {
|
||||
COM1 = 0x3f8,
|
||||
COM2 = 0x2f8,
|
||||
COM3 = 0x3e8,
|
||||
COM4 = 0x2e8,
|
||||
};
|
||||
|
||||
/*! \brief Transmission speed
|
||||
*
|
||||
* The unit Baud describes the transmission speed in number of symbols per
|
||||
* seconds. 1 Baud therefore equals the transmission of 1 symbol per second.
|
||||
* The possible Baud rates are whole-number dividers of the clock frequency
|
||||
* of 115200 Hz..
|
||||
*/
|
||||
enum class BaudRate : uint16_t {
|
||||
B300 = 384,
|
||||
B600 = 192,
|
||||
B1200 = 96,
|
||||
B2400 = 48,
|
||||
B4800 = 24,
|
||||
B9600 = 12,
|
||||
B19200 = 6,
|
||||
B38400 = 3,
|
||||
B57600 = 2,
|
||||
B115200 = 1,
|
||||
};
|
||||
|
||||
/*! \brief Number of data bits per character */
|
||||
enum class DataBits : uint8_t {
|
||||
D5 = 0,
|
||||
D6 = 1,
|
||||
D7 = 2,
|
||||
D8 = 3,
|
||||
};
|
||||
|
||||
/*! \brief Number of stop bits per character */
|
||||
enum class StopBits : uint8_t {
|
||||
S1 = 0,
|
||||
S1_5 = 4,
|
||||
S2 = 4,
|
||||
};
|
||||
|
||||
/*! \brief parity bit */
|
||||
enum class Parity : uint8_t {
|
||||
NONE = 0,
|
||||
ODD = 8,
|
||||
EVEN = 24,
|
||||
MARK = 40,
|
||||
SPACE = 56,
|
||||
};
|
||||
|
||||
private:
|
||||
/*! \brief register index */
|
||||
enum class RegisterIndex : uint8_t {
|
||||
RECEIVE_BUFFER = 0,
|
||||
TRANSMIT_BUFFER = 0,
|
||||
INTERRUPT_ENABLE = 1,
|
||||
DIVISOR_LOW = 0,
|
||||
DIVISOR_HIGH = 1,
|
||||
INTERRUPT_IDENT = 2,
|
||||
FIFO_CONTROL = 2,
|
||||
LINE_CONTROL = 3,
|
||||
MODEM_CONTROL = 4,
|
||||
LINE_STATUS = 5,
|
||||
MODEM_STATUS = 6
|
||||
};
|
||||
|
||||
/*! \brief Mask for the respective register */
|
||||
enum class RegisterMask : uint8_t {
|
||||
RECEIVED_DATA_AVAILABLE = 1 << 0,
|
||||
TRANSMITTER_HOLDING_REGISTER_EMPTY = 1 << 1,
|
||||
RECEIVER_LINE_STATUS = 1 << 2,
|
||||
MODEM_STATUS = 1 << 3,
|
||||
|
||||
// Interrupt Ident Register
|
||||
INTERRUPT_PENDING = 1 << 0, ///< 0 means interrupt pending
|
||||
INTERRUPT_ID_0 = 1 << 1,
|
||||
INTERRUPT_ID_1 = 1 << 2,
|
||||
|
||||
// FIFO Control Register
|
||||
ENABLE_FIFO = 1 << 0, ///< 0 means disabled ^= conforming to 8250a
|
||||
CLEAR_RECEIVE_FIFO = 1 << 1,
|
||||
CLEAR_TRANSMIT_FIFO = 1 << 2,
|
||||
DMA_MODE_SELECT = 1 << 3,
|
||||
TRIGGER_RECEIVE = 1 << 6,
|
||||
|
||||
// Line Control Register
|
||||
// bits per character: 5 6 7 8
|
||||
WORD_LENGTH_SELECT_0 = 1 << 0, // Setting Select0: 0 1 0 1
|
||||
WORD_LENGTH_SELECT_1 = 1 << 1, // Setting Select1: 0 0 1 1
|
||||
NUMBER_OF_STOP_BITS = 1 << 2, // 0 ≙ one stop bit, 1 ≙ 1.5/2 stop bits
|
||||
PARITY_ENABLE = 1 << 3,
|
||||
EVEN_PARITY_SELECT = 1 << 4,
|
||||
STICK_PARITY = 1 << 5,
|
||||
SET_BREAK = 1 << 6,
|
||||
DIVISOR_LATCH_ACCESS_BIT = 1 << 7, // DLAB
|
||||
|
||||
// Modem Control Register
|
||||
DATA_TERMINAL_READY = 1 << 0,
|
||||
REQUEST_TO_SEND = 1 << 1,
|
||||
OUT_1 = 1 << 2,
|
||||
OUT_2 = 1 << 3, // must be set for interrupts!
|
||||
LOOP = 1 << 4,
|
||||
|
||||
// Line Status Register
|
||||
DATA_READY = 1 << 0, // Set when there is a value in the receive buffer
|
||||
OVERRUN_ERROR = 1 << 1,
|
||||
PARITY_ERROR = 1 << 2,
|
||||
FRAMING_ERROR = 1 << 3,
|
||||
BREAK_INTERRUPT = 1 << 4,
|
||||
TRANSMITTER_HOLDING_REGISTER = 1 << 5,
|
||||
TRANSMITTER_EMPTY = 1 << 6, // Send buffer empty (ready to send)
|
||||
|
||||
// Modem Status Register
|
||||
DELTA_CLEAR_TO_SEND = 1 << 0,
|
||||
DELTA_DATA_SET_READY = 1 << 1,
|
||||
TRAILING_EDGE_RING_INDICATOR = 1 << 2,
|
||||
DELTA_DATA_CARRIER_DETECT = 1 << 3,
|
||||
CLEAR_TO_SEND = 1 << 4,
|
||||
DATA_SET_READY = 1 << 5,
|
||||
RING_INDICATOR = 1 << 6,
|
||||
DATA_CARRIER_DETECT = 1 << 7
|
||||
};
|
||||
|
||||
/*! \brief Read value from register
|
||||
*
|
||||
*
|
||||
* \param reg Register index
|
||||
* \return The value read from register
|
||||
*/
|
||||
uint8_t readReg(RegisterIndex reg);
|
||||
|
||||
/*! \brief Write value to register
|
||||
*
|
||||
*
|
||||
* \param reg Register index
|
||||
* \param out value to be written
|
||||
*/
|
||||
void writeReg(RegisterIndex reg, uint8_t out);
|
||||
|
||||
protected:
|
||||
/*! \brief Selected COM port */
|
||||
const ComPort port;
|
||||
|
||||
public:
|
||||
/*! \brief Constructor
|
||||
*
|
||||
* Creates a Serial object that encapsulates the used COM port, as well as
|
||||
* the parameters used for the serial connection. Default values are `8N1`
|
||||
* (8 bit, no parity bit, one stop bit) with 115200 Baud using COM1.
|
||||
*
|
||||
*/
|
||||
explicit Serial(ComPort port = ComPort::COM1,
|
||||
BaudRate baud_rate = BaudRate::B115200,
|
||||
DataBits data_bits = DataBits::D8,
|
||||
StopBits stop_bits = StopBits::S1,
|
||||
Parity parity = Parity::NONE);
|
||||
|
||||
/*! \brief Write one byte to the serial interface
|
||||
*
|
||||
*
|
||||
* \param out Byte to be written
|
||||
* \return Byte written (or `-1` if writing byte failed)
|
||||
*/
|
||||
int write(uint8_t out);
|
||||
};
|
||||
Reference in New Issue
Block a user