summaryrefslogtreecommitdiff
path: root/hid/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hid/src/main.cpp')
-rw-r--r--hid/src/main.cpp388
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;
}