diff options
author | Maxim Devaev <[email protected]> | 2023-07-31 02:17:23 +0300 |
---|---|---|
committer | Maxim Devaev <[email protected]> | 2023-07-31 02:17:23 +0300 |
commit | 1a8f98a64f9480c1062225e0fc994ceac4ba346d (patch) | |
tree | 934ac95c6c0774d6ac512860905d4d2454b0b2aa /hid/src | |
parent | cf44668af998b114fbddc8fa41b47193b606c064 (diff) |
moved arduino hid to hid/arduino
Diffstat (limited to 'hid/src')
-rw-r--r-- | hid/src/main.cpp | 253 | ||||
-rw-r--r-- | hid/src/outputs.h | 122 | ||||
-rw-r--r-- | hid/src/proto.h | 142 |
3 files changed, 0 insertions, 517 deletions
diff --git a/hid/src/main.cpp b/hid/src/main.cpp deleted file mode 100644 index c1539106..00000000 --- a/hid/src/main.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/***************************************************************************** -# # -# KVMD - The main PiKVM daemon. # -# # -# Copyright (C) 2018-2023 Maxim Devaev <[email protected]> # -# # -# This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see <https://www.gnu.org/licenses/>. # -# # -*****************************************************************************/ - - -#include <Arduino.h> - -#include "tools.h" -#include "proto.h" -#include "board.h" -#include "outputs.h" -#ifdef AUM -# include "aum.h" -#endif - - -static DRIVERS::Connection *_conn; -static DRIVERS::Board *_board; -static Outputs _out; - -#ifdef HID_DYNAMIC -# define RESET_TIMEOUT 500000 -static bool _reset_required = false; -static unsigned long _reset_timestamp; -#endif - - -// ----------------------------------------------------------------------------- -#ifdef HID_DYNAMIC -static void _resetRequest() { - _reset_required = true; - _reset_timestamp = micros(); -} -#endif - -static void _cmdSetKeyboard(const uint8_t *data) { // 1 bytes -# ifdef HID_DYNAMIC - _out.writeOutputs(PROTO::OUTPUTS1::KEYBOARD::MASK, data[0], false); - _resetRequest(); -# endif -} - -static void _cmdSetMouse(const uint8_t *data) { // 1 bytes -# ifdef HID_DYNAMIC - _out.writeOutputs(PROTO::OUTPUTS1::MOUSE::MASK, data[0], false); - _resetRequest(); -# endif -} - -static void _cmdSetConnected(const uint8_t *data) { // 1 byte -# ifdef AUM - aumSetUsbConnected(data[0]); -# endif -} - -static void _cmdClearHid(const uint8_t *_) { // 0 bytes - _out.kbd->clear(); - _out.mouse->clear(); -} - -static void _cmdKeyEvent(const uint8_t *data) { // 2 bytes - _out.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 - _out.mouse->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) - ); -# undef MOUSE_PAIR -} - -static void _cmdMouseMoveEvent(const uint8_t *data) { // 4 bytes - // See /kvmd/apps/otg/hid/keyboard.py for details - _out.mouse->sendMove( - PROTO::merge8_int(data[0], data[1]), - PROTO::merge8_int(data[2], data[3]) - ); -} - -static void _cmdMouseRelativeEvent(const uint8_t *data) { // 2 bytes - _out.mouse->sendRelative(data[0], data[1]); -} - -static void _cmdMouseWheelEvent(const uint8_t *data) { // 2 bytes - // Y only, X is not supported - _out.mouse->sendWheel(data[1]); -} - -static uint8_t _handleRequest(const uint8_t *data) { // 8 bytes - _board->updateStatus(DRIVERS::RX_DATA); - // FIXME: See kvmd/kvmd#80 - // Should input buffer be cleared in this case? - if (data[0] == PROTO::MAGIC && 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::SET_CONNECTED: HANDLE(_cmdSetConnected); - 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; - } -# undef HANDLE - } - return PROTO::RESP::CRC_ERROR; -} - - -// ----------------------------------------------------------------------------- -static void _sendResponse(uint8_t code) { - static uint8_t prev_code = PROTO::RESP::NONE; - if (code == 0) { - code = prev_code; // Repeat the last code - } else { - prev_code = code; - } - - uint8_t response[8] = {0}; - response[0] = PROTO::MAGIC_RESP; - if (code & PROTO::PONG::OK) { - response[1] = PROTO::PONG::OK; -# ifdef HID_DYNAMIC - if (_reset_required) { - response[1] |= PROTO::PONG::RESET_REQUIRED; - if (is_micros_timed_out(_reset_timestamp, RESET_TIMEOUT)) { - _board->reset(); - } - } - response[2] = PROTO::OUTPUTS1::DYNAMIC; -# endif - if (_out.kbd->getType() != DRIVERS::DUMMY) { - if(_out.kbd->isOffline()) { - response[1] |= PROTO::PONG::KEYBOARD_OFFLINE; - } else { - _board->updateStatus(DRIVERS::KEYBOARD_ONLINE); - } - DRIVERS::KeyboardLedsState leds = _out.kbd->getLeds(); - response[1] |= (leds.caps ? PROTO::PONG::CAPS : 0); - response[1] |= (leds.num ? PROTO::PONG::NUM : 0); - response[1] |= (leds.scroll ? PROTO::PONG::SCROLL : 0); - switch (_out.kbd->getType()) { - case DRIVERS::USB_KEYBOARD: - response[2] |= PROTO::OUTPUTS1::KEYBOARD::USB; - break; - case DRIVERS::PS2_KEYBOARD: - response[2] |= PROTO::OUTPUTS1::KEYBOARD::PS2; - break; - } - } - if (_out.mouse->getType() != DRIVERS::DUMMY) { - if(_out.mouse->isOffline()) { - response[1] |= PROTO::PONG::MOUSE_OFFLINE; - } else { - _board->updateStatus(DRIVERS::MOUSE_ONLINE); - } - switch (_out.mouse->getType()) { - case DRIVERS::USB_MOUSE_ABSOLUTE_WIN98: - response[2] |= PROTO::OUTPUTS1::MOUSE::USB_WIN98; - break; - case DRIVERS::USB_MOUSE_ABSOLUTE: - response[2] |= PROTO::OUTPUTS1::MOUSE::USB_ABS; - break; - case DRIVERS::USB_MOUSE_RELATIVE: - response[2] |= PROTO::OUTPUTS1::MOUSE::USB_REL; - break; - } - } // TODO: ps2 -# ifdef AUM - response[3] |= PROTO::OUTPUTS2::CONNECTABLE; - if (aumIsUsbConnected()) { - response[3] |= PROTO::OUTPUTS2::CONNECTED; - } -# endif -# ifdef HID_WITH_USB - response[3] |= PROTO::OUTPUTS2::HAS_USB; -# ifdef HID_WITH_USB_WIN98 - response[3] |= PROTO::OUTPUTS2::HAS_USB_WIN98; -# endif -# endif -# ifdef HID_WITH_PS2 - response[3] |= PROTO::OUTPUTS2::HAS_PS2; -# endif - } else { - response[1] = code; - } - PROTO::split16(PROTO::crc16(response, 6), &response[6], &response[7]); - - _conn->write(response, 8); -} - -static void _onTimeout() { - _sendResponse(PROTO::RESP::TIMEOUT_ERROR); -} - -static void _onData(const uint8_t *data, size_t size) { - _sendResponse(_handleRequest(data)); -} - -void setup() { - _out.initOutputs(); - -# ifdef AUM - aumInit(); -# endif - - _conn = DRIVERS::Factory::makeConnection(DRIVERS::CONNECTION); - _conn->onTimeout(_onTimeout); - _conn->onData(_onData); - _conn->begin(); - - _board = DRIVERS::Factory::makeBoard(DRIVERS::BOARD); -} - -void loop() { -# ifdef AUM - aumProxyUsbVbus(); -# endif - - _out.kbd->periodic(); - _out.mouse->periodic(); - _board->periodic(); - _conn->periodic(); -} diff --git a/hid/src/outputs.h b/hid/src/outputs.h deleted file mode 100644 index dd9008f3..00000000 --- a/hid/src/outputs.h +++ /dev/null @@ -1,122 +0,0 @@ -/***************************************************************************** -# # -# KVMD - The main PiKVM daemon. # -# # -# Copyright (C) 2018-2023 Maxim Devaev <[email protected]> # -# # -# This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see <https://www.gnu.org/licenses/>. # -# # -*****************************************************************************/ - - -#include "factory.h" -#include "proto.h" - - -class Outputs { - public: - 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]); - _storage->updateBlock(data, 0, 8); - } - - void initOutputs() { -# ifdef HID_DYNAMIC - _storage = DRIVERS::Factory::makeStorage(DRIVERS::NON_VOLATILE_STORAGE); -# else - _storage = DRIVERS::Factory::makeStorage(DRIVERS::DUMMY); -# endif - - int outputs = _readOutputs(); - if (outputs < 0) { - outputs = 0; -# if defined(HID_WITH_USB) && defined(HID_SET_USB_KBD) - outputs |= PROTO::OUTPUTS1::KEYBOARD::USB; -# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_KBD) - outputs |= PROTO::OUTPUTS1::KEYBOARD::PS2; -# endif -# if defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_ABS) - outputs |= PROTO::OUTPUTS1::MOUSE::USB_ABS; -# elif defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_REL) - outputs |= PROTO::OUTPUTS1::MOUSE::USB_REL; -# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_MOUSE) - outputs |= PROTO::OUTPUTS1::MOUSE::PS2; -# elif defined(HID_WITH_USB) && defined(HID_WITH_USB_WIN98) && defined(HID_SET_USB_MOUSE_WIN98) - outputs |= PROTO::OUTPUTS1::MOUSE::USB_WIN98; -# endif - writeOutputs(0xFF, outputs, true); - } - - uint8_t kbd_type = outputs & PROTO::OUTPUTS1::KEYBOARD::MASK; - switch (kbd_type) { - case PROTO::OUTPUTS1::KEYBOARD::USB: - kbd = DRIVERS::Factory::makeKeyboard(DRIVERS::USB_KEYBOARD); - break; - case PROTO::OUTPUTS1::KEYBOARD::PS2: - kbd = DRIVERS::Factory::makeKeyboard(DRIVERS::PS2_KEYBOARD); - break; - default: - kbd = DRIVERS::Factory::makeKeyboard(DRIVERS::DUMMY); - break; - } - - uint8_t mouse_type = outputs & PROTO::OUTPUTS1::MOUSE::MASK; - switch (mouse_type) { - case PROTO::OUTPUTS1::MOUSE::USB_ABS: - mouse = DRIVERS::Factory::makeMouse(DRIVERS::USB_MOUSE_ABSOLUTE); - break; - case PROTO::OUTPUTS1::MOUSE::USB_WIN98: - mouse = DRIVERS::Factory::makeMouse(DRIVERS::USB_MOUSE_ABSOLUTE_WIN98); - break; - case PROTO::OUTPUTS1::MOUSE::USB_REL: - mouse = DRIVERS::Factory::makeMouse(DRIVERS::USB_MOUSE_RELATIVE); - break; - default: - mouse = DRIVERS::Factory::makeMouse(DRIVERS::DUMMY); - break; - } - -# ifdef ARDUINO_ARCH_AVR - USBDevice.attach(); -# endif - - kbd->begin(); - mouse->begin(); - } - - DRIVERS::Keyboard *kbd = nullptr; - DRIVERS::Mouse *mouse = nullptr; - - private: - int _readOutputs(void) { - uint8_t data[8]; - _storage->readBlock(data, 0, 8); - if (data[0] != PROTO::MAGIC || PROTO::crc16(data, 6) != PROTO::merge8(data[6], data[7])) { - return -1; - } - return data[1]; - } - - DRIVERS::Storage *_storage = nullptr; -}; diff --git a/hid/src/proto.h b/hid/src/proto.h deleted file mode 100644 index 5fbdd49c..00000000 --- a/hid/src/proto.h +++ /dev/null @@ -1,142 +0,0 @@ -/***************************************************************************** -# # -# KVMD - The main PiKVM daemon. # -# # -# Copyright (C) 2018-2023 Maxim Devaev <[email protected]> # -# # -# This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see <https://www.gnu.org/licenses/>. # -# # -*****************************************************************************/ - - -#pragma once - - -namespace PROTO { - const uint8_t MAGIC = 0x33; - const uint8_t MAGIC_RESP = 0x34; - - namespace RESP { // Plain responses - // const uint8_t OK = 0x20; // Legacy - const uint8_t NONE = 0x24; - const uint8_t CRC_ERROR = 0x40; - const uint8_t INVALID_ERROR = 0x45; - const uint8_t TIMEOUT_ERROR = 0x48; - }; - - namespace PONG { // Complex response - 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 OUTPUTS1 { // 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; - const uint8_t USB_WIN98 = 0b00100000; - }; - }; - - namespace OUTPUTS2 { // Complex response - const uint8_t CONNECTABLE = 0b10000000; - const uint8_t CONNECTED = 0b01000000; - const uint8_t HAS_USB = 0b00000001; - const uint8_t HAS_PS2 = 0b00000010; - const uint8_t HAS_USB_WIN98 = 0b00000100; - } - - namespace CMD { - const uint8_t PING = 0x01; - const uint8_t REPEAT = 0x02; - const uint8_t SET_KEYBOARD = 0x03; - const uint8_t SET_MOUSE = 0x04; - const uint8_t SET_CONNECTED = 0x05; - 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 RELATIVE = 0x15; - namespace LEFT { - const uint8_t SELECT = 0b10000000; - const uint8_t STATE = 0b00001000; - }; - namespace RIGHT { - const uint8_t SELECT = 0b01000000; - const uint8_t STATE = 0b00000100; - }; - namespace MIDDLE { - const uint8_t SELECT = 0b00100000; - const uint8_t STATE = 0b00000010; - }; - namespace EXTRA_UP { - const uint8_t SELECT = 0b10000000; - const uint8_t STATE = 0b00001000; - }; - namespace EXTRA_DOWN { - const uint8_t SELECT = 0b01000000; - const uint8_t STATE = 0b00000100; - }; - }; - }; - - uint16_t crc16(const uint8_t *buffer, unsigned length) { - const uint16_t polinom = 0xA001; - 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 ^ 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); - } -}; |