diff options
Diffstat (limited to 'hid/src/main.cpp')
-rw-r--r-- | hid/src/main.cpp | 388 |
1 files changed, 230 insertions, 158 deletions
diff --git a/hid/src/main.cpp b/hid/src/main.cpp index 8b48f82a..e97bc37c 100644 --- a/hid/src/main.cpp +++ b/hid/src/main.cpp @@ -20,186 +20,233 @@ *****************************************************************************/ +// #define CMD_SERIAL Serial1 +// #define CMD_SERIAL_SPEED 115200 +// #define CMD_SERIAL_TIMEOUT 100000 +// -- OR -- +// #define CMD_SPI + #if !(defined(CMD_SERIAL) || defined(CMD_SPI)) # error CMD phy is not defined #endif #include <Arduino.h> -#ifdef CMD_SPI -# include <SPI.h> +#ifdef HID_DYNAMIC +# include <avr/eeprom.h> #endif #include "proto.h" - -#if defined(HID_USB_KBD) || defined(HID_USB_MOUSE) -# include "usb/hid.h" -#endif -#ifdef HID_PS2_KBD -# include "ps2/hid.h" +#ifdef CMD_SPI +# include "spi.h" #endif +#include "usb/hid.h" +#include "ps2/hid.h" -// #define CMD_SERIAL Serial1 -// #define CMD_SERIAL_SPEED 115200 -// #define CMD_SERIAL_TIMEOUT 100000 -// -- OR -- -// #define CMD_SPI +// ----------------------------------------------------------------------------- +static UsbKeyboard *_usb_kbd = NULL; +static UsbMouseAbsolute *_usb_mouse_abs = NULL; +static UsbMouseRelative *_usb_mouse_rel = NULL; +static Ps2Keyboard *_ps2_kbd = NULL; -// ----------------------------------------------------------------------------- -#ifdef HID_USB_KBD - UsbHidKeyboard hid_kbd; -#elif defined(HID_PS2_KBD) - Ps2HidKeyboard hid_kbd; -#endif -#ifdef HID_USB_MOUSE - UsbHidMouse hid_mouse; -#endif +#ifdef HID_DYNAMIC +static bool _reset_required = false; +static int _readOutputs(void) { + uint8_t data[8]; + eeprom_read_block(data, 0, 8); + if (data[0] != PROTO::MAGIC || PROTO::crc16(data, 6) != PROTO::merge8(data[6], data[7])) { + return -1; + } + return data[1]; +} -// ----------------------------------------------------------------------------- -uint8_t cmdPong(const uint8_t *_=NULL) { // 0 bytes - return ( - PROTO::PONG::PREFIX - | hid_kbd.getLedsAs(PROTO::PONG::CAPS, PROTO::PONG::SCROLL, PROTO::PONG::NUM) - | (hid_kbd.isOnline() ? 0 : PROTO::PONG::KEYBOARD_OFFLINE) -# ifdef HID_USB_MOUSE - | (hid_mouse.isOnline() ? 0 : PROTO::PONG::MOUSE_OFFLINE) -# endif - ); +static void _writeOutputs(uint8_t mask, uint8_t outputs, bool force) { + int old = 0; + if (!force) { + old = _readOutputs(); + if (old < 0) { + old = 0; + } + } + uint8_t data[8] = {0}; + data[0] = PROTO::MAGIC; + data[1] = (old & ~mask) | outputs; + PROTO::split16(PROTO::crc16(data, 6), &data[6], &data[7]); + eeprom_update_block(data, 0, 8); } +#endif + +static void _initOutputs() { + int outputs; +# ifdef HID_DYNAMIC + outputs = _readOutputs(); + if (outputs < 0) { +# endif + outputs = 0; -uint8_t cmdResetHid(const uint8_t *_) { // 0 bytes -# ifdef HID_USB_KBD - hid_kbd.reset(); +# if defined(HID_WITH_USB) && defined(HID_SET_USB_KBD) + outputs |= PROTO::OUTPUTS::KEYBOARD::USB; +# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_KBD) + outputs |= PROTO::OUTPUTS::KEYBOARD::PS2; # endif -# ifdef HID_USB_MOUSE - hid_mouse.reset(); +# if defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_ABS) + outputs |= PROTO::OUTPUTS::MOUSE::USB_ABS; +# elif defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_REL) + outputs |= PROTO::OUTPUTS::MOUSE::USB_REL; +# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_MOUSE) + outputs |= PROTO::OUTPUTS::MOUSE::PS2; # endif - return cmdPong(); -} -uint8_t cmdKeyEvent(const uint8_t *buffer) { // 2 bytes - hid_kbd.sendKey(buffer[0], buffer[1]); - return cmdPong(); -} +# ifdef HID_DYNAMIC + _writeOutputs(0xFF, outputs, true); + } +# endif -uint8_t cmdMouseButtonEvent(const uint8_t *buffer) { // 2 bytes -# ifdef HID_USB_MOUSE - uint8_t main_state = buffer[0]; - uint8_t extra_state = buffer[1]; + uint8_t kbd = outputs & PROTO::OUTPUTS::KEYBOARD::MASK; + switch (kbd) { +# ifdef HID_WITH_USB + case PROTO::OUTPUTS::KEYBOARD::USB: _usb_kbd = new UsbKeyboard(); break; +# endif +# ifdef HID_WITH_PS2 + case PROTO::OUTPUTS::KEYBOARD::PS2: _ps2_kbd = new Ps2Keyboard(); break; +# endif + } -# define MOUSE_PAIR(_state, _button) \ - _state & PROTO::CMD::MOUSE::_button::SELECT, \ - _state & PROTO::CMD::MOUSE::_button::STATE - hid_mouse.sendButtons( - MOUSE_PAIR(main_state, LEFT), - MOUSE_PAIR(main_state, RIGHT), - MOUSE_PAIR(main_state, MIDDLE), - MOUSE_PAIR(extra_state, EXTRA_UP), - MOUSE_PAIR(extra_state, EXTRA_DOWN) - ); -# undef MOUSE_PAIR + uint8_t mouse = outputs & PROTO::OUTPUTS::MOUSE::MASK; + switch (mouse) { +# ifdef HID_WITH_USB + case PROTO::OUTPUTS::MOUSE::USB_ABS: _usb_mouse_abs = new UsbMouseAbsolute(); break; + case PROTO::OUTPUTS::MOUSE::USB_REL: _usb_mouse_rel = new UsbMouseRelative(); break; # endif - return cmdPong(); -} + } -uint8_t cmdMouseMoveEvent(const uint8_t *buffer) { // 4 bytes -# ifdef HID_USB_MOUSE - int x = (int)buffer[0] << 8; - x |= (int)buffer[1]; - x = (x + 32768) / 2; // See /kvmd/apps/otg/hid/keyboard.py for details + USBDevice.attach(); - int y = (int)buffer[2] << 8; - y |= (int)buffer[3]; - y = (y + 32768) / 2; // See /kvmd/apps/otg/hid/keyboard.py for details + switch (kbd) { +# ifdef HID_WITH_USB + case PROTO::OUTPUTS::KEYBOARD::USB: _usb_kbd->begin(); break; +# endif +# ifdef HID_WITH_PS2 + case PROTO::OUTPUTS::KEYBOARD::PS2: _ps2_kbd->begin(); break; +# endif + } - hid_mouse.sendMove(x, y); + switch (mouse) { +# ifdef HID_WITH_USB + case PROTO::OUTPUTS::MOUSE::USB_ABS: _usb_mouse_abs->begin(); break; + case PROTO::OUTPUTS::MOUSE::USB_REL: _usb_mouse_rel->begin(); break; # endif - return cmdPong(); + } } -uint8_t cmdMouseWheelEvent(const uint8_t *buffer) { // 2 bytes -# ifdef HID_USB_MOUSE - hid_mouse.sendWheel(buffer[1]); // Y only, X is not supported + +// ----------------------------------------------------------------------------- +static void _cmdSetKeyboard(const uint8_t *data) { // 1 bytes +# ifdef HID_DYNAMIC + _writeOutputs(PROTO::OUTPUTS::KEYBOARD::MASK, data[0], false); + _reset_required = true; # endif - return cmdPong(); } -uint8_t handleCmdBuffer(const uint8_t *buffer) { // 8 bytes - uint16_t crc = (uint16_t)buffer[6] << 8; - crc |= (uint16_t)buffer[7]; - - if (protoCrc16(buffer, 6) == crc) { -# define HANDLE(_handler) { return _handler(buffer + 2); } - switch (buffer[1]) { - case PROTO::CMD::RESET_HID: HANDLE(cmdResetHid); - case PROTO::CMD::KEYBOARD::KEY: HANDLE(cmdKeyEvent); - case PROTO::CMD::MOUSE::BUTTON: HANDLE(cmdMouseButtonEvent); - case PROTO::CMD::MOUSE::MOVE: HANDLE(cmdMouseMoveEvent); - case PROTO::CMD::MOUSE::WHEEL: HANDLE(cmdMouseWheelEvent); - case PROTO::CMD::PING: HANDLE(cmdPong); - case PROTO::CMD::REPEAT: return 0; - default: return PROTO::RESP::INVALID_ERROR; - } -# undef HANDLE +static void _cmdSetMouse(const uint8_t *data) { // 1 bytes +# ifdef HID_DYNAMIC + _writeOutputs(PROTO::OUTPUTS::MOUSE::MASK, data[0], false); + _reset_required = true; +# endif +} + +static void _cmdClearHid(const uint8_t *_) { // 0 bytes + if (_usb_kbd) { + _usb_kbd->clear(); + } + if (_usb_mouse_abs) { + _usb_mouse_abs->clear(); + } else if (_usb_mouse_rel) { + _usb_mouse_rel->clear(); } - return PROTO::RESP::CRC_ERROR; } +static void _cmdKeyEvent(const uint8_t *data) { // 2 bytes + if (_usb_kbd) { + _usb_kbd->sendKey(data[0], data[1]); + } else if (_ps2_kbd) { + _ps2_kbd->sendKey(data[0], data[1]); + } +} -// ----------------------------------------------------------------------------- -#ifdef CMD_SPI -volatile uint8_t spi_in[8] = {0}; -volatile uint8_t spi_in_index = 0; +static void _cmdMouseButtonEvent(const uint8_t *data) { // 2 bytes +# define MOUSE_PAIR(_state, _button) \ + _state & PROTO::CMD::MOUSE::_button::SELECT, \ + _state & PROTO::CMD::MOUSE::_button::STATE +# define SEND_BUTTONS(_hid) \ + _hid->sendButtons( \ + MOUSE_PAIR(data[0], LEFT), \ + MOUSE_PAIR(data[0], RIGHT), \ + MOUSE_PAIR(data[0], MIDDLE), \ + MOUSE_PAIR(data[1], EXTRA_UP), \ + MOUSE_PAIR(data[1], EXTRA_DOWN) \ + ); + if (_usb_mouse_abs) { + SEND_BUTTONS(_usb_mouse_abs); + } else if (_usb_mouse_rel) { + SEND_BUTTONS(_usb_mouse_rel); + } +# undef SEND_BUTTONS +# undef MOUSE_PAIR +} -volatile uint8_t spi_out[4] = {0}; -volatile uint8_t spi_out_index = 0; +static void _cmdMouseMoveEvent(const uint8_t *data) { // 4 bytes + // See /kvmd/apps/otg/hid/keyboard.py for details + if (_usb_mouse_abs) { + _usb_mouse_abs->sendMove( + (PROTO::merge8_int(data[0], data[1]) + 32768) / 2, + (PROTO::merge8_int(data[2], data[3]) + 32768) / 2 + ); + } +} -bool spiReady() { - return (!spi_out[0] && spi_in_index == 8); +static void _cmdMouseRelativeEvent(const uint8_t *data) { // 2 bytes + if (_usb_mouse_rel) { + _usb_mouse_rel->sendRelative(data[0], data[1]); + } } -void spiWrite(const uint8_t *buffer) { - spi_out[3] = buffer[3]; - spi_out[2] = buffer[2]; - spi_out[1] = buffer[1]; - spi_out[0] = buffer[0]; // Меджик разрешает начать ответ +static void _cmdMouseWheelEvent(const uint8_t *data) { // 2 bytes + // Y only, X is not supported + if (_usb_mouse_abs) { + _usb_mouse_abs->sendWheel(data[1]); + } else if (_usb_mouse_rel) { + _usb_mouse_rel->sendWheel(data[1]); + } } -ISR(SPI_STC_vect) { - uint8_t in = SPDR; - if (spi_out[0] && spi_out_index < 4) { - SPDR = spi_out[spi_out_index]; - if (!(SPSR & (1 << WCOL))) { - ++spi_out_index; - if (spi_out_index == 4) { - spi_out_index = 0; - spi_in_index = 0; - spi_out[0] = 0; - } - } - } else { - static bool receiving = false; - if (!receiving && in == PROTO::MAGIC) { - receiving = true; - } - if (receiving && spi_in_index < 8) { - spi_in[spi_in_index] = in; - ++spi_in_index; - } - if (spi_in_index == 8) { - receiving = false; +static uint8_t _handleRequest(const uint8_t *data) { // 8 bytes + if (PROTO::crc16(data, 6) == PROTO::merge8(data[6], data[7])) { +# define HANDLE(_handler) { _handler(data + 2); return PROTO::PONG::OK; } + switch (data[1]) { + case PROTO::CMD::PING: return PROTO::PONG::OK; + case PROTO::CMD::SET_KEYBOARD: HANDLE(_cmdSetKeyboard); + case PROTO::CMD::SET_MOUSE: HANDLE(_cmdSetMouse); + case PROTO::CMD::CLEAR_HID: HANDLE(_cmdClearHid); + case PROTO::CMD::KEYBOARD::KEY: HANDLE(_cmdKeyEvent); + case PROTO::CMD::MOUSE::BUTTON: HANDLE(_cmdMouseButtonEvent); + case PROTO::CMD::MOUSE::MOVE: HANDLE(_cmdMouseMoveEvent); + case PROTO::CMD::MOUSE::RELATIVE: HANDLE(_cmdMouseRelativeEvent); + case PROTO::CMD::MOUSE::WHEEL: HANDLE(_cmdMouseWheelEvent); + case PROTO::CMD::REPEAT: return 0; + default: return PROTO::RESP::INVALID_ERROR; } - SPDR = 0; +# undef HANDLE } + return PROTO::RESP::CRC_ERROR; } -#endif // ----------------------------------------------------------------------------- -void sendCmdResponse(uint8_t code) { +static void _sendResponse(uint8_t code) { static uint8_t prev_code = PROTO::RESP::NONE; if (code == 0) { code = prev_code; // Repeat the last code @@ -207,51 +254,75 @@ void sendCmdResponse(uint8_t code) { prev_code = code; } - uint8_t buffer[4]; - buffer[0] = PROTO::MAGIC; - buffer[1] = code; - uint16_t crc = protoCrc16(buffer, 2); - buffer[2] = (uint8_t)(crc >> 8); - buffer[3] = (uint8_t)(crc & 0xFF); + uint8_t response[8] = {0}; + response[0] = PROTO::MAGIC; + if (code & PROTO::PONG::OK) { + response[1] = PROTO::PONG::OK; +# ifdef HID_DYNAMIC + if (_reset_required) { + response[1] |= PROTO::PONG::RESET_REQUIRED; + } + response[2] = PROTO::OUTPUTS::DYNAMIC; +# endif + if (_usb_kbd) { + response[1] |= _usb_kbd->getOfflineAs(PROTO::PONG::KEYBOARD_OFFLINE); + response[1] |= _usb_kbd->getLedsAs(PROTO::PONG::CAPS, PROTO::PONG::SCROLL, PROTO::PONG::NUM); + response[2] |= PROTO::OUTPUTS::KEYBOARD::USB; + } else if (_ps2_kbd) { + response[1] |= _ps2_kbd->getOfflineAs(PROTO::PONG::KEYBOARD_OFFLINE); + response[1] |= _ps2_kbd->getLedsAs(PROTO::PONG::CAPS, PROTO::PONG::SCROLL, PROTO::PONG::NUM); + response[2] |= PROTO::OUTPUTS::KEYBOARD::PS2; + } + if (_usb_mouse_abs) { + response[1] |= _usb_mouse_abs->getOfflineAs(PROTO::PONG::MOUSE_OFFLINE); + response[2] |= PROTO::OUTPUTS::MOUSE::USB_ABS; + } else if (_usb_mouse_rel) { + response[1] |= _usb_mouse_rel->getOfflineAs(PROTO::PONG::MOUSE_OFFLINE); + response[2] |= PROTO::OUTPUTS::MOUSE::USB_REL; + } // TODO: ps2 +# ifdef HID_WITH_USB + response[3] |= PROTO::FEATURES::HAS_USB; +# endif +# ifdef HID_WITH_PS2 + response[3] |= PROTO::FEATURES::HAS_PS2; +# endif + } else { + response[1] = code; + } + PROTO::split16(PROTO::crc16(response, 6), &response[6], &response[7]); # ifdef CMD_SERIAL - CMD_SERIAL.write(buffer, 4); + CMD_SERIAL.write(response, 8); # elif defined(CMD_SPI) - spiWrite(buffer); + spiWrite(response); # endif } -void setup() { - hid_kbd.begin(); -# ifdef HID_USB_MOUSE - hid_mouse.begin(); -# endif +int main() { + init(); // Embedded + initVariant(); // Arduino + _initOutputs(); # ifdef CMD_SERIAL CMD_SERIAL.begin(CMD_SERIAL_SPEED); -# elif defined(CMD_SPI) - pinMode(MISO, OUTPUT); - SPCR = (1 << SPE) | (1 << SPIE); // Slave, SPI En, IRQ En -# endif -} - -void loop() { -# ifdef CMD_SERIAL unsigned long last = micros(); uint8_t buffer[8]; uint8_t index = 0; +# elif defined(CMD_SPI) + spiBegin(); # endif while (true) { -# ifdef HID_PS2_KBD - hid_kbd.periodic(); +# ifdef HID_WITH_PS2 + if (_ps2_kbd) { + _ps2_kbd->periodic(); + } # endif - # ifdef CMD_SERIAL if (CMD_SERIAL.available() > 0) { buffer[index] = (uint8_t)CMD_SERIAL.read(); if (index == 7) { - sendCmdResponse(handleCmdBuffer(buffer)); + _sendResponse(_handleRequest(buffer)); index = 0; } else { last = micros(); @@ -263,14 +334,15 @@ void loop() { (now >= last && now - last > CMD_SERIAL_TIMEOUT) || (now < last && ((unsigned long)-1) - last + now > CMD_SERIAL_TIMEOUT) ) { - sendCmdResponse(PROTO::RESP::TIMEOUT_ERROR); + _sendResponse(PROTO::RESP::TIMEOUT_ERROR); index = 0; } } # elif defined(CMD_SPI) if (spiReady()) { - sendCmdResponse(handleCmdBuffer(spi_in)); + _sendResponse(_handleRequest(spiGet())); } # endif } + return 0; } |