summaryrefslogtreecommitdiff
path: root/hid/src
diff options
context:
space:
mode:
authorMaxim Devaev <[email protected]>2023-07-31 02:17:23 +0300
committerMaxim Devaev <[email protected]>2023-07-31 02:17:23 +0300
commit1a8f98a64f9480c1062225e0fc994ceac4ba346d (patch)
tree934ac95c6c0774d6ac512860905d4d2454b0b2aa /hid/src
parentcf44668af998b114fbddc8fa41b47193b606c064 (diff)
moved arduino hid to hid/arduino
Diffstat (limited to 'hid/src')
-rw-r--r--hid/src/main.cpp253
-rw-r--r--hid/src/outputs.h122
-rw-r--r--hid/src/proto.h142
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);
- }
-};