diff options
Diffstat (limited to 'hid/src/main.cpp')
-rw-r--r-- | hid/src/main.cpp | 371 |
1 files changed, 240 insertions, 131 deletions
diff --git a/hid/src/main.cpp b/hid/src/main.cpp index 8b48f82a..3117d455 100644 --- a/hid/src/main.cpp +++ b/hid/src/main.cpp @@ -29,15 +29,13 @@ #ifdef CMD_SPI # include <SPI.h> #endif +#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" -#endif +#include "usb/hid.h" +#include "ps2/hid.h" // #define CMD_SERIAL Serial1 @@ -48,98 +46,176 @@ // ----------------------------------------------------------------------------- -#ifdef HID_USB_KBD - UsbHidKeyboard hid_kbd; -#elif defined(HID_PS2_KBD) - Ps2HidKeyboard hid_kbd; -#endif -#ifdef HID_USB_MOUSE - UsbHidMouse hid_mouse; -#endif +static UsbKeyboard *_usb_kbd = NULL; +static UsbMouseAbsolute *_usb_mouse_abs = NULL; +static UsbMouseRelative *_usb_mouse_rel = NULL; +static Ps2Keyboard *_ps2_kbd = NULL; -// ----------------------------------------------------------------------------- -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 - ); +#ifdef HID_DYNAMIC +static bool _reset_required = false; + +static void _setOutputs(uint8_t outputs) { + uint8_t data[8] = {0}; + data[0] = PROTO::MAGIC; + data[1] = outputs; + PROTO::split16(PROTO::crc16(data, 6), &data[6], &data[7]); + eeprom_update_block(data, 0, 8); } +#endif -uint8_t cmdResetHid(const uint8_t *_) { // 0 bytes -# ifdef HID_USB_KBD - hid_kbd.reset(); +static void _initOutputs() { + uint8_t data[8]; +# ifdef HID_DYNAMIC + eeprom_read_block(data, 0, 8); + if ( + PROTO::crc16(data, 6) != PROTO::merge8(data[6], data[7]) + || data[0] != PROTO::MAGIC + ) { # endif -# ifdef HID_USB_MOUSE - hid_mouse.reset(); + data[1] = 0; + +# if defined(HID_WITH_USB) && defined(HID_SET_USB_KBD) + data[1] |= PROTO::OUTPUTS::KEYBOARD::USB; +# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_KBD) + data[1] |= PROTO::OUTPUTS::KEYBOARD::PS2; +# endif +# if defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_ABS) + data[1] |= PROTO::OUTPUTS::MOUSE::USB_ABS; +# elif defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_REL) + data[1] |= PROTO::OUTPUTS::MOUSE::USB_REL; +# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_MOUSE) + data[1] |= PROTO::OUTPUTS::MOUSE::PS2; +# endif + +# ifdef HID_DYNAMIC + _setOutputs(data[1]); + } # endif - return cmdPong(); + + uint8_t kbd = data[1] & 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 + } + + uint8_t mouse = data[1] & 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 + } + + USBDevice.attach(); + + 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 + } + + 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 + } } -uint8_t cmdKeyEvent(const uint8_t *buffer) { // 2 bytes - hid_kbd.sendKey(buffer[0], buffer[1]); - return cmdPong(); + +// ----------------------------------------------------------------------------- +static void _cmdSetOutputs(const uint8_t *data) { // 1 bytes +# ifdef HID_DYNAMIC + _setOutputs(data[0]); + _reset_required = 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]; +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(); + } +} + +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]); + } +} +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 - 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) - ); +# 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 -# 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 - - int y = (int)buffer[2] << 8; - y |= (int)buffer[3]; - y = (y + 32768) / 2; // See /kvmd/apps/otg/hid/keyboard.py for details +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 + ); + } +} - hid_mouse.sendMove(x, y); -# endif - return cmdPong(); +static void _cmdMouseRelativeEvent(const uint8_t *data) { // 2 bytes + if (_usb_mouse_rel) { + _usb_mouse_rel->sendRelative(data[0], data[1]); + } } -uint8_t cmdMouseWheelEvent(const uint8_t *buffer) { // 2 bytes -# ifdef HID_USB_MOUSE - hid_mouse.sendWheel(buffer[1]); // Y only, X is not supported -# endif - return cmdPong(); +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]); + } } -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); +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_OUTPUTS: HANDLE(_cmdSetOutputs); + 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; } @@ -151,33 +227,33 @@ uint8_t handleCmdBuffer(const uint8_t *buffer) { // 8 bytes // ----------------------------------------------------------------------------- #ifdef CMD_SPI -volatile uint8_t spi_in[8] = {0}; -volatile uint8_t spi_in_index = 0; +static volatile uint8_t _spi_in[8] = {0}; +static volatile uint8_t _spi_in_index = 0; -volatile uint8_t spi_out[4] = {0}; -volatile uint8_t spi_out_index = 0; +static volatile uint8_t _spi_out[8] = {0}; +static volatile uint8_t _spi_out_index = 0; -bool spiReady() { - return (!spi_out[0] && spi_in_index == 8); +static bool _spiReady() { + return (!_spi_out[0] && _spi_in_index == 8); } -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 _spiWrite(const uint8_t *data) { + // Меджик в нулевом байте разрешает начать ответ + for (int index = 7; index >= 0; --index) { + _spi_out[index] = data[index]; + } } ISR(SPI_STC_vect) { uint8_t in = SPDR; - if (spi_out[0] && spi_out_index < 4) { - SPDR = spi_out[spi_out_index]; + if (_spi_out[0] && _spi_out_index < 8) { + 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; + ++_spi_out_index; + if (_spi_out_index == 8) { + _spi_out_index = 0; + _spi_in_index = 0; + _spi_out[0] = 0; } } } else { @@ -185,11 +261,11 @@ ISR(SPI_STC_vect) { if (!receiving && in == PROTO::MAGIC) { receiving = true; } - if (receiving && spi_in_index < 8) { - spi_in[spi_in_index] = in; - ++spi_in_index; + if (receiving && _spi_in_index < 8) { + _spi_in[_spi_in_index] = in; + ++_spi_in_index; } - if (spi_in_index == 8) { + if (_spi_in_index == 8) { receiving = false; } SPDR = 0; @@ -199,7 +275,7 @@ ISR(SPI_STC_vect) { // ----------------------------------------------------------------------------- -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 +283,71 @@ 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 data[8] = {0}; + data[0] = PROTO::MAGIC; + if (code & PROTO::PONG::OK) { + data[1] = PROTO::PONG::OK; +# ifdef HID_DYNAMIC + if (_reset_required) { + data[1] |= PROTO::PONG::RESET_REQUIRED; + } + data[2] = PROTO::OUTPUTS::DYNAMIC; +# endif + if (_usb_kbd) { + data[1] |= _usb_kbd->getOfflineAs(PROTO::PONG::KEYBOARD_OFFLINE); + data[1] |= _usb_kbd->getLedsAs(PROTO::PONG::CAPS, PROTO::PONG::SCROLL, PROTO::PONG::NUM); + data[2] |= PROTO::OUTPUTS::KEYBOARD::USB; + } else if (_ps2_kbd) { + data[1] |= _ps2_kbd->getOfflineAs(PROTO::PONG::KEYBOARD_OFFLINE); + data[1] |= _ps2_kbd->getLedsAs(PROTO::PONG::CAPS, PROTO::PONG::SCROLL, PROTO::PONG::NUM); + data[2] |= PROTO::OUTPUTS::KEYBOARD::PS2; + } + if (_usb_mouse_abs) { + data[1] |= _usb_mouse_abs->getOfflineAs(PROTO::PONG::MOUSE_OFFLINE); + data[2] |= PROTO::OUTPUTS::MOUSE::USB_ABS; + } else if (_usb_mouse_rel) { + data[1] |= _usb_mouse_rel->getOfflineAs(PROTO::PONG::MOUSE_OFFLINE); + data[2] |= PROTO::OUTPUTS::MOUSE::USB_REL; + } // TODO: ps2 +# ifdef HID_WITH_USB + data[3] |= PROTO::FEATURES::HAS_USB; +# endif +# ifdef HID_WITH_PS2 + data[3] |= PROTO::FEATURES::HAS_PS2; +# endif + } else { + data[1] = code; + } + PROTO::split16(PROTO::crc16(data, 6), &data[6], &data[7]); # ifdef CMD_SERIAL - CMD_SERIAL.write(buffer, 4); + CMD_SERIAL.write(data, 8); # elif defined(CMD_SPI) - spiWrite(buffer); + _spiWrite(data); # 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; -# 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 +359,27 @@ 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)); + } + +# elif defined(CMD_SPI) + pinMode(MISO, OUTPUT); + SPCR = (1 << SPE) | (1 << SPIE); // Slave, SPI En, IRQ En + + while (true) { +# ifdef HID_WITH_PS2 + if (_ps2_kbd) { + _ps2_kbd->periodic(); } # endif + if (_spiReady()) { + _sendResponse(_handleRequest((const uint8_t *)_spi_in)); + } } + +# endif + return 0; } |