Handout
This commit is contained in:
122
device/keydecoder.cc
Normal file
122
device/keydecoder.cc
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "keydecoder.h"
|
||||
|
||||
#include "ps2controller.h"
|
||||
|
||||
// Constants used for key decoding
|
||||
const unsigned char BREAK_BIT = 0x80;
|
||||
const unsigned char PREFIX_1 = 0xe0;
|
||||
const unsigned char PREFIX_2 = 0xe1;
|
||||
|
||||
Key KeyDecoder::decode(unsigned char code) {
|
||||
Key key = modifier;
|
||||
|
||||
// All keys that are introduced by the MF II keyboard (compared to the older
|
||||
// AT keyboard) always send a prefix value as first byte.
|
||||
if (code == PREFIX_1 || code == PREFIX_2) {
|
||||
prefix = code;
|
||||
} else {
|
||||
// Releasing a key is, for us, only important for the modifier keys such as
|
||||
// SHIFT, CTRL and ALT, For other, non-modifier keys, we ignore the break
|
||||
// code.
|
||||
bool pressed = (code & BREAK_BIT) == 0;
|
||||
|
||||
// A key's break code is identical to its make code with an additionally set
|
||||
// BREAK_BIT
|
||||
Key::Scancode scancode = static_cast<Key::Scancode>(code & (~BREAK_BIT));
|
||||
|
||||
// We ignore "new" special keys, such as the Windows key
|
||||
if (scancode < Key::Scancode::KEYS) {
|
||||
// save state
|
||||
status[scancode] = pressed;
|
||||
|
||||
// Take a closer look at modifier make and break events
|
||||
bool isModifier = true;
|
||||
switch (scancode) {
|
||||
// both shifts are handled equally
|
||||
case Key::Scancode::KEY_LEFT_SHIFT:
|
||||
case Key::Scancode::KEY_RIGHT_SHIFT:
|
||||
modifier.shift = pressed;
|
||||
break;
|
||||
|
||||
case Key::Scancode::KEY_LEFT_ALT:
|
||||
if (prefix == PREFIX_1) {
|
||||
modifier.alt_right = pressed;
|
||||
} else {
|
||||
modifier.alt_left = pressed;
|
||||
}
|
||||
break;
|
||||
|
||||
case Key::Scancode::KEY_LEFT_CTRL:
|
||||
if (prefix == PREFIX_1) {
|
||||
modifier.ctrl_right = pressed;
|
||||
} else {
|
||||
modifier.ctrl_left = pressed;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
isModifier = false;
|
||||
}
|
||||
|
||||
// For keys other than modifiers, we only care about the make code
|
||||
if (pressed && !isModifier) {
|
||||
switch (scancode) {
|
||||
case Key::Scancode::KEY_CAPS_LOCK:
|
||||
modifier.caps_lock ^= 1;
|
||||
setLed(PS2Controller::LED_CAPS_LOCK, modifier.caps_lock);
|
||||
break;
|
||||
|
||||
case Key::Scancode::KEY_SCROLL_LOCK:
|
||||
modifier.scroll_lock ^= 1;
|
||||
setLed(PS2Controller::LED_SCROLL_LOCK, modifier.scroll_lock);
|
||||
break;
|
||||
|
||||
case Key::Scancode::KEY_NUM_LOCK: // Can be both NumLock and pause
|
||||
// On old keyboards, the pause functionality was only accessible by
|
||||
// pressing Ctrl+NumLock. Modern MF-II keyboards therefore send
|
||||
// exactly this code combination when the pause key was pressed.
|
||||
// Normally, the pause key does not provide an ASCII code, but we
|
||||
// check that anyway. In either case, we're now done decoding.
|
||||
if (modifier.ctrl_left) { // pause key
|
||||
key.scancode = scancode;
|
||||
} else { // NumLock
|
||||
modifier.num_lock ^= 1;
|
||||
setLed(PS2Controller::LED_NUM_LOCK, modifier.num_lock);
|
||||
}
|
||||
break;
|
||||
|
||||
// Special case scan code 53: This code is used by both the minus key
|
||||
// on the main keyboard and the division key on the number block. When
|
||||
// the division key was pressed, we adjust the scancode accordingly.
|
||||
case Key::Scancode::KEY_SLASH:
|
||||
if (prefix == PREFIX_1) {
|
||||
key.scancode = Key::Scancode::KEY_DIV;
|
||||
key.shift = true;
|
||||
} else {
|
||||
key.scancode = scancode;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
key.scancode = scancode;
|
||||
|
||||
// When NumLock is enabled and a key on the keypad was pressed, we
|
||||
// want return the ASCII and scan codes of the corresponding
|
||||
// numerical key instead of the arrow keys. The keys on the cursor
|
||||
// block (prefix == PREFIX_1), however, should remain usable.
|
||||
// Therefore, as a little hack, we deactivate the NumLock for these
|
||||
// keys.
|
||||
if (modifier.num_lock && prefix == PREFIX_1) {
|
||||
key.num_lock = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The prefix is only valid for the immediately following code, which was
|
||||
// just handled.
|
||||
prefix = 0;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
40
device/keydecoder.h
Normal file
40
device/keydecoder.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*! \file
|
||||
* \brief \ref KeyDecoder decodes a keystroke to the corresponding \ref Key
|
||||
* object
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../object/key.h"
|
||||
#include "../types.h"
|
||||
|
||||
/*! \brief Decoder for \ref ps2keyboardset1 "keyboard codes" received from the
|
||||
* \ref PS2Controller
|
||||
* \ingroup io
|
||||
*
|
||||
* Extracts the make and break codes, modifier and scan codes from the pressed
|
||||
* key.
|
||||
*/
|
||||
class KeyDecoder {
|
||||
unsigned char prefix; ///< Prefix byte for keys
|
||||
Key modifier; ///< activated modifier keys (e.g., caps lock)
|
||||
|
||||
public:
|
||||
/*! \brief Current state (pressed or released) of all keys.
|
||||
*/
|
||||
bool status[Key::Scancode::KEYS];
|
||||
|
||||
/*! \brief Default constructor
|
||||
*/
|
||||
KeyDecoder() {}
|
||||
|
||||
/*! \brief Interprets the \ref ps2keyboardset1 "make and break codes"
|
||||
* received from the keyboard and derives the corresponding scan code and
|
||||
* further information about other pressed keys, such as \key{shift} and
|
||||
* \key{ctrl}.
|
||||
*
|
||||
* \param code Byte from Keyboard to decode
|
||||
* \return Pressed key (\ref Key::valid returns `false` if the key is not yet
|
||||
* complete)
|
||||
*/
|
||||
Key decode(unsigned char code);
|
||||
};
|
||||
130
device/ps2controller.cc
Normal file
130
device/ps2controller.cc
Normal file
@@ -0,0 +1,130 @@
|
||||
#include "ps2controller.h"
|
||||
|
||||
#include "../arch/core_interrupt.h"
|
||||
#include "../arch/ioport.h"
|
||||
#include "../compiler/fix.h"
|
||||
#include "../debug/output.h"
|
||||
#include "keydecoder.h"
|
||||
|
||||
namespace PS2Controller {
|
||||
|
||||
// I/O Ports of the PS2 Controller
|
||||
static const IOPort ctrl_port(
|
||||
0x64); ///< Access status- (read) and command (write) register
|
||||
static const IOPort data_port(0x60); ///< Access PS/2 device [keyboard] output-
|
||||
///< (read) and input (write) buffer
|
||||
/* The buffers are used to communicate with the controller or the connected
|
||||
* PS/2 devices alike:
|
||||
* - For the output buffer, the controller decides to which PS/2 device the
|
||||
* data gets forwarded to -- by default it is the primary PS/2 device
|
||||
* (keyboard).
|
||||
* - The source device from which the data was gathered can be determined using
|
||||
* the status flag (\ref IS_MOUSE).
|
||||
*
|
||||
* Please also note, that the naming of the buffer may be a bit contra-intuitive
|
||||
* since it is the perspective of the PS/2 controller due to historical reasons.
|
||||
*/
|
||||
|
||||
// Key decoder (stores the state of the modifier keys)
|
||||
static KeyDecoder key_decoder;
|
||||
|
||||
// To store the current state of the Keyboard LEDs
|
||||
static uint8_t leds = 0;
|
||||
|
||||
/*! \brief Flags in the PS/2 controller status register
|
||||
*/
|
||||
enum Status {
|
||||
HAS_OUTPUT = 1 << 0, ///< Output buffer non-empty?
|
||||
INPUT_PENDING = 1 << 1, ///< Is input buffer full?
|
||||
SYSTEM_FLAG = 1 << 2, ///< set on soft reset, cleared on power up
|
||||
IS_COMMAND = 1 << 3, ///< Is command Byte? (otherwise data)
|
||||
IS_MOUSE = 1 << 5, ///< Mouse output has data
|
||||
TIMEOUT_ERROR = 1 << 6, ///< Timeout error
|
||||
PARITY_ERROR = 1 << 7 ///< Parity error
|
||||
};
|
||||
|
||||
/*! \brief Commands to be send to the Keyboard
|
||||
*/
|
||||
enum KeyboardCommand : uint8_t {
|
||||
KEYBOARD_SET_LED =
|
||||
0xed, ///< Set the LED (according to the following parameter byte)
|
||||
KEYBOARD_SEND_ECHO = 0xee, ///< Send an echo packet
|
||||
KEYBOARD_SET_SPEED = 0xf3, ///< Set the repeat rate (according to the
|
||||
///< following parameter byte)
|
||||
KEYBOARD_ENABLE = 0xf4, ///< Enable Keyboard
|
||||
KEYBOARD_DISABLE = 0xf5, ///< Disable Keyboard
|
||||
KEYBOARD_SET_DEFAULT = 0xf6, ///< Load defaults
|
||||
};
|
||||
|
||||
/*! \brief Replies
|
||||
*/
|
||||
enum Reply {
|
||||
ACK = 0xfa, ///< Acknowledgement
|
||||
RESEND = 0xfe, ///< Request to resend (not required to implement)
|
||||
ECHO = 0xee ///< Echo answer
|
||||
};
|
||||
|
||||
/*! \brief Commands for the PS/2 Controller
|
||||
*
|
||||
* These commands are processed by the controller and *not* send to
|
||||
* keyboard/mouse. They have to be written into the command register.
|
||||
*/
|
||||
enum ControllerCommand {
|
||||
CONTROLLER_GET_COMMAND_BYTE = 0x20, ///< Read Command Byte of PS/2 Controller
|
||||
CONTROLLER_SET_COMMAND_BYTE =
|
||||
0x60, ///< Write Command Byte of PS/2 Controller
|
||||
CONTROLLER_MOUSE_DISABLE = 0xa7, ///< Disable mouse interface
|
||||
CONTROLLER_MOUSE_ENABLE = 0xa8, ///< Enable mouse interface
|
||||
CONTROLLER_KEYBOARD_DISABLE = 0xad, ///< Disable keyboard interface
|
||||
CONTROLLER_KEYBOARD_ENABLE = 0xae, ///< Enable keyboard interface
|
||||
CONTROLLER_SEND_TO_MOUSE = 0xd4, ///< Send parameter to mouse device
|
||||
};
|
||||
|
||||
/*! \brief Send a command or data to a connected PS/2 device
|
||||
*
|
||||
* The value must only be written into the input buffer after the previously
|
||||
* written values have been fetched (\ref INPUT_PENDING in the status register).
|
||||
*
|
||||
* \todo(11) Implement method
|
||||
*
|
||||
* \param value data to be sent
|
||||
*/
|
||||
[[maybe_unused]] static void sendData(uint8_t value) {
|
||||
// TODO: You have to implement this method
|
||||
(void)value;
|
||||
}
|
||||
|
||||
void init() {
|
||||
// Switch all LEDs off (on many PCs NumLock is turned on after power up)
|
||||
setLed(LED_CAPS_LOCK, false);
|
||||
setLed(LED_SCROLL_LOCK, false);
|
||||
setLed(LED_NUM_LOCK, false);
|
||||
|
||||
// Set to maximum speed & minimum delay
|
||||
setRepeatRate(SPEED_30_0CPS, DELAY_250MS);
|
||||
}
|
||||
|
||||
bool fetch(Key &pressed) {
|
||||
// TODO: You have to implement this method
|
||||
(void)pressed;
|
||||
return false;
|
||||
}
|
||||
|
||||
void setRepeatRate(Speed speed, Delay delay) {
|
||||
(void)speed;
|
||||
(void)delay;
|
||||
}
|
||||
|
||||
void setLed(enum LED led, bool on) {
|
||||
if (on) {
|
||||
leds |= led;
|
||||
} else {
|
||||
leds &= ~led;
|
||||
}
|
||||
sendData(KEYBOARD_SET_LED); // Command for the Keyboard
|
||||
sendData(leds); // Parameter
|
||||
}
|
||||
|
||||
void drainBuffer() {}
|
||||
|
||||
} // namespace PS2Controller
|
||||
153
device/ps2controller.h
Normal file
153
device/ps2controller.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/*! \file
|
||||
* \brief \ref PS2Controller "PS/2 Controller" (Intel 8042, also known as
|
||||
* Keyboard Controller)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../object/key.h"
|
||||
#include "../types.h"
|
||||
|
||||
/*! \brief PS/2 Controller
|
||||
* \ingroup io
|
||||
*
|
||||
* Initializes the PS/2 devices (Keyboard and optional Mouse), and
|
||||
* determines both the scan code and ASCII character of a pressed key from the
|
||||
* transmitted make and break codes using the \ref KeyDecoder.
|
||||
*
|
||||
* \note This controller is also known as Intel 8042 (nowadays integrated in
|
||||
* the mainboard) or *Keyboard Controller*.
|
||||
* But to avoid confusion with the actual Keyboard and since we use the
|
||||
* PS/2-compatible mode to support the Mouse as well, the name
|
||||
* PS/2 Controller was chosen for the sake of simplicity.
|
||||
*
|
||||
* \note Since modern PCs sometimes don't have an PS/2 connector, USB keyboards
|
||||
* and mice are emulated as PS/2 device with USB Legacy Support.
|
||||
*/
|
||||
namespace PS2Controller {
|
||||
/*! \brief Initialization of connected devices
|
||||
*
|
||||
* All status LEDs of the keyboard are switched off and the repetition rate is
|
||||
* set to maximum speed.
|
||||
*
|
||||
* Later the \ref IOAPIC is configured to receive corresponding interrupts.
|
||||
*
|
||||
* \note The keyboard interrupts should be configured as \ref IOAPIC::LEVEL
|
||||
* "level triggered". According to the standard we would have to check the
|
||||
* corresponding entry in
|
||||
* \ref ACPI::MADS::Interrupt_Source_Override and use these values. Most
|
||||
* likely this would suggest an \ref IOAPIC::EDGE "edge-triggered mode" -- which
|
||||
* would work as well. However, using a \ref IOAPIC::LEVEL "level-triggered
|
||||
* mode" is more forgiving because it resends the interrupt request even if an
|
||||
* interrupt was lost (e.g. the required handling, retrieving the buffer entry,
|
||||
* was not performed).
|
||||
*
|
||||
* \todo(12) Register with \ref IOAPIC
|
||||
*/
|
||||
void init();
|
||||
|
||||
/*! \brief Retrieve the keyboard event
|
||||
*
|
||||
* Retrieves make and brake events from the keyboard.
|
||||
* If a valid (non special) key was pressed, the scan code is determined
|
||||
* using \ref KeyDecoder::decode into a \ref Key object.
|
||||
* Events on special keys like \key{Shift}, \key{Alt}, \key{CapsLock} etc. are
|
||||
* stored (in \ref KeyDecoder) and applied on subsequent keystrokes, while no
|
||||
* valid key is retrieved.
|
||||
*
|
||||
* Mouse events are ignored.
|
||||
*
|
||||
* \todo(11) Implement Method
|
||||
*
|
||||
* \todo(12) Adjust method (unless it is already non-blocking)
|
||||
*
|
||||
* \param pressed Reference to an object which will contain the pressed \ref Key
|
||||
* on success
|
||||
* \return `true` if a valid key was decoded
|
||||
*/
|
||||
bool fetch(Key &pressed);
|
||||
|
||||
/*! \brief Delay before the keyboard starts repeating sending a pressed key
|
||||
*/
|
||||
enum Delay {
|
||||
DELAY_250MS = 0, ///< Delay of 0.25s
|
||||
DELAY_500MS = 1, ///< Delay of 0.5s
|
||||
DELAY_750MS = 2, ///< Delay of 0.75s
|
||||
DELAY_1000MS = 3 ///< Delay of 1s
|
||||
};
|
||||
|
||||
/*! \brief Repeat Rate of Characters
|
||||
*
|
||||
* \see \ref ps2keyboard
|
||||
*/
|
||||
enum Speed {
|
||||
SPEED_30_0CPS = 0x00, ///< 30 characters per second
|
||||
SPEED_26_7CPS = 0x01, ///< 26.7 characters per second
|
||||
SPEED_24_0CPS = 0x02, ///< 24 characters per second
|
||||
SPEED_21_8CPS = 0x03, ///< 12.8 characters per second
|
||||
SPEED_20_7CPS = 0x04, ///< 20.7 characters per second
|
||||
SPEED_18_5CPS = 0x05, ///< 18.5 characters per second
|
||||
SPEED_17_1CPS = 0x06, ///< 17.1 characters per second
|
||||
SPEED_16_0CPS = 0x07, ///< 16 characters per second
|
||||
SPEED_15_0CPS = 0x08, ///< 15 characters per second
|
||||
SPEED_13_3CPS = 0x09, ///< 13.3 characters per second
|
||||
SPEED_12_0CPS = 0x0a, ///< 12 characters per second
|
||||
SPEED_10_9CPS = 0x0b, ///< 10.9 characters per second
|
||||
SPEED_10_0CPS = 0x0c, ///< 10 characters per second
|
||||
SPEED_09_2CPS = 0x0d, ///< 9.2 characters per second
|
||||
SPEED_08_6CPS = 0x0e, ///< 8.6 characters per second
|
||||
SPEED_08_0CPS = 0x0f, ///< 8 characters per second
|
||||
SPEED_07_5CPS = 0x10, ///< 7.5 characters per second
|
||||
SPEED_06_7CPS = 0x11, ///< 6.7 characters per second
|
||||
SPEED_06_0CPS = 0x12, ///< 6 characters per second
|
||||
SPEED_05_5CPS = 0x13, ///< 5.5 characters per second
|
||||
SPEED_05_0CPS = 0x14, ///< 5 characters per second
|
||||
SPEED_04_6CPS = 0x15, ///< 4.6 characters per second
|
||||
SPEED_04_3CPS = 0x16, ///< 4.3 characters per second
|
||||
SPEED_04_0CPS = 0x17, ///< 4 characters per second
|
||||
SPEED_03_7CPS = 0x18, ///< 3.7 characters per second
|
||||
SPEED_03_3CPS = 0x19, ///< 3.3 characters per second
|
||||
SPEED_03_0CPS = 0x1a, ///< 3 characters per second
|
||||
SPEED_02_7CPS = 0x1b, ///< 2.7 characters per second
|
||||
SPEED_02_5CPS = 0x1c, ///< 2.5 characters per second
|
||||
SPEED_02_3CPS = 0x1d, ///< 2.3 characters per second
|
||||
SPEED_02_1CPS = 0x1e, ///< 2.1 characters per second
|
||||
SPEED_02_0CPS = 0x1f, ///< 2 characters per second
|
||||
};
|
||||
|
||||
/*! \brief Configure the repeat rate of the keyboard
|
||||
*
|
||||
* \param delay configures how long a key must be pressed before the repetition
|
||||
* begins.
|
||||
* \param speed determines how fast the key codes should follow each other.
|
||||
* Valid values are between `0` (30 characters per second) and
|
||||
* `31` (2 characters per second).
|
||||
*/
|
||||
void setRepeatRate(Speed speed, Delay delay);
|
||||
|
||||
/*! \brief Keyboard LEDs
|
||||
*/
|
||||
enum LED {
|
||||
LED_SCROLL_LOCK = 1 << 0, ///< Scroll Lock
|
||||
LED_NUM_LOCK = 1 << 1, ///< Num Lock
|
||||
LED_CAPS_LOCK = 1 << 2, ///< Caps Lock
|
||||
};
|
||||
|
||||
/*! \brief Enable or disable a keyboard LED
|
||||
*
|
||||
* \param led LED to enable or disable
|
||||
* \param on `true` will enable the specified LED, `false` disable
|
||||
*/
|
||||
void setLed(enum LED led, bool on);
|
||||
|
||||
/*! \brief Empties the keyboard buffer.
|
||||
*
|
||||
* The keyboard may not send any interrupts if the buffer is not empty.
|
||||
* To prevent unhandled keystrokes (for example during boot) the buffer
|
||||
* should be emptied once right before allowing keyboard interrupts
|
||||
* (even if keystrokes might be lost).
|
||||
*
|
||||
* \todo(12) Implement method
|
||||
*/
|
||||
void drainBuffer();
|
||||
|
||||
} // namespace PS2Controller
|
||||
30
device/serialstream.cc
Normal file
30
device/serialstream.cc
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "serialstream.h"
|
||||
|
||||
SerialStream::SerialStream(ComPort port, BaudRate baud_rate, DataBits data_bits,
|
||||
StopBits stop_bits, Parity parity) {
|
||||
(void)port;
|
||||
(void)baud_rate;
|
||||
(void)data_bits;
|
||||
(void)stop_bits;
|
||||
(void)parity;
|
||||
}
|
||||
|
||||
void SerialStream::flush() {}
|
||||
|
||||
void SerialStream::setForeground(Color c) { (void)c; }
|
||||
|
||||
void SerialStream::setBackground(Color c) { (void)c; }
|
||||
|
||||
void SerialStream::setAttribute(Attrib a) { (void)a; }
|
||||
|
||||
void SerialStream::reset() {}
|
||||
|
||||
void SerialStream::setPos(int x, int y) {
|
||||
(void)x;
|
||||
(void)y;
|
||||
}
|
||||
|
||||
void SerialStream::print(char* str, int length) {
|
||||
(void)str;
|
||||
(void)length;
|
||||
}
|
||||
143
device/serialstream.h
Normal file
143
device/serialstream.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*! \file
|
||||
* \brief \ref Serial \ref SerialStream "output stream"
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../arch/serial.h"
|
||||
#include "../object/outputstream.h"
|
||||
#include "../types.h"
|
||||
|
||||
/*! \brief Console (VT100 compatible) via \ref Serial interface.
|
||||
* \ingroup io
|
||||
*
|
||||
* This class allows to connect a VT100-compatible display terminal via
|
||||
* the serial interface.
|
||||
*
|
||||
* The utility 'screen' can be used to attach a terminal to an interface
|
||||
* at a specified connection speed: `screen /dev/ttyS0 115200`
|
||||
*
|
||||
* Color and position can be adjusted with the help of
|
||||
* [escape
|
||||
* codes](http://web.archive.org/web/20181008150037/http://www.termsys.demon.co.uk/vtansi.htm).
|
||||
*/
|
||||
|
||||
class SerialStream : public OutputStream, public Serial {
|
||||
public:
|
||||
/*! \brief Attributes
|
||||
* can be used to influence the display of the output.
|
||||
*
|
||||
* \note The attributes might not be supported or have a different effect
|
||||
* depending on the terminal emulator!
|
||||
*/
|
||||
enum Attrib {
|
||||
RESET = 0, ///< Turn off character attributes
|
||||
BRIGHT = 1, ///< Bold
|
||||
DIM = 2, ///< Low intensity (dimmed)
|
||||
UNDERSCORE = 4, ///< Underline
|
||||
BLINK = 5, ///< Blink (slow)
|
||||
REVERSE = 7, ///< Swap fore & background
|
||||
HIDDEN = 8, ///< Concealed
|
||||
};
|
||||
|
||||
/*! \brief Color codes
|
||||
*
|
||||
* Default VT100 supports eight colors for both foreground and background
|
||||
* (later versions 256 [8 bit] and even true color [32 bit]).
|
||||
* The actual color is affected by the attributes and can look significantly
|
||||
* different depending on the terminal emulator.
|
||||
*/
|
||||
enum Color {
|
||||
BLACK = 0,
|
||||
RED = 1,
|
||||
GREEN = 2,
|
||||
YELLOW = 3,
|
||||
BLUE = 4,
|
||||
MAGENTA = 5,
|
||||
CYAN = 6,
|
||||
WHITE = 7
|
||||
};
|
||||
|
||||
/*! \brief Constructor for the VT100-compatible console
|
||||
*
|
||||
* Sets up the serial connection as well
|
||||
*
|
||||
* \todo(11) Implement Method
|
||||
*/
|
||||
explicit SerialStream(ComPort port = COM1, BaudRate baud_rate = BAUD_115200,
|
||||
DataBits data_bits = DATA_8BIT,
|
||||
StopBits stop_bits = STOP_1BIT,
|
||||
Parity parity = PARITY_NONE);
|
||||
|
||||
/*! \brief Method to output the buffer contents of the base class \ref
|
||||
* Stringbuffer
|
||||
*
|
||||
* The method is automatically called when the buffer is full,
|
||||
* but can also be called explicitly to force output of the current buffer.
|
||||
*
|
||||
* \todo(11) Implement Method
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
/*! \brief Change foreground color (for subsequent output)
|
||||
*
|
||||
* \todo(11) Implement Method
|
||||
*
|
||||
* \param c Color
|
||||
*/
|
||||
void setForeground(Color c);
|
||||
|
||||
/*! \brief Change background color (for subsequent output)
|
||||
*
|
||||
* \todo(11) Implement Method
|
||||
*
|
||||
* \param c Color
|
||||
*/
|
||||
void setBackground(Color c);
|
||||
|
||||
/*! \brief Change text attribute (for subsequent output)
|
||||
*
|
||||
* \todo(11) Implement Method
|
||||
*
|
||||
* \param a Attribute
|
||||
*/
|
||||
void setAttribute(Attrib a);
|
||||
|
||||
/*! \brief Reset terminal
|
||||
*
|
||||
* Clear screen, place cursor at the beginning and reset colors
|
||||
* and attributes to the default value.
|
||||
*
|
||||
* \todo(11) Implement Method
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/*! \brief Set the cursor position
|
||||
*
|
||||
* \param x Column in window
|
||||
* \param y Row in window
|
||||
*
|
||||
* \todo(11) Implement Method
|
||||
*/
|
||||
void setPos(int x, int y);
|
||||
|
||||
/*! \brief Display multiple characters in the window starting at the current
|
||||
* cursor position
|
||||
*
|
||||
* This method can be used to output a string, starting at the current cursor
|
||||
* position. Since the string does not need to contain a '\0' termination
|
||||
* (as it is usually the case in C), the parameter `length` is required to
|
||||
* specify the number of characters in the string.
|
||||
*
|
||||
* The text is displayed using the previously configured
|
||||
* \ref setAttribute() "attributes", \ref setForeground() "fore-"
|
||||
* and \ref setBackground "background" color.
|
||||
*
|
||||
* A line break will occur wherever the character `\n` is inserted
|
||||
* in the text to be output (for compatibility reasons a `\r` is
|
||||
* automatically appended).
|
||||
*
|
||||
* \param str String to output
|
||||
* \param length length of string
|
||||
*/
|
||||
void print(char* str, int length);
|
||||
};
|
||||
12
device/textstream.cc
Normal file
12
device/textstream.cc
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "textstream.h"
|
||||
|
||||
TextStream::TextStream(unsigned from_col, unsigned to_col, unsigned from_row,
|
||||
unsigned to_row, bool use_cursor) {
|
||||
(void)from_col;
|
||||
(void)to_col;
|
||||
(void)from_row;
|
||||
(void)to_row;
|
||||
(void)use_cursor;
|
||||
}
|
||||
|
||||
void TextStream::flush() {}
|
||||
41
device/textstream.h
Normal file
41
device/textstream.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*! \file
|
||||
* \brief \ref TextStream outputs text onto the screen in \ref CGA
|
||||
*/
|
||||
|
||||
/*! \defgroup io I/O subsystem
|
||||
* \brief The input/output subsystem
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
|
||||
/*! \brief Output text (form different data type sources) on screen in text
|
||||
* mode
|
||||
* \ingroup io
|
||||
*
|
||||
* Allows the output of different data types as strings on the \ref CGA
|
||||
* screen of a PC.
|
||||
* To achieve this, \ref TextStream is derived from both \ref OutputStream and
|
||||
* \ref TextWindow and only implements the method \ref TextStream::flush().
|
||||
* Further formatting or special effects are implemented in \ref TextWindow.
|
||||
*/
|
||||
class TextStream {
|
||||
// Prevent copies and assignments
|
||||
TextStream(const TextStream&) = delete;
|
||||
TextStream& operator=(const TextStream&) = delete;
|
||||
|
||||
public:
|
||||
/// \copydoc TextWindow::TextWindow(unsigned,unsigned,unsigned,unsigned,bool)
|
||||
TextStream(unsigned from_col, unsigned to_col, unsigned from_row,
|
||||
unsigned to_row, bool use_cursor = false);
|
||||
|
||||
/*! \brief Output the buffer contents of the base class \ref Stringbuffer
|
||||
*
|
||||
* The method is automatically called when the buffer is full,
|
||||
* but can also be called explicitly to force output of the current buffer.
|
||||
*
|
||||
*
|
||||
* \todo(11) Implement method
|
||||
*/
|
||||
void flush();
|
||||
};
|
||||
Reference in New Issue
Block a user