multihid firmware

This commit is contained in:
Devaev Maxim 2020-11-19 23:28:23 +03:00
parent 188de71515
commit a77db72355
17 changed files with 636 additions and 379 deletions

View File

@ -1,15 +1,7 @@
usb: serial:
make _build E=usb make _build E=serial
ps2: spi:
make _build E=ps2 make _build E=spi
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
_build: _build:
rm -f .current rm -f .current
platformio run --environment $(E) platformio run --environment $(E)

View File

@ -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") _patch(_get_pkg_path("framework-arduino-avr"), "patches/get-plugged-endpoint.patch")
_libs = _get_libs() _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")

View File

@ -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;

17
hid/patches/no-main.patch Normal file
View File

@ -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;
}
+*/

View File

@ -5,7 +5,7 @@ https://github.com/arduino-libraries/MIDIUSB/issues/50#issuecomment-451427496
return obj; return obj;
} }
+#ifndef NO_SERIAL +#ifndef NO_USB_SERIAL
PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT), PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT),
lastEp(CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT), lastEp(CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT),
+#else +#else
@ -22,7 +22,7 @@ diff -u -r a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp
{ {
0, // Control Endpoint 0, // Control Endpoint
+#ifndef NO_SERIAL +#ifndef NO_USB_SERIAL
EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM
EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT
EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN 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; u8 i = setup.wIndex;
+#ifndef NO_SERIAL +#ifndef NO_USB_SERIAL
if (CDC_ACM_INTERFACE == i) if (CDC_ACM_INTERFACE == i)
return CDC_Setup(setup); return CDC_Setup(setup);
+#endif +#endif
@ -45,7 +45,7 @@ diff -u -r a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp
{ {
u8 interfaces = 0; u8 interfaces = 0;
+#ifndef NO_SERIAL +#ifndef NO_USB_SERIAL
CDC_GetInterface(&interfaces); CDC_GetInterface(&interfaces);
+#endif +#endif

View File

@ -6,87 +6,51 @@ core_dir = ./.platformio/
platform = atmelavr platform = atmelavr
board = micro board = micro
framework = arduino framework = arduino
lib_deps =
HID-Project@2.6.1
git+https://github.com/Harvie/ps2dev#v0.0.3
extra_scripts = extra_scripts =
pre:avrdude.py pre:avrdude.py
post:patch.py post:patch.py
platform_packages = platform_packages =
tool-avrdude tool-avrdude
[_parts_usb_kbd] [_common]
lib_deps =
HID-Project@2.6.1
build_flags = build_flags =
-DHID_USB_KBD -DHID_PS2_KBD_CLOCK_PIN=7
-DHID_PS2_KBD_DATA_PIN=5
[_parts_usb_mouse] -DHID_USB_CHECK_ENDPOINT
lib_deps = # ----- The default config with dynamic switching -----
HID-Project@2.6.1 -DHID_DYNAMIC
build_flags = -DHID_WITH_USB
-DHID_USB_MOUSE -DHID_SET_USB_KBD
-DHID_SET_USB_MOUSE_ABS
[_parts_ps2_kbd] # ----- PS2 keyboard only -----
lib_deps = # -DHID_WITH_PS2
git+https://github.com/Harvie/ps2dev#v0.0.3 # -DHID_SET_PS2_KBD
build_flags = # ----- PS2 keyboard + USB absolute mouse -----
-DHID_PS2_KBD # -DHID_WITH_USB
-DPS2_KBD_CLOCK_PIN=7 # -DHID_WITH_PS2
-DPS2_KBD_DATA_PIN=5 # -DHID_SET_PS2_KBD
# -DHID_SET_USB_MOUSE_ABS
[_usb] # ----- PS2 keyboard + USB relative mouse -----
lib_deps = # -DHID_WITH_USB
${_parts_usb_kbd.lib_deps} # -DHID_WITH_PS2
# ${_parts_usb_mouse.lib_deps} # -DHID_SET_PS2_KBD
build_flags = # -DHID_SET_USB_MOUSE_REL
${_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}
build_flags =
${_parts_ps2_kbd.build_flags}
${_parts_usb_mouse.build_flags}
# ===== Serial ===== # ===== Serial =====
[_cmd_serial] [env:serial]
extends =
_common
build_flags = build_flags =
${_common.build_flags}
-DCMD_SERIAL=Serial1 -DCMD_SERIAL=Serial1
-DCMD_SERIAL_SPEED=115200 -DCMD_SERIAL_SPEED=115200
-DCMD_SERIAL_TIMEOUT=100000 -DCMD_SERIAL_TIMEOUT=100000
upload_port = /dev/ttyACM0 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 ===== # ===== RPi SPI =====
[env:bootloader_spi] [env:bootloader_spi]
@ -99,11 +63,13 @@ upload_flags =
extra_scripts = extra_scripts =
pre:avrdude.py pre:avrdude.py
[_cmd_spi] [env:spi]
extends =
_common
build_flags = build_flags =
${_common.build_flags}
-DCMD_SPI -DCMD_SPI
-DNO_SERIAL -DNO_USB_SERIAL
-DCHECK_ENDPOINT
upload_protocol = custom upload_protocol = custom
upload_flags = upload_flags =
-C -C
@ -117,27 +83,3 @@ upload_flags =
-p -p
$BOARD_MCU $BOARD_MCU
upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i 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}

View File

@ -29,15 +29,13 @@
#ifdef CMD_SPI #ifdef CMD_SPI
# include <SPI.h> # include <SPI.h>
#endif #endif
#ifdef HID_DYNAMIC
# include <avr/eeprom.h>
#endif
#include "proto.h" #include "proto.h"
#if defined(HID_USB_KBD) || defined(HID_USB_MOUSE)
#include "usb/hid.h" #include "usb/hid.h"
#endif
#ifdef HID_PS2_KBD
#include "ps2/hid.h" #include "ps2/hid.h"
#endif
// #define CMD_SERIAL Serial1 // #define CMD_SERIAL Serial1
@ -48,98 +46,176 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#ifdef HID_USB_KBD static UsbKeyboard *_usb_kbd = NULL;
UsbHidKeyboard hid_kbd; static UsbMouseAbsolute *_usb_mouse_abs = NULL;
#elif defined(HID_PS2_KBD) static UsbMouseRelative *_usb_mouse_rel = NULL;
Ps2HidKeyboard hid_kbd;
static Ps2Keyboard *_ps2_kbd = NULL;
#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 #endif
#ifdef HID_USB_MOUSE
UsbHidMouse hid_mouse; 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 # endif
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
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 cmdPong(const uint8_t *_=NULL) { // 0 bytes static void _cmdSetOutputs(const uint8_t *data) { // 1 bytes
return ( # ifdef HID_DYNAMIC
PROTO::PONG::PREFIX _setOutputs(data[0]);
| hid_kbd.getLedsAs(PROTO::PONG::CAPS, PROTO::PONG::SCROLL, PROTO::PONG::NUM) _reset_required = true;
| (hid_kbd.isOnline() ? 0 : PROTO::PONG::KEYBOARD_OFFLINE)
# ifdef HID_USB_MOUSE
| (hid_mouse.isOnline() ? 0 : PROTO::PONG::MOUSE_OFFLINE)
# endif # endif
);
} }
uint8_t cmdResetHid(const uint8_t *_) { // 0 bytes static void _cmdClearHid(const uint8_t *_) { // 0 bytes
# ifdef HID_USB_KBD if (_usb_kbd) {
hid_kbd.reset(); _usb_kbd->clear();
# endif }
# ifdef HID_USB_MOUSE if (_usb_mouse_abs) {
hid_mouse.reset(); _usb_mouse_abs->clear();
# endif } else if (_usb_mouse_rel) {
return cmdPong(); _usb_mouse_rel->clear();
}
} }
uint8_t cmdKeyEvent(const uint8_t *buffer) { // 2 bytes static void _cmdKeyEvent(const uint8_t *data) { // 2 bytes
hid_kbd.sendKey(buffer[0], buffer[1]); if (_usb_kbd) {
return cmdPong(); _usb_kbd->sendKey(data[0], data[1]);
} else if (_ps2_kbd) {
_ps2_kbd->sendKey(data[0], data[1]);
}
} }
uint8_t cmdMouseButtonEvent(const uint8_t *buffer) { // 2 bytes static void _cmdMouseButtonEvent(const uint8_t *data) { // 2 bytes
# ifdef HID_USB_MOUSE
uint8_t main_state = buffer[0];
uint8_t extra_state = buffer[1];
# define MOUSE_PAIR(_state, _button) \ # define MOUSE_PAIR(_state, _button) \
_state & PROTO::CMD::MOUSE::_button::SELECT, \ _state & PROTO::CMD::MOUSE::_button::SELECT, \
_state & PROTO::CMD::MOUSE::_button::STATE _state & PROTO::CMD::MOUSE::_button::STATE
hid_mouse.sendButtons( # define SEND_BUTTONS(_hid) \
MOUSE_PAIR(main_state, LEFT), _hid->sendButtons( \
MOUSE_PAIR(main_state, RIGHT), MOUSE_PAIR(data[0], LEFT), \
MOUSE_PAIR(main_state, MIDDLE), MOUSE_PAIR(data[0], RIGHT), \
MOUSE_PAIR(extra_state, EXTRA_UP), MOUSE_PAIR(data[0], MIDDLE), \
MOUSE_PAIR(extra_state, EXTRA_DOWN) 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 # undef MOUSE_PAIR
# endif
return cmdPong();
} }
uint8_t cmdMouseMoveEvent(const uint8_t *buffer) { // 4 bytes static void _cmdMouseMoveEvent(const uint8_t *data) { // 4 bytes
# ifdef HID_USB_MOUSE // See /kvmd/apps/otg/hid/keyboard.py for details
int x = (int)buffer[0] << 8; if (_usb_mouse_abs) {
x |= (int)buffer[1]; _usb_mouse_abs->sendMove(
x = (x + 32768) / 2; // See /kvmd/apps/otg/hid/keyboard.py for details (PROTO::merge8_int(data[0], data[1]) + 32768) / 2,
(PROTO::merge8_int(data[2], data[3]) + 32768) / 2
int y = (int)buffer[2] << 8; );
y |= (int)buffer[3]; }
y = (y + 32768) / 2; // See /kvmd/apps/otg/hid/keyboard.py for details
hid_mouse.sendMove(x, y);
# endif
return cmdPong();
} }
uint8_t cmdMouseWheelEvent(const uint8_t *buffer) { // 2 bytes static void _cmdMouseRelativeEvent(const uint8_t *data) { // 2 bytes
# ifdef HID_USB_MOUSE if (_usb_mouse_rel) {
hid_mouse.sendWheel(buffer[1]); // Y only, X is not supported _usb_mouse_rel->sendRelative(data[0], data[1]);
# endif }
return cmdPong();
} }
uint8_t handleCmdBuffer(const uint8_t *buffer) { // 8 bytes static void _cmdMouseWheelEvent(const uint8_t *data) { // 2 bytes
uint16_t crc = (uint16_t)buffer[6] << 8; // Y only, X is not supported
crc |= (uint16_t)buffer[7]; if (_usb_mouse_abs) {
_usb_mouse_abs->sendWheel(data[1]);
} else if (_usb_mouse_rel) {
_usb_mouse_rel->sendWheel(data[1]);
}
}
if (protoCrc16(buffer, 6) == crc) { static uint8_t _handleRequest(const uint8_t *data) { // 8 bytes
# define HANDLE(_handler) { return _handler(buffer + 2); } if (PROTO::crc16(data, 6) == PROTO::merge8(data[6], data[7])) {
switch (buffer[1]) { # define HANDLE(_handler) { _handler(data + 2); return PROTO::PONG::OK; }
case PROTO::CMD::RESET_HID: HANDLE(cmdResetHid); switch (data[1]) {
case PROTO::CMD::KEYBOARD::KEY: HANDLE(cmdKeyEvent); case PROTO::CMD::PING: return PROTO::PONG::OK;
case PROTO::CMD::MOUSE::BUTTON: HANDLE(cmdMouseButtonEvent); case PROTO::CMD::SET_OUTPUTS: HANDLE(_cmdSetOutputs);
case PROTO::CMD::MOUSE::MOVE: HANDLE(cmdMouseMoveEvent); case PROTO::CMD::CLEAR_HID: HANDLE(_cmdClearHid);
case PROTO::CMD::MOUSE::WHEEL: HANDLE(cmdMouseWheelEvent); case PROTO::CMD::KEYBOARD::KEY: HANDLE(_cmdKeyEvent);
case PROTO::CMD::PING: HANDLE(cmdPong); 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; case PROTO::CMD::REPEAT: return 0;
default: return PROTO::RESP::INVALID_ERROR; default: return PROTO::RESP::INVALID_ERROR;
} }
@ -151,33 +227,33 @@ uint8_t handleCmdBuffer(const uint8_t *buffer) { // 8 bytes
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#ifdef CMD_SPI #ifdef CMD_SPI
volatile uint8_t spi_in[8] = {0}; static volatile uint8_t _spi_in[8] = {0};
volatile uint8_t spi_in_index = 0; static volatile uint8_t _spi_in_index = 0;
volatile uint8_t spi_out[4] = {0}; static volatile uint8_t _spi_out[8] = {0};
volatile uint8_t spi_out_index = 0; static volatile uint8_t _spi_out_index = 0;
bool spiReady() { static bool _spiReady() {
return (!spi_out[0] && spi_in_index == 8); return (!_spi_out[0] && _spi_in_index == 8);
} }
void spiWrite(const uint8_t *buffer) { static void _spiWrite(const uint8_t *data) {
spi_out[3] = buffer[3]; // Меджик в нулевом байте разрешает начать ответ
spi_out[2] = buffer[2]; for (int index = 7; index >= 0; --index) {
spi_out[1] = buffer[1]; _spi_out[index] = data[index];
spi_out[0] = buffer[0]; // Меджик разрешает начать ответ }
} }
ISR(SPI_STC_vect) { ISR(SPI_STC_vect) {
uint8_t in = SPDR; uint8_t in = SPDR;
if (spi_out[0] && spi_out_index < 4) { if (_spi_out[0] && _spi_out_index < 8) {
SPDR = spi_out[spi_out_index]; SPDR = _spi_out[_spi_out_index];
if (!(SPSR & (1 << WCOL))) { if (!(SPSR & (1 << WCOL))) {
++spi_out_index; ++_spi_out_index;
if (spi_out_index == 4) { if (_spi_out_index == 8) {
spi_out_index = 0; _spi_out_index = 0;
spi_in_index = 0; _spi_in_index = 0;
spi_out[0] = 0; _spi_out[0] = 0;
} }
} }
} else { } else {
@ -185,11 +261,11 @@ ISR(SPI_STC_vect) {
if (!receiving && in == PROTO::MAGIC) { if (!receiving && in == PROTO::MAGIC) {
receiving = true; receiving = true;
} }
if (receiving && spi_in_index < 8) { if (receiving && _spi_in_index < 8) {
spi_in[spi_in_index] = in; _spi_in[_spi_in_index] = in;
++spi_in_index; ++_spi_in_index;
} }
if (spi_in_index == 8) { if (_spi_in_index == 8) {
receiving = false; receiving = false;
} }
SPDR = 0; 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; static uint8_t prev_code = PROTO::RESP::NONE;
if (code == 0) { if (code == 0) {
code = prev_code; // Repeat the last code code = prev_code; // Repeat the last code
@ -207,51 +283,71 @@ void sendCmdResponse(uint8_t code) {
prev_code = code; prev_code = code;
} }
uint8_t buffer[4]; uint8_t data[8] = {0};
buffer[0] = PROTO::MAGIC; data[0] = PROTO::MAGIC;
buffer[1] = code; if (code & PROTO::PONG::OK) {
uint16_t crc = protoCrc16(buffer, 2); data[1] = PROTO::PONG::OK;
buffer[2] = (uint8_t)(crc >> 8); # ifdef HID_DYNAMIC
buffer[3] = (uint8_t)(crc & 0xFF); 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 # ifdef CMD_SERIAL
CMD_SERIAL.write(buffer, 4); CMD_SERIAL.write(data, 8);
# elif defined(CMD_SPI) # elif defined(CMD_SPI)
spiWrite(buffer); _spiWrite(data);
# endif # endif
} }
void setup() { int main() {
hid_kbd.begin(); init(); // Embedded
# ifdef HID_USB_MOUSE initVariant(); // Arduino
hid_mouse.begin(); _initOutputs();
# endif
# ifdef CMD_SERIAL # ifdef CMD_SERIAL
CMD_SERIAL.begin(CMD_SERIAL_SPEED); 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(); unsigned long last = micros();
uint8_t buffer[8]; uint8_t buffer[8];
uint8_t index = 0; uint8_t index = 0;
# endif
while (true) { while (true) {
# ifdef HID_PS2_KBD # ifdef HID_WITH_PS2
hid_kbd.periodic(); if (_ps2_kbd) {
_ps2_kbd->periodic();
}
# endif # endif
# ifdef CMD_SERIAL
if (CMD_SERIAL.available() > 0) { if (CMD_SERIAL.available() > 0) {
buffer[index] = (uint8_t)CMD_SERIAL.read(); buffer[index] = (uint8_t)CMD_SERIAL.read();
if (index == 7) { if (index == 7) {
sendCmdResponse(handleCmdBuffer(buffer)); _sendResponse(_handleRequest(buffer));
index = 0; index = 0;
} else { } else {
last = micros(); last = micros();
@ -263,14 +359,27 @@ void loop() {
(now >= last && now - last > CMD_SERIAL_TIMEOUT) (now >= last && now - last > CMD_SERIAL_TIMEOUT)
|| (now < last && ((unsigned long)-1) - last + now > 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; index = 0;
} }
} }
}
# elif defined(CMD_SPI) # elif defined(CMD_SPI)
if (spiReady()) { pinMode(MISO, OUTPUT);
sendCmdResponse(handleCmdBuffer(spi_in)); SPCR = (1 << SPE) | (1 << SPIE); // Slave, SPI En, IRQ En
while (true) {
# ifdef HID_WITH_PS2
if (_ps2_kbd) {
_ps2_kbd->periodic();
} }
# endif # endif
if (_spiReady()) {
_sendResponse(_handleRequest((const uint8_t *)_spi_in));
} }
} }
# endif
return 0;
}

View File

@ -25,7 +25,6 @@
namespace PROTO { namespace PROTO {
const uint8_t MAGIC = 0x33; const uint8_t MAGIC = 0x33;
const uint16_t CRC_POLINOM = 0xA001;
namespace RESP { // Plain responses namespace RESP { // Plain responses
// const uint8_t OK = 0x20; // Legacy // const uint8_t OK = 0x20; // Legacy
@ -36,18 +35,40 @@ namespace PROTO {
}; };
namespace PONG { // Complex response namespace PONG { // Complex response
const uint8_t PREFIX = 0x80; const uint8_t OK = 0x80;
const uint8_t CAPS = 0b00000001; const uint8_t CAPS = 0b00000001;
const uint8_t SCROLL = 0b00000010; const uint8_t SCROLL = 0b00000010;
const uint8_t NUM = 0b00000100; const uint8_t NUM = 0b00000100;
const uint8_t KEYBOARD_OFFLINE = 0b00001000; const uint8_t KEYBOARD_OFFLINE = 0b00001000;
const uint8_t MOUSE_OFFLINE = 0b00010000; 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 { namespace CMD {
const uint8_t PING = 0x01; const uint8_t PING = 0x01;
const uint8_t REPEAT = 0x02; 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 { namespace KEYBOARD {
const uint8_t KEY = 0x11; const uint8_t KEY = 0x11;
@ -57,6 +78,7 @@ namespace PROTO {
const uint8_t MOVE = 0x12; const uint8_t MOVE = 0x12;
const uint8_t BUTTON = 0x13; const uint8_t BUTTON = 0x13;
const uint8_t WHEEL = 0x14; const uint8_t WHEEL = 0x14;
const uint8_t RELATIVE = 0x15;
namespace LEFT { namespace LEFT {
const uint8_t SELECT = 0b10000000; const uint8_t SELECT = 0b10000000;
const uint8_t STATE = 0b00001000; const uint8_t STATE = 0b00001000;
@ -79,10 +101,9 @@ namespace PROTO {
}; };
}; };
}; };
};
uint16_t crc16(const uint8_t *buffer, unsigned length) {
uint16_t protoCrc16(const uint8_t *buffer, unsigned length) { const uint16_t polinom = 0xA001;
uint16_t crc = 0xFFFF; uint16_t crc = 0xFFFF;
for (unsigned byte_count = 0; byte_count < length; ++byte_count) { for (unsigned byte_count = 0; byte_count < length; ++byte_count) {
@ -92,9 +113,23 @@ uint16_t protoCrc16(const uint8_t *buffer, unsigned length) {
crc = crc >> 1; crc = crc >> 1;
} else { } else {
crc = crc >> 1; crc = crc >> 1;
crc = crc ^ PROTO::CRC_POLINOM; crc = crc ^ polinom;
} }
} }
} }
return crc; 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);
}
};

View File

@ -27,24 +27,20 @@
#include "keymap.h" #include "keymap.h"
// #define PS2_KBD_CLOCK_PIN 7 // #define HID_PS2_KBD_CLOCK_PIN 7
// #define PS2_KBD_DATA_PIN 5 // #define HID_PS2_KBD_DATA_PIN 5
class Ps2HidKeyboard { class Ps2Keyboard {
// https://wiki.osdev.org/PS/2_Keyboard // https://wiki.osdev.org/PS/2_Keyboard
public: 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() { void begin() {
_dev.keyboard_init(); _dev.keyboard_init();
} }
bool isOnline() {
return true;
}
void periodic() { void periodic() {
_dev.keyboard_handle(&_leds); _dev.keyboard_handle(&_leds);
} }
@ -57,7 +53,7 @@ class Ps2HidKeyboard {
if (ps2_type != PS2_KEY_TYPE_UNKNOWN) { if (ps2_type != PS2_KEY_TYPE_UNKNOWN) {
// Не отправлялась часть нажатий. Когда clock на нуле, комп не принимает ничего от клавы. // Не отправлялась часть нажатий. Когда clock на нуле, комп не принимает ничего от клавы.
// Этот костыль понижает процент пропущенных нажатий. // Этот костыль понижает процент пропущенных нажатий.
while (digitalRead(PS2_KBD_CLOCK_PIN) == 0) {}; while (digitalRead(HID_PS2_KBD_CLOCK_PIN) == 0) {};
if (state) { if (state) {
switch (ps2_type) { switch (ps2_type) {
case PS2_KEY_TYPE_REG: _dev.keyboard_press(ps2_code); break; 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 getLedsAs(uint8_t caps, uint8_t scroll, uint8_t num) {
uint8_t result = 0; uint8_t result = 0;

View File

@ -29,113 +29,158 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#ifdef CHECK_ENDPOINT #ifdef HID_USB_CHECK_ENDPOINT
static bool _checkEndpoint(uint8_t ep) {
// https://github.com/arduino/ArduinoCore-avr/blob/2f67c916f6ab6193c404eebe22efe901e0f9542d/cores/arduino/USBCore.cpp#L249 // 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 // 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; # define CLS_GET_OFFLINE_AS(_hid) \
cli(); uint8_t getOfflineAs(uint8_t offline) { \
UENUM = ep & 7; uint8_t ep = _hid.getPluggedEndpoint(); \
bool rw_allowed = UEINTX & (1 << RWAL); uint8_t intr_state = SREG; \
SREG = intr_state; cli(); \
return rw_allowed; UENUM = ep & 7; \
bool rw_allowed = UEINTX & (1 << RWAL); \
SREG = intr_state; \
if (rw_allowed) { \
return 0; \
} \
return offline; \
} }
# define CHECK_HID_EP { if (!isOnline()) return; } # define CHECK_HID_EP { if (getOfflineAs(1)) return; }
#else #else
# define CLS_GET_OFFLINE_AS(_hid) \
uint8_t getOfflineAs(uint8_t offline) { \
return 0; \
}
# define CHECK_HID_EP # define CHECK_HID_EP
#endif #endif
class UsbHidKeyboard { class UsbKeyboard {
public: public:
UsbHidKeyboard() {} UsbKeyboard() {}
void begin() { void begin() {
BootKeyboard.begin(); _kbd.begin();
} }
bool isOnline() { void clear() {
# ifdef CHECK_ENDPOINT _kbd.releaseAll();
return _checkEndpoint(BootKeyboard.getPluggedEndpoint());
# else
return true;
# endif
}
void reset() {
BootKeyboard.releaseAll();
} }
void sendKey(uint8_t code, bool state) { void sendKey(uint8_t code, bool state) {
CHECK_HID_EP; CHECK_HID_EP;
KeyboardKeycode usb_code = keymapUsb(code); KeyboardKeycode usb_code = keymapUsb(code);
if (usb_code != KEY_ERROR_UNDEFINED) { if (usb_code != KEY_ERROR_UNDEFINED) {
if (state) BootKeyboard.press(usb_code); if (state) _kbd.press(usb_code);
else BootKeyboard.release(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 getLedsAs(uint8_t caps, uint8_t scroll, uint8_t num) {
uint8_t leds = BootKeyboard.getLeds(); uint8_t leds = _kbd.getLeds();
uint8_t result = 0; uint8_t result = 0;
if (leds & LED_CAPS_LOCK) result |= caps; if (leds & LED_CAPS_LOCK) result |= caps;
if (leds & LED_SCROLL_LOCK) result |= scroll; if (leds & LED_SCROLL_LOCK) result |= scroll;
if (leds & LED_NUM_LOCK) result |= num; if (leds & LED_NUM_LOCK) result |= num;
return result; 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: public:
UsbHidMouse() {} UsbMouseAbsolute() {}
void begin() { void begin() {
SingleAbsoluteMouse.begin(); _mouse.begin();
} }
bool isOnline() { void clear() {
# ifdef CHECK_ENDPOINT _mouse.releaseAll();
return _checkEndpoint(SingleAbsoluteMouse.getPluggedEndpoint());
# else
return true;
# endif
} }
void reset() { CLS_SEND_BUTTONS
SingleAbsoluteMouse.releaseAll();
}
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 sendMove(int x, int y) { void sendMove(int x, int y) {
CHECK_HID_EP; CHECK_HID_EP;
SingleAbsoluteMouse.moveTo(x, y); _mouse.moveTo(x, y);
} }
void sendWheel(int delta_y) { void sendWheel(int delta_y) {
CHECK_HID_EP;
// delta_x is not supported by hid-project now // 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: private:
SingleAbsoluteMouse_ _mouse;
void _sendButton(uint8_t button, bool state) { void _sendButton(uint8_t button, bool state) {
CHECK_HID_EP; CHECK_HID_EP;
if (state) SingleAbsoluteMouse.press(button); if (state) _mouse.press(button);
else SingleAbsoluteMouse.release(button); else _mouse.release(button);
} }
}; };
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
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) _mouse.press(button);
else _mouse.release(button);
}
};
#undef CLS_SEND_BUTTONS
#undef CLS_GET_OFFLINE_AS
#undef CHECK_HID_EP #undef CHECK_HID_EP

View File

@ -25,7 +25,9 @@ import queue
from typing import Tuple from typing import Tuple
from typing import Dict from typing import Dict
from typing import Type
from typing import TypeVar from typing import TypeVar
from typing import Generic
from typing import Optional from typing import Optional
from . import aiotools from . import aiotools
@ -71,14 +73,19 @@ class AioProcessNotifier:
# ===== # =====
class AioSharedFlags: _SharedFlagT = TypeVar("_SharedFlagT", int, bool)
class AioSharedFlags(Generic[_SharedFlagT]):
def __init__( def __init__(
self, self,
initial: Dict[str, bool], initial: Dict[str, _SharedFlagT],
notifier: AioProcessNotifier, notifier: AioProcessNotifier,
type: Type[_SharedFlagT]=bool, # pylint: disable=redefined-builtin
) -> None: ) -> None:
self.__notifier = notifier self.__notifier = notifier
self.__type: Type[_SharedFlagT] = type
self.__flags = { self.__flags = {
key: multiprocessing.RawValue("i", int(value)) # type: ignore key: multiprocessing.RawValue("i", int(value)) # type: ignore
@ -87,7 +94,7 @@ class AioSharedFlags:
self.__lock = multiprocessing.Lock() self.__lock = multiprocessing.Lock()
def update(self, **kwargs: bool) -> None: def update(self, **kwargs: _SharedFlagT) -> None:
changed = False changed = False
with self.__lock: with self.__lock:
for (key, value) in kwargs.items(): for (key, value) in kwargs.items():
@ -98,12 +105,12 @@ class AioSharedFlags:
if changed: if changed:
self.__notifier.notify() self.__notifier.notify()
async def get(self) -> Dict[str, bool]: async def get(self) -> Dict[str, _SharedFlagT]:
return (await aiotools.run_async(self.__inner_get)) return (await aiotools.run_async(self.__inner_get))
def __inner_get(self) -> Dict[str, bool]: def __inner_get(self) -> Dict[str, _SharedFlagT]:
with self.__lock: with self.__lock:
return { return {
key: bool(shared.value) key: self.__type(shared.value)
for (key, shared) in self.__flags.items() for (key, shared) in self.__flags.items()
} }

View File

@ -136,6 +136,19 @@ class _MouseMoveEvent(_BaseEvent):
return struct.pack(">Bhh", 0x12, self.to_x, self.to_y) return struct.pack(">Bhh", 0x12, self.to_x, self.to_y)
@dataclasses.dataclass(frozen=True)
class _MouseRelativeEvent(_BaseEvent):
delta_x: int
delta_y: int
def __post_init__(self) -> None:
assert -127 <= self.delta_x <= 127
assert -127 <= self.delta_y <= 127
def make_command(self) -> bytes:
return struct.pack(">Bbbxx", 0x15, self.delta_x, self.delta_y)
@dataclasses.dataclass(frozen=True) @dataclasses.dataclass(frozen=True)
class _MouseWheelEvent(_BaseEvent): class _MouseWheelEvent(_BaseEvent):
delta_x: int delta_x: int
@ -196,12 +209,9 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
self.__notifier = aiomulti.AioProcessNotifier() self.__notifier = aiomulti.AioProcessNotifier()
self.__state_flags = aiomulti.AioSharedFlags({ self.__state_flags = aiomulti.AioSharedFlags({
"keyboard_online": True, "online": 0,
"mouse_online": True, "status": 0,
"caps": False, }, self.__notifier, type=int)
"scroll": False,
"num": False,
}, self.__notifier)
self.__stop_event = multiprocessing.Event() self.__stop_event = multiprocessing.Event()
@ -226,19 +236,51 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
async def get_state(self) -> Dict: async def get_state(self) -> Dict:
state = await self.__state_flags.get() state = await self.__state_flags.get()
online = bool(state["online"])
pong = (state["status"] >> 16) & 0xFF
outputs = (state["status"] >> 8) & 0xFF
features = state["status"] & 0xFF
absolute = True
if online and (outputs & 0b00111000) in [0b00010000, 0b00011000]:
absolute = False
keyboard_outputs: Dict = {"available": {}, "active": ""}
mouse_outputs: Dict = {"available": {}, "active": ""}
if outputs & 0b10000000: # Dynamic
if features & 0b00000001: # USB
keyboard_outputs["available"]["usb"] = {"name": "USB"}
mouse_outputs["available"]["usb_abs"] = {"name": "USB", "absolute": True}
mouse_outputs["available"]["usb_rel"] = {"name": "USB Relative", "absolute": False}
if features & 0b00000010: # PS/2
keyboard_outputs["available"]["ps2"] = {"name": "PS/2"}
mouse_outputs["available"]["ps2"] = {"name": "PS/2"}
keyboard_outputs["active"] = {
0b00000001: "usb",
0b00000011: "ps2",
}.get(outputs & 0b00000111, "")
mouse_outputs["active"] = {
0b00001000: "usb_abs",
0b00010000: "usb_rel",
0b00011000: "ps2",
}.get(outputs & 0b00111000, "")
return { return {
"online": (state["keyboard_online"] and state["mouse_online"]), "online": online,
"keyboard": { "keyboard": {
"online": state["keyboard_online"], "online": (online and not (pong & 0b00001000)),
"leds": { "leds": {
"caps": state["caps"], "caps": bool(pong & 0b00000001),
"scroll": state["scroll"], "scroll": bool(pong & 0b00000010),
"num": state["num"], "num": bool(pong & 0b00000100),
}, },
"outputs": keyboard_outputs,
}, },
"mouse": { "mouse": {
"online": state["mouse_online"], "online": (online and not (pong & 0b00010000)),
"absolute": True, "absolute": absolute,
"outputs": mouse_outputs,
}, },
} }
@ -287,8 +329,7 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
self.__queue_event(_MouseMoveEvent(to_x, to_y)) self.__queue_event(_MouseMoveEvent(to_x, to_y))
def send_mouse_relative_event(self, delta_x: int, delta_y: int) -> None: def send_mouse_relative_event(self, delta_x: int, delta_y: int) -> None:
_ = delta_x # No relative events yet self.__queue_event(_MouseRelativeEvent(delta_x, delta_y))
_ = delta_y
def send_mouse_wheel_event(self, delta_x: int, delta_y: int) -> None: def send_mouse_wheel_event(self, delta_x: int, delta_y: int) -> None:
self.__queue_event(_MouseWheelEvent(delta_x, delta_y)) self.__queue_event(_MouseWheelEvent(delta_x, delta_y))
@ -350,8 +391,8 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
read_retries -= 1 read_retries -= 1
raise _TempRequestError(f"No response from HID: request={request!r}") raise _TempRequestError(f"No response from HID: request={request!r}")
assert len(response) == 4, response assert len(response) in (4, 8), response
if self.__make_crc16(response[-4:-2]) != struct.unpack(">H", response[-2:])[0]: if self.__make_crc16(response[:-2]) != struct.unpack(">H", response[-2:])[0]:
request = self.__make_request(b"\x02\x00\x00\x00\x00") # Repeat an answer request = self.__make_request(b"\x02\x00\x00\x00\x00") # Repeat an answer
raise _TempRequestError("Invalid response CRC; requesting response again ...") raise _TempRequestError("Invalid response CRC; requesting response again ...")
@ -368,7 +409,7 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
self.__set_state_online(True) self.__set_state_online(True)
return True return True
elif code & 0x80: # Pong/Done with state elif code & 0x80: # Pong/Done with state
self.__set_state_code(code) self.__set_state_pong(response)
return True return True
raise _TempRequestError(f"Invalid response from HID: request={request!r}; code=0x{code:02X}") raise _TempRequestError(f"Invalid response from HID: request={request!r}; code=0x{code:02X}")
@ -401,19 +442,13 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
return error_retval return error_retval
def __set_state_online(self, online: bool) -> None: def __set_state_online(self, online: bool) -> None:
self.__state_flags.update( self.__state_flags.update(online=int(online))
keyboard_online=online,
mouse_online=online,
)
def __set_state_code(self, code: int) -> None: def __set_state_pong(self, data: bytes) -> None:
self.__state_flags.update( status = data[1] << 16
keyboard_online=(not (code & 0b00001000)), if len(data) > 4:
mouse_online=(not (code & 0b00010000)), status |= (data[2] << 8) | data[3]
caps=bool(code & 0b00000001), self.__state_flags.update(online=1, status=status)
scroll=bool(code & 0b00000010),
num=bool(code & 0b00000100),
)
def __send_request(self, conn: BasePhyConnection, request: bytes) -> bytes: def __send_request(self, conn: BasePhyConnection, request: bytes) -> bytes:
if not self.__noop: if not self.__noop:

View File

@ -131,8 +131,9 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
async def get_state(self) -> Dict: async def get_state(self) -> Dict:
state = await self.__server.get_state() state = await self.__server.get_state()
outputs: Dict = {"available": {}, "active": ""}
return { return {
"online": state["online"], "online": True,
"keyboard": { "keyboard": {
"online": state["online"], "online": state["online"],
"leds": { "leds": {
@ -140,10 +141,12 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
"scroll": state["scroll"], "scroll": state["scroll"],
"num": state["num"], "num": state["num"],
}, },
"outputs": outputs,
}, },
"mouse": { "mouse": {
"online": state["online"], "online": state["online"],
"absolute": False, "absolute": False,
"outputs": outputs,
}, },
} }

View File

@ -89,8 +89,9 @@ class Plugin(BaseHid):
async def get_state(self) -> Dict: async def get_state(self) -> Dict:
keyboard_state = await self.__keyboard_proc.get_state() keyboard_state = await self.__keyboard_proc.get_state()
mouse_state = await self.__mouse_proc.get_state() mouse_state = await self.__mouse_proc.get_state()
outputs: Dict = {"available": {}, "active": ""}
return { return {
"online": (keyboard_state["online"] and mouse_state["online"]), "online": True,
"keyboard": { "keyboard": {
"online": keyboard_state["online"], "online": keyboard_state["online"],
"leds": { "leds": {
@ -98,8 +99,9 @@ class Plugin(BaseHid):
"scroll": keyboard_state["scroll"], "scroll": keyboard_state["scroll"],
"num": keyboard_state["num"], "num": keyboard_state["num"],
}, },
"outputs": outputs,
}, },
"mouse": mouse_state, "mouse": {**mouse_state, "outputs": outputs},
} }
async def poll_state(self) -> AsyncGenerator[Dict, None]: async def poll_state(self) -> AsyncGenerator[Dict, None]:

View File

@ -51,7 +51,10 @@ class _SerialPhyConnection(BasePhyConnection):
if self.__tty.in_waiting: if self.__tty.in_waiting:
self.__tty.read_all() self.__tty.read_all()
assert self.__tty.write(request) == 8 assert self.__tty.write(request) == 8
return self.__tty.read(4) data = self.__tty.read(4)
if data[0] == 0x34: # New response protocol
data += self.__tty.read(4)
return data
class _SerialPhy(BasePhy): class _SerialPhy(BasePhy):

View File

@ -67,7 +67,7 @@ class _SpiPhyConnection(BasePhyConnection):
assert request[0] == 0x33 assert request[0] == 0x33
deadline_ts = time.monotonic() + self.__read_timeout deadline_ts = time.monotonic() + self.__read_timeout
dummy = b"\x00" * 8 dummy = b"\x00" * 10
while time.monotonic() < deadline_ts: while time.monotonic() < deadline_ts:
if bytes(self.__xfer(dummy)) == dummy: if bytes(self.__xfer(dummy)) == dummy:
break break
@ -81,15 +81,15 @@ class _SpiPhyConnection(BasePhyConnection):
deadline_ts = time.monotonic() + self.__read_timeout deadline_ts = time.monotonic() + self.__read_timeout
found = False found = False
while time.monotonic() < deadline_ts: while time.monotonic() < deadline_ts:
for byte in self.__xfer(b"\x00" * (5 - len(response))): for byte in self.__xfer(b"\x00" * (9 - len(response))):
if not found: if not found:
if byte != 0x33: if byte == 0:
continue continue
found = True found = True
response.append(byte) response.append(byte)
if len(response) == 4: if len(response) == 8:
break break
if len(response) == 4: if len(response) == 8:
break break
else: else:
get_logger(0).error("SPI timeout reached while responce waiting") get_logger(0).error("SPI timeout reached while responce waiting")