diff options
author | Devaev Maxim <[email protected]> | 2020-11-19 23:28:23 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2020-11-20 00:15:18 +0300 |
commit | a77db72355c760eb38deb4c46a83fb7d3f2ed008 (patch) | |
tree | 208cd060c234fbfd77ef3c1879ed906950660bed /hid | |
parent | 188de715153100806bc4a95f3888f6f03f1ede2f (diff) |
multihid firmware
Diffstat (limited to 'hid')
-rw-r--r-- | hid/Makefile | 16 | ||||
-rw-r--r-- | hid/patch.py | 9 | ||||
-rw-r--r-- | hid/patches/absmouse-win-fix.patch (renamed from hid/patches/absmouse.patch) | 0 | ||||
-rw-r--r-- | hid/patches/no-hid-singletones.patch | 66 | ||||
-rw-r--r-- | hid/patches/no-main.patch | 17 | ||||
-rw-r--r-- | hid/patches/optional-usb-serial.patch (renamed from hid/patches/optional-serial.patch) | 8 | ||||
-rw-r--r-- | hid/platformio.ini | 126 | ||||
-rw-r--r-- | hid/src/main.cpp | 371 | ||||
-rw-r--r-- | hid/src/proto.h | 75 | ||||
-rw-r--r-- | hid/src/ps2/hid.h | 18 | ||||
-rw-r--r-- | hid/src/usb/hid.h | 161 |
11 files changed, 537 insertions, 330 deletions
diff --git a/hid/Makefile b/hid/Makefile index 81fe129d..4d2d4763 100644 --- a/hid/Makefile +++ b/hid/Makefile @@ -1,15 +1,7 @@ -usb: - make _build E=usb -ps2: - make _build E=ps2 -mixed: - make _build E=mixed -usb-spi: - make _build E=usb_spi -ps2-spi: - make _build E=ps2_spi -mixed-spi: - make _build E=mixed_spi +serial: + make _build E=serial +spi: + make _build E=spi _build: rm -f .current platformio run --environment $(E) diff --git a/hid/patch.py b/hid/patch.py index a6ad1ce5..b77e4dac 100644 --- a/hid/patch.py +++ b/hid/patch.py @@ -33,10 +33,11 @@ def _patch(path: str, patch_path: str) -> None: # ===== -_patch(_get_pkg_path("framework-arduino-avr"), "patches/optional-serial.patch") +_patch(_get_pkg_path("framework-arduino-avr"), "patches/no-main.patch") +_patch(_get_pkg_path("framework-arduino-avr"), "patches/optional-usb-serial.patch") _patch(_get_pkg_path("framework-arduino-avr"), "patches/get-plugged-endpoint.patch") _libs = _get_libs() -if "HID-Project" in _libs: - _patch(_libs["HID-Project"], "patches/absmouse.patch") - _patch(_libs["HID-Project"], "patches/shut-up.patch") +_patch(_libs["HID-Project"], "patches/shut-up.patch") +_patch(_libs["HID-Project"], "patches/no-hid-singletones.patch") +_patch(_libs["HID-Project"], "patches/absmouse-win-fix.patch") diff --git a/hid/patches/absmouse.patch b/hid/patches/absmouse-win-fix.patch index ac2226a1..ac2226a1 100644 --- a/hid/patches/absmouse.patch +++ b/hid/patches/absmouse-win-fix.patch diff --git a/hid/patches/no-hid-singletones.patch b/hid/patches/no-hid-singletones.patch new file mode 100644 index 00000000..af971ea5 --- /dev/null +++ b/hid/patches/no-hid-singletones.patch @@ -0,0 +1,66 @@ +diff -u -r HID-Project/src/SingleReport/BootKeyboard.cpp _HID-Project/src/SingleReport/BootKeyboard.cpp +--- HID-Project/src/SingleReport/BootKeyboard.cpp 2019-07-13 21:16:23.000000000 +0300 ++++ _HID-Project/src/SingleReport/BootKeyboard.cpp 2020-11-17 18:59:36.618815374 +0300 +@@ -206,6 +206,6 @@ + } + + +-BootKeyboard_ BootKeyboard; ++//BootKeyboard_ BootKeyboard; + + +diff -u -r HID-Project/src/SingleReport/BootKeyboard.h _HID-Project/src/SingleReport/BootKeyboard.h +--- HID-Project/src/SingleReport/BootKeyboard.h 2019-07-13 21:16:23.000000000 +0300 ++++ _HID-Project/src/SingleReport/BootKeyboard.h 2020-11-17 19:00:54.967113649 +0300 +@@ -80,6 +80,6 @@ + uint8_t* featureReport; + int featureLength; + }; +-extern BootKeyboard_ BootKeyboard; ++//extern BootKeyboard_ BootKeyboard; + + +diff -u -r HID-Project/src/SingleReport/BootMouse.cpp _HID-Project/src/SingleReport/BootMouse.cpp +--- HID-Project/src/SingleReport/BootMouse.cpp 2019-07-13 21:16:23.000000000 +0300 ++++ _HID-Project/src/SingleReport/BootMouse.cpp 2020-11-17 18:59:22.859113905 +0300 +@@ -139,6 +139,6 @@ + } + } + +-BootMouse_ BootMouse; ++//BootMouse_ BootMouse; + + +diff -u -r HID-Project/src/SingleReport/BootMouse.h _HID-Project/src/SingleReport/BootMouse.h +--- HID-Project/src/SingleReport/BootMouse.h 2019-07-13 21:16:23.000000000 +0300 ++++ _HID-Project/src/SingleReport/BootMouse.h 2020-11-17 19:01:04.076915591 +0300 +@@ -48,6 +48,6 @@ + + virtual void SendReport(void* data, int length) override; + }; +-extern BootMouse_ BootMouse; ++//extern BootMouse_ BootMouse; + + +diff -u -r HID-Project/src/SingleReport/SingleAbsoluteMouse.cpp _HID-Project/src/SingleReport/SingleAbsoluteMouse.cpp +--- HID-Project/src/SingleReport/SingleAbsoluteMouse.cpp 2020-11-17 18:39:35.314843889 +0300 ++++ _HID-Project/src/SingleReport/SingleAbsoluteMouse.cpp 2020-11-17 18:59:12.189345326 +0300 +@@ -139,6 +139,6 @@ + USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, length); + } + +-SingleAbsoluteMouse_ SingleAbsoluteMouse; ++//SingleAbsoluteMouse_ SingleAbsoluteMouse; + + +diff -u -r HID-Project/src/SingleReport/SingleAbsoluteMouse.h _HID-Project/src/SingleReport/SingleAbsoluteMouse.h +--- HID-Project/src/SingleReport/SingleAbsoluteMouse.h 2019-07-13 21:16:23.000000000 +0300 ++++ _HID-Project/src/SingleReport/SingleAbsoluteMouse.h 2020-11-17 19:01:21.356539808 +0300 +@@ -49,6 +49,6 @@ + + virtual inline void SendReport(void* data, int length) override; + }; +-extern SingleAbsoluteMouse_ SingleAbsoluteMouse; ++//extern SingleAbsoluteMouse_ SingleAbsoluteMouse; + + diff --git a/hid/patches/no-main.patch b/hid/patches/no-main.patch new file mode 100644 index 00000000..5c645480 --- /dev/null +++ b/hid/patches/no-main.patch @@ -0,0 +1,17 @@ +diff -u -r framework-arduino-avr/cores/arduino/main.cpp _framework-arduino-avr/cores/arduino/main.cpp +--- framework-arduino-avr/cores/arduino/main.cpp 2019-05-16 15:52:01.000000000 +0300 ++++ _framework-arduino-avr/cores/arduino/main.cpp 2020-11-17 18:56:01.243474508 +0300 +@@ -30,6 +30,7 @@ + void setupUSB() __attribute__((weak)); + void setupUSB() { } + ++/* + int main(void) + { + init(); +@@ -49,4 +50,5 @@ + + return 0; + } ++*/ + diff --git a/hid/patches/optional-serial.patch b/hid/patches/optional-usb-serial.patch index 94dd1d72..0d4a0b37 100644 --- a/hid/patches/optional-serial.patch +++ b/hid/patches/optional-usb-serial.patch @@ -5,7 +5,7 @@ https://github.com/arduino-libraries/MIDIUSB/issues/50#issuecomment-451427496 return obj; } -+#ifndef NO_SERIAL ++#ifndef NO_USB_SERIAL PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT), lastEp(CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT), +#else @@ -22,7 +22,7 @@ diff -u -r a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp { 0, // Control Endpoint -+#ifndef NO_SERIAL ++#ifndef NO_USB_SERIAL EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN @@ -34,7 +34,7 @@ diff -u -r a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp { u8 i = setup.wIndex; -+#ifndef NO_SERIAL ++#ifndef NO_USB_SERIAL if (CDC_ACM_INTERFACE == i) return CDC_Setup(setup); +#endif @@ -45,7 +45,7 @@ diff -u -r a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp { u8 interfaces = 0; -+#ifndef NO_SERIAL ++#ifndef NO_USB_SERIAL CDC_GetInterface(&interfaces); +#endif diff --git a/hid/platformio.ini b/hid/platformio.ini index 1f6bd069..87d4fe39 100644 --- a/hid/platformio.ini +++ b/hid/platformio.ini @@ -6,87 +6,51 @@ core_dir = ./.platformio/ platform = atmelavr board = micro framework = arduino +lib_deps = + git+https://github.com/Harvie/ps2dev#v0.0.3 extra_scripts = pre:avrdude.py post:patch.py platform_packages = tool-avrdude -[_parts_usb_kbd] -lib_deps = -build_flags = - -DHID_USB_KBD - -[_parts_usb_mouse] -lib_deps = -build_flags = - -DHID_USB_MOUSE - -[_parts_ps2_kbd] -lib_deps = - git+https://github.com/Harvie/ps2dev#v0.0.3 -build_flags = - -DHID_PS2_KBD - -DPS2_KBD_CLOCK_PIN=7 - -DPS2_KBD_DATA_PIN=5 - -[_usb] -lib_deps = - ${_parts_usb_kbd.lib_deps} -# ${_parts_usb_mouse.lib_deps} -build_flags = - ${_parts_usb_kbd.build_flags} - ${_parts_usb_mouse.build_flags} - -[_ps2] -lib_deps = - ${_parts_ps2_kbd.lib_deps} -build_flags = - ${_parts_ps2_kbd.build_flags} - -[_mixed] -lib_deps = - ${_parts_ps2_kbd.lib_deps} - ${_parts_usb_mouse.lib_deps} +[_common] build_flags = - ${_parts_ps2_kbd.build_flags} - ${_parts_usb_mouse.build_flags} + -DHID_PS2_KBD_CLOCK_PIN=7 + -DHID_PS2_KBD_DATA_PIN=5 + -DHID_USB_CHECK_ENDPOINT +# ----- The default config with dynamic switching ----- + -DHID_DYNAMIC + -DHID_WITH_USB + -DHID_SET_USB_KBD + -DHID_SET_USB_MOUSE_ABS +# ----- PS2 keyboard only ----- +# -DHID_WITH_PS2 +# -DHID_SET_PS2_KBD +# ----- PS2 keyboard + USB absolute mouse ----- +# -DHID_WITH_USB +# -DHID_WITH_PS2 +# -DHID_SET_PS2_KBD +# -DHID_SET_USB_MOUSE_ABS +# ----- PS2 keyboard + USB relative mouse ----- +# -DHID_WITH_USB +# -DHID_WITH_PS2 +# -DHID_SET_PS2_KBD +# -DHID_SET_USB_MOUSE_REL # ===== Serial ===== -[_cmd_serial] +[env:serial] +extends = + _common build_flags = + ${_common.build_flags} -DCMD_SERIAL=Serial1 -DCMD_SERIAL_SPEED=115200 -DCMD_SERIAL_TIMEOUT=100000 upload_port = /dev/ttyACM0 -[env:usb] -extends = - _usb - _cmd_serial -build_flags = - ${_usb.build_flags} - ${_cmd_serial.build_flags} - -[env:ps2] -extends = - _ps2 - _cmd_serial -build_flags = - ${_ps2.build_flags} - ${_cmd_serial.build_flags} - -[env:mixed] -extends = - _mixed - _cmd_serial -build_flags = - ${_mixed.build_flags} - ${_cmd_serial.build_flags} - # ===== RPi SPI ===== [env:bootloader_spi] @@ -99,11 +63,13 @@ upload_flags = extra_scripts = pre:avrdude.py -[_cmd_spi] +[env:spi] +extends = + _common build_flags = + ${_common.build_flags} -DCMD_SPI - -DNO_SERIAL - -DCHECK_ENDPOINT + -DNO_USB_SERIAL upload_protocol = custom upload_flags = -C @@ -117,27 +83,3 @@ upload_flags = -p $BOARD_MCU upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i - -[env:usb_spi] -extends = - _usb - _cmd_spi -build_flags = - ${_usb.build_flags} - ${_cmd_spi.build_flags} - -[env:ps2_spi] -extends = - _ps2 - _cmd_spi -build_flags = - ${_ps2.build_flags} - ${_cmd_spi.build_flags} - -[env:mixed_spi] -extends = - _mixed - _cmd_spi -build_flags = - ${_mixed.build_flags} - ${_cmd_spi.build_flags} 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; } diff --git a/hid/src/proto.h b/hid/src/proto.h index ca9b4f2c..456ba073 100644 --- a/hid/src/proto.h +++ b/hid/src/proto.h @@ -25,7 +25,6 @@ namespace PROTO { const uint8_t MAGIC = 0x33; - const uint16_t CRC_POLINOM = 0xA001; namespace RESP { // Plain responses // const uint8_t OK = 0x20; // Legacy @@ -36,27 +35,50 @@ namespace PROTO { }; namespace PONG { // Complex response - const uint8_t PREFIX = 0x80; + const uint8_t OK = 0x80; const uint8_t CAPS = 0b00000001; const uint8_t SCROLL = 0b00000010; const uint8_t NUM = 0b00000100; const uint8_t KEYBOARD_OFFLINE = 0b00001000; const uint8_t MOUSE_OFFLINE = 0b00010000; + const uint8_t RESET_REQUIRED = 0b01000000; }; + namespace OUTPUTS { // Complex request/responce flags + const uint8_t DYNAMIC = 0b10000000; + namespace KEYBOARD { + const uint8_t MASK = 0b00000111; + const uint8_t USB = 0b00000001; + const uint8_t PS2 = 0b00000011; + }; + namespace MOUSE { + const uint8_t MASK = 0b00111000; + const uint8_t USB_ABS = 0b00001000; + const uint8_t USB_REL = 0b00010000; + const uint8_t PS2 = 0b00011000; + }; + }; + + namespace FEATURES { + const uint8_t HAS_USB = 0b00000001; + const uint8_t HAS_PS2 = 0b00000010; + } + namespace CMD { const uint8_t PING = 0x01; const uint8_t REPEAT = 0x02; - const uint8_t RESET_HID = 0x10; + const uint8_t SET_OUTPUTS = 0x03; + const uint8_t CLEAR_HID = 0x10; namespace KEYBOARD { const uint8_t KEY = 0x11; }; namespace MOUSE { - const uint8_t MOVE = 0x12; - const uint8_t BUTTON = 0x13; - const uint8_t WHEEL = 0x14; + const uint8_t MOVE = 0x12; + const uint8_t BUTTON = 0x13; + const uint8_t WHEEL = 0x14; + const uint8_t RELATIVE = 0x15; namespace LEFT { const uint8_t SELECT = 0b10000000; const uint8_t STATE = 0b00001000; @@ -79,22 +101,35 @@ namespace PROTO { }; }; }; -}; + uint16_t crc16(const uint8_t *buffer, unsigned length) { + const uint16_t polinom = 0xA001; + uint16_t crc = 0xFFFF; -uint16_t protoCrc16(const uint8_t *buffer, unsigned length) { - uint16_t crc = 0xFFFF; - - for (unsigned byte_count = 0; byte_count < length; ++byte_count) { - crc = crc ^ buffer[byte_count]; - for (unsigned bit_count = 0; bit_count < 8; ++bit_count) { - if ((crc & 0x0001) == 0) { - crc = crc >> 1; - } else { - crc = crc >> 1; - crc = crc ^ PROTO::CRC_POLINOM; + for (unsigned byte_count = 0; byte_count < length; ++byte_count) { + crc = crc ^ buffer[byte_count]; + for (unsigned bit_count = 0; bit_count < 8; ++bit_count) { + if ((crc & 0x0001) == 0) { + crc = crc >> 1; + } else { + crc = crc >> 1; + crc = crc ^ polinom; + } } } + return crc; + } + + inline int merge8_int(uint8_t from_a, uint8_t from_b) { + return (((int)from_a << 8) | (int)from_b); + } + + inline uint16_t merge8(uint8_t from_a, uint8_t from_b) { + return (((uint16_t)from_a << 8) | (uint16_t)from_b); + } + + inline void split16(uint16_t from, uint8_t *to_a, uint8_t *to_b) { + *to_a = (uint8_t)(from >> 8); + *to_b = (uint8_t)(from & 0xFF); } - return crc; -} +}; diff --git a/hid/src/ps2/hid.h b/hid/src/ps2/hid.h index 3f226090..c344625b 100644 --- a/hid/src/ps2/hid.h +++ b/hid/src/ps2/hid.h @@ -27,24 +27,20 @@ #include "keymap.h" -// #define PS2_KBD_CLOCK_PIN 7 -// #define PS2_KBD_DATA_PIN 5 +// #define HID_PS2_KBD_CLOCK_PIN 7 +// #define HID_PS2_KBD_DATA_PIN 5 -class Ps2HidKeyboard { +class Ps2Keyboard { // https://wiki.osdev.org/PS/2_Keyboard public: - Ps2HidKeyboard() : _dev(PS2_KBD_CLOCK_PIN, PS2_KBD_DATA_PIN) {} + Ps2Keyboard() : _dev(HID_PS2_KBD_CLOCK_PIN, HID_PS2_KBD_DATA_PIN) {} void begin() { _dev.keyboard_init(); } - bool isOnline() { - return true; - } - void periodic() { _dev.keyboard_handle(&_leds); } @@ -57,7 +53,7 @@ class Ps2HidKeyboard { if (ps2_type != PS2_KEY_TYPE_UNKNOWN) { // Не отправлялась часть нажатий. Когда clock на нуле, комп не принимает ничего от клавы. // Этот костыль понижает процент пропущенных нажатий. - while (digitalRead(PS2_KBD_CLOCK_PIN) == 0) {}; + while (digitalRead(HID_PS2_KBD_CLOCK_PIN) == 0) {}; if (state) { switch (ps2_type) { case PS2_KEY_TYPE_REG: _dev.keyboard_press(ps2_code); break; @@ -78,6 +74,10 @@ class Ps2HidKeyboard { } } + uint8_t getOfflineAs(uint8_t offline) { + return 0; + } + uint8_t getLedsAs(uint8_t caps, uint8_t scroll, uint8_t num) { uint8_t result = 0; diff --git a/hid/src/usb/hid.h b/hid/src/usb/hid.h index d48d0fc2..7a102eab 100644 --- a/hid/src/usb/hid.h +++ b/hid/src/usb/hid.h @@ -29,113 +29,158 @@ // ----------------------------------------------------------------------------- -#ifdef CHECK_ENDPOINT -static bool _checkEndpoint(uint8_t ep) { - // https://github.com/arduino/ArduinoCore-avr/blob/2f67c916f6ab6193c404eebe22efe901e0f9542d/cores/arduino/USBCore.cpp#L249 - // https://sourceforge.net/p/arduinomidilib/svn/41/tree/branch/3.1/Teensy/teensy_core/usb_midi/usb_api.cpp#l103 - uint8_t intr_state = SREG; - cli(); - UENUM = ep & 7; - bool rw_allowed = UEINTX & (1 << RWAL); - SREG = intr_state; - return rw_allowed; -} -# define CHECK_HID_EP { if (!isOnline()) return; } +#ifdef HID_USB_CHECK_ENDPOINT +// https://github.com/arduino/ArduinoCore-avr/blob/2f67c916f6ab6193c404eebe22efe901e0f9542d/cores/arduino/USBCore.cpp#L249 +// https://sourceforge.net/p/arduinomidilib/svn/41/tree/branch/3.1/Teensy/teensy_core/usb_midi/usb_api.cpp#l103 +# define CLS_GET_OFFLINE_AS(_hid) \ + uint8_t getOfflineAs(uint8_t offline) { \ + uint8_t ep = _hid.getPluggedEndpoint(); \ + uint8_t intr_state = SREG; \ + cli(); \ + UENUM = ep & 7; \ + bool rw_allowed = UEINTX & (1 << RWAL); \ + SREG = intr_state; \ + if (rw_allowed) { \ + return 0; \ + } \ + return offline; \ + } +# define CHECK_HID_EP { if (getOfflineAs(1)) return; } + #else +# define CLS_GET_OFFLINE_AS(_hid) \ + uint8_t getOfflineAs(uint8_t offline) { \ + return 0; \ + } # define CHECK_HID_EP + #endif -class UsbHidKeyboard { +class UsbKeyboard { public: - UsbHidKeyboard() {} + UsbKeyboard() {} void begin() { - BootKeyboard.begin(); - } - - bool isOnline() { -# ifdef CHECK_ENDPOINT - return _checkEndpoint(BootKeyboard.getPluggedEndpoint()); -# else - return true; -# endif + _kbd.begin(); } - void reset() { - BootKeyboard.releaseAll(); + void clear() { + _kbd.releaseAll(); } void sendKey(uint8_t code, bool state) { CHECK_HID_EP; KeyboardKeycode usb_code = keymapUsb(code); if (usb_code != KEY_ERROR_UNDEFINED) { - if (state) BootKeyboard.press(usb_code); - else BootKeyboard.release(usb_code); + if (state) _kbd.press(usb_code); + else _kbd.release(usb_code); } } + CLS_GET_OFFLINE_AS(_kbd) + uint8_t getLedsAs(uint8_t caps, uint8_t scroll, uint8_t num) { - uint8_t leds = BootKeyboard.getLeds(); + uint8_t leds = _kbd.getLeds(); uint8_t result = 0; - if (leds & LED_CAPS_LOCK) result |= caps; if (leds & LED_SCROLL_LOCK) result |= scroll; if (leds & LED_NUM_LOCK) result |= num; return result; } + + private: + BootKeyboard_ _kbd; }; -class UsbHidMouse { +#define CLS_SEND_BUTTONS \ + void sendButtons( \ + bool left_select, bool left_state, \ + bool right_select, bool right_state, \ + bool middle_select, bool middle_state, \ + bool up_select, bool up_state, \ + bool down_select, bool down_state \ + ) { \ + if (left_select) _sendButton(MOUSE_LEFT, left_state); \ + if (right_select) _sendButton(MOUSE_RIGHT, right_state); \ + if (middle_select) _sendButton(MOUSE_MIDDLE, middle_state); \ + if (up_select) _sendButton(MOUSE_PREV, up_state); \ + if (down_select) _sendButton(MOUSE_NEXT, down_state); \ + } + +class UsbMouseAbsolute { public: - UsbHidMouse() {} + UsbMouseAbsolute() {} void begin() { - SingleAbsoluteMouse.begin(); + _mouse.begin(); } - bool isOnline() { -# ifdef CHECK_ENDPOINT - return _checkEndpoint(SingleAbsoluteMouse.getPluggedEndpoint()); -# else - return true; -# endif + void clear() { + _mouse.releaseAll(); } - void reset() { - SingleAbsoluteMouse.releaseAll(); + CLS_SEND_BUTTONS + + void sendMove(int x, int y) { + CHECK_HID_EP; + _mouse.moveTo(x, y); } - void sendButtons( - bool left_select, bool left_state, - bool right_select, bool right_state, - bool middle_select, bool middle_state, - bool up_select, bool up_state, - bool down_select, bool down_state - ) { - if (left_select) _sendButton(MOUSE_LEFT, left_state); - if (right_select) _sendButton(MOUSE_RIGHT, right_state); - if (middle_select) _sendButton(MOUSE_MIDDLE, middle_state); - if (up_select) _sendButton(MOUSE_PREV, up_state); - if (down_select) _sendButton(MOUSE_NEXT, down_state); + void sendWheel(int delta_y) { + // delta_x is not supported by hid-project now + CHECK_HID_EP; + _mouse.move(0, 0, delta_y); } - void sendMove(int x, int y) { + CLS_GET_OFFLINE_AS(_mouse) + + private: + SingleAbsoluteMouse_ _mouse; + + void _sendButton(uint8_t button, bool state) { CHECK_HID_EP; - SingleAbsoluteMouse.moveTo(x, y); + if (state) _mouse.press(button); + else _mouse.release(button); } +}; - void sendWheel(int delta_y) { +class UsbMouseRelative { + public: + UsbMouseRelative() {} + + void begin() { + _mouse.begin(); + } + + void clear() { + _mouse.releaseAll(); + } + + CLS_SEND_BUTTONS + + void sendRelative(int x, int y) { CHECK_HID_EP; + _mouse.move(x, y, 0); + } + + void sendWheel(int delta_y) { // delta_x is not supported by hid-project now - SingleAbsoluteMouse.move(0, 0, delta_y); + CHECK_HID_EP; + _mouse.move(0, 0, delta_y); } + CLS_GET_OFFLINE_AS(_mouse) + private: + BootMouse_ _mouse; + void _sendButton(uint8_t button, bool state) { CHECK_HID_EP; - if (state) SingleAbsoluteMouse.press(button); - else SingleAbsoluteMouse.release(button); + if (state) _mouse.press(button); + else _mouse.release(button); } }; +#undef CLS_SEND_BUTTONS +#undef CLS_GET_OFFLINE_AS #undef CHECK_HID_EP |