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