mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-28 16:41:52 +08:00
moved arduino hid to hid/arduino
This commit is contained in:
6
hid/arduino/.gitignore
vendored
Normal file
6
hid/arduino/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/.platformio/
|
||||
/.pio/
|
||||
/.current
|
||||
/.vscode/
|
||||
/.config
|
||||
/platformio.ini
|
||||
51
hid/arduino/Makefile
Normal file
51
hid/arduino/Makefile
Normal file
@@ -0,0 +1,51 @@
|
||||
serial:
|
||||
make _build E=serial C=avr
|
||||
spi:
|
||||
make _build E=spi C=avr
|
||||
aum:
|
||||
make _build E=aum C=avr
|
||||
stm32:
|
||||
platformio run --environment patch --project-conf platformio-stm32.ini
|
||||
make _build E=serial C=stm32
|
||||
_build:
|
||||
rm -f .current .config
|
||||
platformio run --environment $(E) --project-conf platformio-$(C).ini
|
||||
echo -n $(E) > .current
|
||||
echo -n $(C) > .config
|
||||
|
||||
# Added to easy test all builds
|
||||
_build_all: aum spi serial stm32
|
||||
rm -f .current .config
|
||||
|
||||
install: upload
|
||||
upload:
|
||||
$(eval $@_CURRENT := $(shell cat .current))
|
||||
$(eval $@_CONFIG := $(shell cat .config))
|
||||
bash -ex -c " \
|
||||
current=`cat .current`; \
|
||||
if [ '$($@_CURRENT)' == 'spi' ] || [ '$($@_CURRENT)' == 'aum' ]; then \
|
||||
gpioset 0 25=1; \
|
||||
gpioset 0 25=0; \
|
||||
fi \
|
||||
"
|
||||
platformio run --environment '$($@_CURRENT)' --project-conf 'platformio-$($@_CONFIG).ini' --target upload
|
||||
|
||||
|
||||
bootloader-spi: install-bootloader-spi
|
||||
install-bootloader-spi: upload-bootloader-spi
|
||||
upload-bootloader-spi:
|
||||
platformio run --environment bootloader_spi --project-conf platformio-avr.ini --target bootloader
|
||||
|
||||
|
||||
update:
|
||||
platformio platform update
|
||||
|
||||
|
||||
clean-all: clean
|
||||
rm -rf .platformio
|
||||
clean:
|
||||
rm -rf .pio .current .config platformio.ini
|
||||
|
||||
|
||||
help:
|
||||
@ cat Makefile
|
||||
7
hid/arduino/avrdude-rpi.conf
Normal file
7
hid/arduino/avrdude-rpi.conf
Normal file
@@ -0,0 +1,7 @@
|
||||
programmer
|
||||
id = "rpi";
|
||||
desc = "RPi SPI programmer";
|
||||
type = "linuxspi";
|
||||
reset = 25;
|
||||
baudrate = 400000;
|
||||
;
|
||||
54
hid/arduino/avrdude.py
Normal file
54
hid/arduino/avrdude.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# https://docs.platformio.org/en/latest/projectconf/advanced_scripting.html
|
||||
|
||||
|
||||
from os import rename
|
||||
from os import symlink
|
||||
from os.path import exists
|
||||
from os.path import join
|
||||
|
||||
import platform
|
||||
|
||||
Import("env")
|
||||
|
||||
|
||||
# =====
|
||||
def _get_tool_path() -> str:
|
||||
path = env.PioPlatform().get_package_dir("tool-avrdude")
|
||||
assert exists(path)
|
||||
return path
|
||||
|
||||
|
||||
def _fix_ld_arm() -> None:
|
||||
tool_path = _get_tool_path()
|
||||
flag_path = join(tool_path, ".fix-ld-arm.done")
|
||||
|
||||
if not exists(flag_path):
|
||||
def patch(*_, **__) -> None:
|
||||
symlink("/usr/lib/libtinfo.so.6", join(tool_path, "libtinfo.so.5"))
|
||||
open(flag_path, "w").close()
|
||||
|
||||
env.Execute(patch)
|
||||
|
||||
|
||||
def _replace_to_system(new_path: str) -> None:
|
||||
tool_path = _get_tool_path()
|
||||
flag_path = join(tool_path, ".replace-to-system.done")
|
||||
|
||||
if not exists(flag_path):
|
||||
def patch(*_, **__) -> None:
|
||||
old_path = join(tool_path, "avrdude")
|
||||
bak_path = join(tool_path, "_avrdude_bak")
|
||||
rename(old_path, bak_path)
|
||||
symlink(new_path, old_path)
|
||||
open(flag_path, "w").close()
|
||||
|
||||
env.Execute(patch)
|
||||
|
||||
|
||||
# =====
|
||||
if "arm" in platform.machine():
|
||||
_fix_ld_arm()
|
||||
|
||||
_path = "/usr/bin/avrdude"
|
||||
if exists(_path):
|
||||
_replace_to_system(_path)
|
||||
0
hid/arduino/lib/.gitignore
vendored
Normal file
0
hid/arduino/lib/.gitignore
vendored
Normal file
40
hid/arduino/lib/drivers-avr/eeprom.h
Normal file
40
hid/arduino/lib/drivers-avr/eeprom.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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 <avr/eeprom.h>
|
||||
|
||||
#include "storage.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
struct Eeprom : public Storage {
|
||||
using Storage::Storage;
|
||||
|
||||
void readBlock(void *dest, const void *src, size_t size) override {
|
||||
eeprom_read_block(dest, src, size);
|
||||
}
|
||||
|
||||
void updateBlock(const void *src, void *dest, size_t size) override {
|
||||
eeprom_update_block(src, dest, size);
|
||||
}
|
||||
};
|
||||
}
|
||||
94
hid/arduino/lib/drivers-avr/factory.cpp
Normal file
94
hid/arduino/lib/drivers-avr/factory.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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 "usb/hid.h"
|
||||
#include "ps2/hid.h"
|
||||
#include "factory.h"
|
||||
#include "eeprom.h"
|
||||
#include "serial.h"
|
||||
#include "spi.h"
|
||||
|
||||
#ifndef ARDUINO_ARCH_AVR
|
||||
# error "Only AVR is supported"
|
||||
#endif
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
Keyboard *Factory::makeKeyboard(type _type) {
|
||||
switch (_type) {
|
||||
# ifdef HID_WITH_USB
|
||||
case USB_KEYBOARD:
|
||||
return new UsbKeyboard();
|
||||
# endif
|
||||
|
||||
# ifdef HID_WITH_PS2
|
||||
case PS2_KEYBOARD:
|
||||
return new Ps2Keyboard();
|
||||
# endif
|
||||
|
||||
default:
|
||||
return new Keyboard(DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
Mouse *Factory::makeMouse(type _type) {
|
||||
switch (_type) {
|
||||
# ifdef HID_WITH_USB
|
||||
case USB_MOUSE_ABSOLUTE:
|
||||
case USB_MOUSE_ABSOLUTE_WIN98:
|
||||
return new UsbMouseAbsolute(_type);
|
||||
case USB_MOUSE_RELATIVE:
|
||||
return new UsbMouseRelative();
|
||||
# endif
|
||||
default:
|
||||
return new Mouse(DRIVERS::DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
Storage *Factory::makeStorage(type _type) {
|
||||
switch (_type) {
|
||||
# ifdef HID_DYNAMIC
|
||||
case NON_VOLATILE_STORAGE:
|
||||
return new Eeprom(DRIVERS::NON_VOLATILE_STORAGE);
|
||||
# endif
|
||||
default:
|
||||
return new Storage(DRIVERS::DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
Board *Factory::makeBoard(type _type) {
|
||||
switch (_type) {
|
||||
default:
|
||||
return new Board(DRIVERS::DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
Connection *Factory::makeConnection(type _type) {
|
||||
# ifdef CMD_SERIAL
|
||||
return new Serial();
|
||||
# elif defined(CMD_SPI)
|
||||
return new Spi();
|
||||
# else
|
||||
# error CMD phy is not defined
|
||||
# endif
|
||||
}
|
||||
}
|
||||
95
hid/arduino/lib/drivers-avr/ps2/hid.h
Normal file
95
hid/arduino/lib/drivers-avr/ps2/hid.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ps2dev.h>
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "keymap.h"
|
||||
|
||||
// #define HID_PS2_KBD_CLOCK_PIN 7
|
||||
// #define HID_PS2_KBD_DATA_PIN 5
|
||||
|
||||
|
||||
class Ps2Keyboard : public DRIVERS::Keyboard {
|
||||
// https://wiki.osdev.org/PS/2_Keyboard
|
||||
|
||||
public:
|
||||
Ps2Keyboard() : DRIVERS::Keyboard(DRIVERS::PS2_KEYBOARD), _dev(HID_PS2_KBD_CLOCK_PIN, HID_PS2_KBD_DATA_PIN) {}
|
||||
|
||||
void begin() override {
|
||||
_dev.keyboard_init();
|
||||
}
|
||||
|
||||
void periodic() override {
|
||||
_dev.keyboard_handle(&_leds);
|
||||
}
|
||||
|
||||
void sendKey(uint8_t code, bool state) override {
|
||||
Ps2KeyType ps2_type;
|
||||
uint8_t ps2_code;
|
||||
|
||||
keymapPs2(code, &ps2_type, &ps2_code);
|
||||
if (ps2_type != PS2_KEY_TYPE_UNKNOWN) {
|
||||
// Не отправлялась часть нажатий. Когда clock на нуле, комп не принимает ничего от клавы.
|
||||
// Этот костыль понижает процент пропущенных нажатий.
|
||||
while (digitalRead(HID_PS2_KBD_CLOCK_PIN) == 0) {};
|
||||
if (state) {
|
||||
switch (ps2_type) {
|
||||
case PS2_KEY_TYPE_REG: _dev.keyboard_press(ps2_code); break;
|
||||
case PS2_KEY_TYPE_SPEC: _dev.keyboard_press_special(ps2_code); break;
|
||||
case PS2_KEY_TYPE_PRINT: _dev.keyboard_press_printscreen(); break;
|
||||
case PS2_KEY_TYPE_PAUSE: _dev.keyboard_pausebreak(); break;
|
||||
case PS2_KEY_TYPE_UNKNOWN: break;
|
||||
}
|
||||
} else {
|
||||
switch (ps2_type) {
|
||||
case PS2_KEY_TYPE_REG: _dev.keyboard_release(ps2_code); break;
|
||||
case PS2_KEY_TYPE_SPEC: _dev.keyboard_release_special(ps2_code); break;
|
||||
case PS2_KEY_TYPE_PRINT: _dev.keyboard_release_printscreen(); break;
|
||||
case PS2_KEY_TYPE_PAUSE: break;
|
||||
case PS2_KEY_TYPE_UNKNOWN: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isOffline() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyboardLedsState getLeds() override {
|
||||
periodic();
|
||||
KeyboardLedsState result = {
|
||||
.caps = _leds & 0b00000100,
|
||||
.scroll = _leds & 0b00000001,
|
||||
.num = _leds & 0b00000010,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
PS2dev _dev;
|
||||
uint8_t _leds = 0;
|
||||
};
|
||||
152
hid/arduino/lib/drivers-avr/ps2/keymap.h
Normal file
152
hid/arduino/lib/drivers-avr/ps2/keymap.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
|
||||
enum Ps2KeyType : uint8_t {
|
||||
PS2_KEY_TYPE_UNKNOWN = 0,
|
||||
PS2_KEY_TYPE_REG = 1,
|
||||
PS2_KEY_TYPE_SPEC = 2,
|
||||
PS2_KEY_TYPE_PRINT = 3,
|
||||
PS2_KEY_TYPE_PAUSE = 4,
|
||||
};
|
||||
|
||||
|
||||
void keymapPs2(uint8_t code, Ps2KeyType *ps2_type, uint8_t *ps2_code) {
|
||||
*ps2_type = PS2_KEY_TYPE_UNKNOWN;
|
||||
*ps2_code = 0;
|
||||
|
||||
switch (code) {
|
||||
case 1: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 28; return; // KeyA
|
||||
case 2: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 50; return; // KeyB
|
||||
case 3: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 33; return; // KeyC
|
||||
case 4: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 35; return; // KeyD
|
||||
case 5: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 36; return; // KeyE
|
||||
case 6: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 43; return; // KeyF
|
||||
case 7: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 52; return; // KeyG
|
||||
case 8: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 51; return; // KeyH
|
||||
case 9: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 67; return; // KeyI
|
||||
case 10: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 59; return; // KeyJ
|
||||
case 11: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 66; return; // KeyK
|
||||
case 12: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 75; return; // KeyL
|
||||
case 13: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 58; return; // KeyM
|
||||
case 14: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 49; return; // KeyN
|
||||
case 15: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 68; return; // KeyO
|
||||
case 16: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 77; return; // KeyP
|
||||
case 17: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 21; return; // KeyQ
|
||||
case 18: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 45; return; // KeyR
|
||||
case 19: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 27; return; // KeyS
|
||||
case 20: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 44; return; // KeyT
|
||||
case 21: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 60; return; // KeyU
|
||||
case 22: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 42; return; // KeyV
|
||||
case 23: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 29; return; // KeyW
|
||||
case 24: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 34; return; // KeyX
|
||||
case 25: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 53; return; // KeyY
|
||||
case 26: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 26; return; // KeyZ
|
||||
case 27: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 22; return; // Digit1
|
||||
case 28: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 30; return; // Digit2
|
||||
case 29: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 38; return; // Digit3
|
||||
case 30: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 37; return; // Digit4
|
||||
case 31: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 46; return; // Digit5
|
||||
case 32: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 54; return; // Digit6
|
||||
case 33: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 61; return; // Digit7
|
||||
case 34: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 62; return; // Digit8
|
||||
case 35: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 70; return; // Digit9
|
||||
case 36: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 69; return; // Digit0
|
||||
case 37: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 90; return; // Enter
|
||||
case 38: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 118; return; // Escape
|
||||
case 39: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 102; return; // Backspace
|
||||
case 40: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 13; return; // Tab
|
||||
case 41: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 41; return; // Space
|
||||
case 42: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 78; return; // Minus
|
||||
case 43: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 85; return; // Equal
|
||||
case 44: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 84; return; // BracketLeft
|
||||
case 45: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 91; return; // BracketRight
|
||||
case 46: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 93; return; // Backslash
|
||||
case 47: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 76; return; // Semicolon
|
||||
case 48: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 82; return; // Quote
|
||||
case 49: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 14; return; // Backquote
|
||||
case 50: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 65; return; // Comma
|
||||
case 51: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 73; return; // Period
|
||||
case 52: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 74; return; // Slash
|
||||
case 53: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 88; return; // CapsLock
|
||||
case 54: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 5; return; // F1
|
||||
case 55: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 6; return; // F2
|
||||
case 56: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 4; return; // F3
|
||||
case 57: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 12; return; // F4
|
||||
case 58: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 3; return; // F5
|
||||
case 59: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 11; return; // F6
|
||||
case 60: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 131; return; // F7
|
||||
case 61: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 10; return; // F8
|
||||
case 62: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 1; return; // F9
|
||||
case 63: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 9; return; // F10
|
||||
case 64: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 120; return; // F11
|
||||
case 65: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 7; return; // F12
|
||||
case 66: *ps2_type = PS2_KEY_TYPE_PRINT; *ps2_code = 255; return; // PrintScreen
|
||||
case 67: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 112; return; // Insert
|
||||
case 68: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 108; return; // Home
|
||||
case 69: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 125; return; // PageUp
|
||||
case 70: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 113; return; // Delete
|
||||
case 71: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 105; return; // End
|
||||
case 72: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 122; return; // PageDown
|
||||
case 73: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 116; return; // ArrowRight
|
||||
case 74: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 107; return; // ArrowLeft
|
||||
case 75: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 114; return; // ArrowDown
|
||||
case 76: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 117; return; // ArrowUp
|
||||
case 77: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 20; return; // ControlLeft
|
||||
case 78: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 18; return; // ShiftLeft
|
||||
case 79: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 17; return; // AltLeft
|
||||
case 80: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 31; return; // MetaLeft
|
||||
case 81: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 20; return; // ControlRight
|
||||
case 82: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 89; return; // ShiftRight
|
||||
case 83: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 17; return; // AltRight
|
||||
case 84: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 39; return; // MetaRight
|
||||
case 85: *ps2_type = PS2_KEY_TYPE_PAUSE; *ps2_code = 255; return; // Pause
|
||||
case 86: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 126; return; // ScrollLock
|
||||
case 87: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 119; return; // NumLock
|
||||
case 88: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 47; return; // ContextMenu
|
||||
case 89: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 74; return; // NumpadDivide
|
||||
case 90: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 124; return; // NumpadMultiply
|
||||
case 91: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 123; return; // NumpadSubtract
|
||||
case 92: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 121; return; // NumpadAdd
|
||||
case 93: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 90; return; // NumpadEnter
|
||||
case 94: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 105; return; // Numpad1
|
||||
case 95: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 114; return; // Numpad2
|
||||
case 96: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 122; return; // Numpad3
|
||||
case 97: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 107; return; // Numpad4
|
||||
case 98: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 115; return; // Numpad5
|
||||
case 99: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 116; return; // Numpad6
|
||||
case 100: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 108; return; // Numpad7
|
||||
case 101: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 117; return; // Numpad8
|
||||
case 102: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 125; return; // Numpad9
|
||||
case 103: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 112; return; // Numpad0
|
||||
case 104: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 113; return; // NumpadDecimal
|
||||
case 105: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 94; return; // Power
|
||||
case 106: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 97; return; // IntlBackslash
|
||||
case 107: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 106; return; // IntlYen
|
||||
case 108: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 81; return; // IntlRo
|
||||
case 109: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 19; return; // KanaMode
|
||||
case 110: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 100; return; // Convert
|
||||
case 111: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 103; return; // NonConvert
|
||||
}
|
||||
}
|
||||
44
hid/arduino/lib/drivers-avr/ps2/keymap.h.mako
Normal file
44
hid/arduino/lib/drivers-avr/ps2/keymap.h.mako
Normal file
@@ -0,0 +1,44 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
|
||||
enum Ps2KeyType : uint8_t {
|
||||
PS2_KEY_TYPE_UNKNOWN = 0,
|
||||
PS2_KEY_TYPE_REG = 1,
|
||||
PS2_KEY_TYPE_SPEC = 2,
|
||||
PS2_KEY_TYPE_PRINT = 3,
|
||||
PS2_KEY_TYPE_PAUSE = 4,
|
||||
};
|
||||
|
||||
<%! import operator %>
|
||||
void keymapPs2(uint8_t code, Ps2KeyType *ps2_type, uint8_t *ps2_code) {
|
||||
*ps2_type = PS2_KEY_TYPE_UNKNOWN;
|
||||
*ps2_code = 0;
|
||||
|
||||
switch (code) {
|
||||
% for km in sorted(keymap, key=operator.attrgetter("mcu_code")):
|
||||
case ${km.mcu_code}: *ps2_type = PS2_KEY_TYPE_${km.ps2_key.type.upper()}; *ps2_code = ${km.ps2_key.code}; return; // ${km.web_name}
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
83
hid/arduino/lib/drivers-avr/spi.cpp
Normal file
83
hid/arduino/lib/drivers-avr/spi.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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 "spi.h"
|
||||
|
||||
#ifdef CMD_SPI
|
||||
|
||||
|
||||
static volatile uint8_t _spi_in[8] = {0};
|
||||
static volatile uint8_t _spi_in_index = 0;
|
||||
|
||||
static volatile uint8_t _spi_out[8] = {0};
|
||||
static volatile uint8_t _spi_out_index = 0;
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
void Spi::begin() {
|
||||
pinMode(MISO, OUTPUT);
|
||||
SPCR = (1 << SPE) | (1 << SPIE); // Slave, SPI En, IRQ En
|
||||
}
|
||||
|
||||
void Spi::periodic() {
|
||||
if (!_spi_out[0] && _spi_in_index == 8) {
|
||||
_data_cb((const uint8_t *)_spi_in, 8);
|
||||
}
|
||||
}
|
||||
|
||||
void Spi::write(const uint8_t *data, size_t size) {
|
||||
// Меджик в нулевом байте разрешает начать ответ
|
||||
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 < 8) {
|
||||
SPDR = _spi_out[_spi_out_index];
|
||||
if (!(SPSR & (1 << WCOL))) {
|
||||
++_spi_out_index;
|
||||
if (_spi_out_index == 8) {
|
||||
_spi_out_index = 0;
|
||||
_spi_in_index = 0;
|
||||
_spi_out[0] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
static bool receiving = false;
|
||||
if (!receiving && in != 0) {
|
||||
receiving = true;
|
||||
}
|
||||
if (receiving && _spi_in_index < 8) {
|
||||
_spi_in[_spi_in_index] = in;
|
||||
++_spi_in_index;
|
||||
}
|
||||
if (_spi_in_index == 8) {
|
||||
receiving = false;
|
||||
}
|
||||
SPDR = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
40
hid/arduino/lib/drivers-avr/spi.h
Normal file
40
hid/arduino/lib/drivers-avr/spi.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
struct Spi : public Connection {
|
||||
Spi() : Connection(CONNECTION) {}
|
||||
|
||||
void begin() override;
|
||||
|
||||
void periodic() override;
|
||||
|
||||
void write(const uint8_t *data, size_t size) override;
|
||||
};
|
||||
}
|
||||
230
hid/arduino/lib/drivers-avr/usb/hid.h
Normal file
230
hid/arduino/lib/drivers-avr/usb/hid.h
Normal file
@@ -0,0 +1,230 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <HID-Project.h>
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "mouse.h"
|
||||
#include "tools.h"
|
||||
#include "usb-keymap.h"
|
||||
#ifdef AUM
|
||||
# include "aum.h"
|
||||
#endif
|
||||
|
||||
using namespace DRIVERS;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#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
|
||||
# ifdef AUM
|
||||
# define CHECK_AUM_USB { if (!aumIsUsbConnected()) { return true; } }
|
||||
# else
|
||||
# define CHECK_AUM_USB
|
||||
# endif
|
||||
# define CLS_IS_OFFLINE(_hid) \
|
||||
bool isOffline() override { \
|
||||
CHECK_AUM_USB; \
|
||||
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 false; \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
# define CHECK_HID_EP { if (isOffline()) return; }
|
||||
|
||||
#else
|
||||
# define CLS_IS_OFFLINE(_hid) \
|
||||
bool isOffline() override { \
|
||||
return false; \
|
||||
}
|
||||
# define CHECK_HID_EP
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class UsbKeyboard : public DRIVERS::Keyboard {
|
||||
public:
|
||||
UsbKeyboard() : DRIVERS::Keyboard(DRIVERS::USB_KEYBOARD) {}
|
||||
|
||||
void begin() override {
|
||||
_kbd.begin();
|
||||
}
|
||||
|
||||
void periodic() override {
|
||||
# ifdef HID_USB_CHECK_ENDPOINT
|
||||
static unsigned long prev_ts = 0;
|
||||
if (is_micros_timed_out(prev_ts, 50000)) {
|
||||
static bool prev_online = true;
|
||||
bool online = !isOffline();
|
||||
if (!_sent || (online && !prev_online)) {
|
||||
_sendCurrent();
|
||||
}
|
||||
prev_online = online;
|
||||
prev_ts = micros();
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
void clear() override {
|
||||
_kbd.releaseAll();
|
||||
}
|
||||
|
||||
void sendKey(uint8_t code, bool state) override {
|
||||
enum KeyboardKeycode usb_code = keymapUsb(code);
|
||||
if (usb_code > 0) {
|
||||
if (state ? _kbd.add(usb_code) : _kbd.remove(usb_code)) {
|
||||
_sendCurrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLS_IS_OFFLINE(_kbd)
|
||||
|
||||
KeyboardLedsState getLeds() override {
|
||||
uint8_t leds = _kbd.getLeds();
|
||||
KeyboardLedsState result = {
|
||||
.caps = leds & LED_CAPS_LOCK,
|
||||
.scroll = leds & LED_SCROLL_LOCK,
|
||||
.num = leds & LED_NUM_LOCK,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
BootKeyboard_ _kbd;
|
||||
bool _sent = true;
|
||||
|
||||
void _sendCurrent() {
|
||||
# ifdef HID_USB_CHECK_ENDPOINT
|
||||
if (isOffline()) {
|
||||
_sent = false;
|
||||
} else {
|
||||
# endif
|
||||
_sent = (_kbd.send() >= 0);
|
||||
# ifdef HID_USB_CHECK_ENDPOINT
|
||||
}
|
||||
# endif
|
||||
}
|
||||
};
|
||||
|
||||
#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 \
|
||||
) override { \
|
||||
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 DRIVERS::Mouse {
|
||||
public:
|
||||
UsbMouseAbsolute(DRIVERS::type _type) : Mouse(_type) {}
|
||||
|
||||
void begin() override {
|
||||
_mouse.begin();
|
||||
_mouse.setWin98FixEnabled(getType() == DRIVERS::USB_MOUSE_ABSOLUTE_WIN98);
|
||||
}
|
||||
|
||||
void clear() override {
|
||||
_mouse.releaseAll();
|
||||
}
|
||||
|
||||
CLS_SEND_BUTTONS
|
||||
|
||||
void sendMove(int x, int y) override {
|
||||
CHECK_HID_EP;
|
||||
_mouse.moveTo(x, y);
|
||||
}
|
||||
|
||||
void sendWheel(int delta_y) override {
|
||||
// delta_x is not supported by hid-project now
|
||||
CHECK_HID_EP;
|
||||
_mouse.move(0, 0, delta_y);
|
||||
}
|
||||
|
||||
CLS_IS_OFFLINE(_mouse)
|
||||
|
||||
private:
|
||||
SingleAbsoluteMouse_ _mouse;
|
||||
|
||||
void _sendButton(uint8_t button, bool state) {
|
||||
CHECK_HID_EP;
|
||||
if (state) _mouse.press(button);
|
||||
else _mouse.release(button);
|
||||
}
|
||||
};
|
||||
|
||||
class UsbMouseRelative : public DRIVERS::Mouse {
|
||||
public:
|
||||
UsbMouseRelative() : DRIVERS::Mouse(DRIVERS::USB_MOUSE_RELATIVE) {}
|
||||
|
||||
void begin() override {
|
||||
_mouse.begin();
|
||||
}
|
||||
|
||||
void clear() override {
|
||||
_mouse.releaseAll();
|
||||
}
|
||||
|
||||
CLS_SEND_BUTTONS
|
||||
|
||||
void sendRelative(int x, int y) override {
|
||||
CHECK_HID_EP;
|
||||
_mouse.move(x, y, 0);
|
||||
}
|
||||
|
||||
void sendWheel(int delta_y) override {
|
||||
// delta_x is not supported by hid-project now
|
||||
CHECK_HID_EP;
|
||||
_mouse.move(0, 0, delta_y);
|
||||
}
|
||||
|
||||
CLS_IS_OFFLINE(_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_IS_OFFLINE
|
||||
#undef CHECK_HID_EP
|
||||
22
hid/arduino/lib/drivers-stm32/README.md
Normal file
22
hid/arduino/lib/drivers-stm32/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
This is WIP. Use AVR version as reference.
|
||||
|
||||
It was tested with bluepill. Most boards are clones.
|
||||
If you have problem with USB please check https://stm32duinoforum.com/forum/wiki_subdomain/index_title_Blue_Pill.html for pull up resistor. If it still does not work check another board or cable.
|
||||
|
||||
TODO:
|
||||
- [x] Serial communication
|
||||
- [x] USB keyboard
|
||||
- [x] USB keyboard - add scroll status
|
||||
- [x] USB keyboard - key sending
|
||||
- [x] USB keyboard - test key mapping
|
||||
- [x] Persistent storage
|
||||
- [ ] SPI communication
|
||||
- [ ] PS2 keyboard
|
||||
- [x] USB absolute mouse
|
||||
- [x] USB absolute mouse - add whele
|
||||
- [x] USB relative mouse
|
||||
- [x] USB relative mouse - add whele
|
||||
- [ ] USB mouses - up down button
|
||||
- [ ] WIN98 USB mouse
|
||||
- [x] undefine SERIAL_USB
|
||||
- [ ] boot keyboard
|
||||
53
hid/arduino/lib/drivers-stm32/backup-register.h
Normal file
53
hid/arduino/lib/drivers-stm32/backup-register.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
|
||||
#include <stm32f1_rtc.h>
|
||||
|
||||
#include "storage.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
struct BackupRegister : public Storage {
|
||||
BackupRegister() : Storage(NON_VOLATILE_STORAGE) {
|
||||
_rtc.enableClockInterface();
|
||||
}
|
||||
|
||||
void readBlock(void *dest, const void *src, size_t size) override {
|
||||
uint8_t *dest_ = reinterpret_cast<uint8_t*>(dest);
|
||||
for(size_t index = 0; index < size; ++index) {
|
||||
dest_[index] = _rtc.getBackupRegister(reinterpret_cast<uintptr_t>(src) + index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void updateBlock(const void *src, void *dest, size_t size) override {
|
||||
const uint8_t *src_ = reinterpret_cast<const uint8_t*>(src);
|
||||
for(size_t index = 0; index < size; ++index) {
|
||||
_rtc.setBackupRegister(reinterpret_cast<uintptr_t>(dest) + index + 1, src_[index]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
STM32F1_RTC _rtc;
|
||||
};
|
||||
}
|
||||
BIN
hid/arduino/lib/drivers-stm32/bluepill_sch.png
Normal file
BIN
hid/arduino/lib/drivers-stm32/bluepill_sch.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 176 KiB |
103
hid/arduino/lib/drivers-stm32/board-stm32.h
Normal file
103
hid/arduino/lib/drivers-stm32/board-stm32.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include "board.h"
|
||||
#include <libmaple/iwdg.h>
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
class BoardStm32 : public Board {
|
||||
public:
|
||||
BoardStm32() : Board(BOARD){
|
||||
//2 sec timeout
|
||||
iwdg_init(IWDG_PRE_16, 0xFFF);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
}
|
||||
|
||||
void reset() override {
|
||||
nvic_sys_reset();
|
||||
}
|
||||
|
||||
void periodic() override {
|
||||
iwdg_feed();
|
||||
if (is_micros_timed_out(_prev_ts, 100000)) {
|
||||
switch(_state) {
|
||||
case 0:
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
break;
|
||||
case 2:
|
||||
if(_rx_data) {
|
||||
_rx_data = false;
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if(_keyboard_online) {
|
||||
_keyboard_online = false;
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if(_mouse_online) {
|
||||
_mouse_online = false;
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
break;
|
||||
case 1: // heartbeat off
|
||||
case 3: // _rx_data off
|
||||
case 7: // _keyboard_online off
|
||||
case 11: // _mouse_online off
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
break;
|
||||
case 19:
|
||||
_state = -1;
|
||||
break;
|
||||
}
|
||||
++_state;
|
||||
_prev_ts = micros();
|
||||
}
|
||||
}
|
||||
|
||||
void updateStatus(status status) override {
|
||||
switch (status) {
|
||||
case RX_DATA:
|
||||
_rx_data = true;
|
||||
break;
|
||||
case KEYBOARD_ONLINE:
|
||||
_keyboard_online = true;
|
||||
break;
|
||||
case MOUSE_ONLINE:
|
||||
_mouse_online = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned long _prev_ts = 0;
|
||||
uint8_t _state = 0;
|
||||
bool _rx_data = false;
|
||||
bool _keyboard_online = false;
|
||||
bool _mouse_online = false;
|
||||
};
|
||||
}
|
||||
94
hid/arduino/lib/drivers-stm32/factory.cpp
Normal file
94
hid/arduino/lib/drivers-stm32/factory.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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 "usb/keyboard-stm32.h"
|
||||
#include "usb/hid-wrapper-stm32.h"
|
||||
#include "usb/mouse-absolute-stm32.h"
|
||||
#include "usb/mouse-relative-stm32.h"
|
||||
#include "backup-register.h"
|
||||
#include "board-stm32.h"
|
||||
#include "serial.h"
|
||||
|
||||
#ifndef __STM32F1__
|
||||
# error "Only STM32F1 is supported"
|
||||
#endif
|
||||
#ifdef SERIAL_USB
|
||||
# error "Disable random USB enumeration"
|
||||
#endif
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
HidWrapper _hidWrapper;
|
||||
|
||||
Keyboard *Factory::makeKeyboard(type _type) {
|
||||
switch (_type) {
|
||||
# ifdef HID_WITH_USB
|
||||
case USB_KEYBOARD:
|
||||
return new UsbKeyboard(_hidWrapper);
|
||||
# endif
|
||||
default:
|
||||
return new Keyboard(DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
Mouse *Factory::makeMouse(type _type) {
|
||||
switch(_type) {
|
||||
# ifdef HID_WITH_USB
|
||||
case USB_MOUSE_ABSOLUTE:
|
||||
return new UsbMouseAbsolute(_hidWrapper);
|
||||
case USB_MOUSE_RELATIVE:
|
||||
return new UsbMouseRelative(_hidWrapper);
|
||||
# endif
|
||||
default:
|
||||
return new Mouse(DRIVERS::DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
Storage *Factory::makeStorage(type _type) {
|
||||
switch (_type) {
|
||||
# ifdef HID_DYNAMIC
|
||||
case NON_VOLATILE_STORAGE:
|
||||
return new BackupRegister();
|
||||
# endif
|
||||
default:
|
||||
return new Storage(DRIVERS::DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
Board *Factory::makeBoard(type _type) {
|
||||
switch (_type) {
|
||||
case BOARD:
|
||||
return new BoardStm32();
|
||||
default:
|
||||
return new Board(DRIVERS::DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
Connection *Factory::makeConnection(type _type) {
|
||||
# ifdef CMD_SERIAL
|
||||
return new Serial();
|
||||
# else
|
||||
# error CMD phy is not defined
|
||||
# endif
|
||||
}
|
||||
}
|
||||
72
hid/arduino/lib/drivers-stm32/usb/hid-wrapper-stm32.h
Normal file
72
hid/arduino/lib/drivers-stm32/usb/hid-wrapper-stm32.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <USBComposite.h>
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
class HidWrapper {
|
||||
public:
|
||||
void begin() {
|
||||
if (_init) {
|
||||
return;
|
||||
}
|
||||
_init = true;
|
||||
|
||||
_report_descriptor_length = 0;
|
||||
for (unsigned index = 0; index < _count; ++index) {
|
||||
_report_descriptor_length += _descriptors_size[index];
|
||||
}
|
||||
|
||||
_report_descriptor = new uint8[_report_descriptor_length];
|
||||
|
||||
size_t offset = 0;
|
||||
for (unsigned index = 0; index < _count; ++index) {
|
||||
memcpy(_report_descriptor + offset, _report_descriptors[index], _descriptors_size[index]);
|
||||
offset += _descriptors_size[index];
|
||||
}
|
||||
|
||||
usbHid.begin(_report_descriptor, _report_descriptor_length);
|
||||
}
|
||||
|
||||
void addReportDescriptor(const uint8_t *report_descriptor, uint16_t report_descriptor_length) {
|
||||
_report_descriptors[_count] = report_descriptor;
|
||||
_descriptors_size[_count] = report_descriptor_length;
|
||||
++_count;
|
||||
}
|
||||
|
||||
USBHID usbHid;
|
||||
|
||||
private:
|
||||
bool _init = false;
|
||||
|
||||
static constexpr uint8_t MAX_USB_DESCRIPTORS = 2;
|
||||
const uint8_t *_report_descriptors[MAX_USB_DESCRIPTORS];
|
||||
uint8_t _descriptors_size[MAX_USB_DESCRIPTORS];
|
||||
|
||||
uint8_t _count = 0;
|
||||
uint8_t *_report_descriptor;
|
||||
uint16_t _report_descriptor_length;
|
||||
};
|
||||
}
|
||||
92
hid/arduino/lib/drivers-stm32/usb/keyboard-stm32.h
Normal file
92
hid/arduino/lib/drivers-stm32/usb/keyboard-stm32.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <USBComposite.h>
|
||||
|
||||
#include "tools.h"
|
||||
#include "keyboard.h"
|
||||
#include "usb-keymap.h"
|
||||
#include "hid-wrapper-stm32.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
const uint8_t reportDescriptionKeyboard[] = {
|
||||
HID_KEYBOARD_REPORT_DESCRIPTOR(),
|
||||
};
|
||||
|
||||
class UsbKeyboard : public Keyboard {
|
||||
public:
|
||||
UsbKeyboard(HidWrapper& _hidWrapper) : Keyboard(USB_KEYBOARD),
|
||||
_hidWrapper(_hidWrapper), _keyboard(_hidWrapper.usbHid) {
|
||||
_hidWrapper.addReportDescriptor(reportDescriptionKeyboard, sizeof(reportDescriptionKeyboard));
|
||||
}
|
||||
|
||||
void begin() override {
|
||||
_hidWrapper.begin();
|
||||
_keyboard.begin();
|
||||
}
|
||||
|
||||
void clear() override {
|
||||
_keyboard.releaseAll();
|
||||
}
|
||||
|
||||
void sendKey(uint8_t code, bool state) override {
|
||||
uint16_t usb_code = keymapUsb(code);
|
||||
if (usb_code == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 0xE0 is a prefix from HID-Project keytable
|
||||
if (usb_code >= 0xE0 && usb_code <= 0xE7) {
|
||||
usb_code = usb_code - 0xE0 + 0x80;
|
||||
} else {
|
||||
usb_code += KEY_HID_OFFSET;
|
||||
}
|
||||
|
||||
if (state) {
|
||||
_keyboard.press(usb_code);
|
||||
} else {
|
||||
_keyboard.release(usb_code);
|
||||
}
|
||||
}
|
||||
|
||||
bool isOffline() override {
|
||||
return (USBComposite == false);
|
||||
}
|
||||
|
||||
KeyboardLedsState getLeds() override {
|
||||
uint8_t leds = _keyboard.getLEDs();
|
||||
KeyboardLedsState result = {
|
||||
.caps = leds & 0b00000010,
|
||||
.scroll = leds & 0b00000100,
|
||||
.num = leds & 0b00000001,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
HidWrapper& _hidWrapper;
|
||||
HIDKeyboard _keyboard;
|
||||
};
|
||||
}
|
||||
86
hid/arduino/lib/drivers-stm32/usb/mouse-absolute-stm32.h
Normal file
86
hid/arduino/lib/drivers-stm32/usb/mouse-absolute-stm32.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <USBComposite.h>
|
||||
|
||||
#include "mouse.h"
|
||||
#include "hid-wrapper-stm32.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
const uint8_t reportDescriptionMouseAbsolute[] = {
|
||||
HID_ABS_MOUSE_REPORT_DESCRIPTOR()
|
||||
};
|
||||
|
||||
class UsbMouseAbsolute : public Mouse {
|
||||
public:
|
||||
UsbMouseAbsolute(HidWrapper& _hidWrapper) : Mouse(USB_MOUSE_ABSOLUTE),
|
||||
_hidWrapper(_hidWrapper), _mouse(_hidWrapper.usbHid) {
|
||||
_hidWrapper.addReportDescriptor(reportDescriptionMouseAbsolute, sizeof(reportDescriptionMouseAbsolute));
|
||||
}
|
||||
|
||||
void begin() override {
|
||||
_hidWrapper.begin();
|
||||
}
|
||||
|
||||
void clear() override {
|
||||
_mouse.release(0xFF);
|
||||
}
|
||||
|
||||
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) override {
|
||||
|
||||
# define SEND_BUTTON(x_low, x_up) { \
|
||||
if (x_low##_select) { \
|
||||
if (x_low##_state) _mouse.press(MOUSE_##x_up); \
|
||||
else _mouse.release(MOUSE_##x_up); \
|
||||
} \
|
||||
}
|
||||
SEND_BUTTON(left, LEFT);
|
||||
SEND_BUTTON(right, RIGHT);
|
||||
SEND_BUTTON(middle, MIDDLE);
|
||||
# undef SEND_BUTTON
|
||||
}
|
||||
|
||||
void sendMove(int x, int y) override {
|
||||
_mouse.move(x, y);
|
||||
}
|
||||
|
||||
void sendWheel(int delta_y) override {
|
||||
_mouse.move(0, 0, delta_y);
|
||||
}
|
||||
|
||||
bool isOffline() override {
|
||||
return (USBComposite == false);
|
||||
}
|
||||
|
||||
private:
|
||||
HidWrapper& _hidWrapper;
|
||||
HIDAbsMouse _mouse;
|
||||
};
|
||||
}
|
||||
86
hid/arduino/lib/drivers-stm32/usb/mouse-relative-stm32.h
Normal file
86
hid/arduino/lib/drivers-stm32/usb/mouse-relative-stm32.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <USBComposite.h>
|
||||
|
||||
#include "mouse.h"
|
||||
#include "hid-wrapper-stm32.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
const uint8_t reportDescriptionMouseRelative[] = {
|
||||
HID_MOUSE_REPORT_DESCRIPTOR()
|
||||
};
|
||||
|
||||
class UsbMouseRelative : public Mouse {
|
||||
public:
|
||||
UsbMouseRelative(HidWrapper& _hidWrapper) : Mouse(USB_MOUSE_RELATIVE),
|
||||
_hidWrapper(_hidWrapper), _mouse(_hidWrapper.usbHid) {
|
||||
_hidWrapper.addReportDescriptor(reportDescriptionMouseRelative, sizeof(reportDescriptionMouseRelative));
|
||||
}
|
||||
|
||||
void begin() override {
|
||||
_hidWrapper.begin();
|
||||
}
|
||||
|
||||
void clear() override {
|
||||
_mouse.release(0xFF);
|
||||
}
|
||||
|
||||
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) override {
|
||||
|
||||
# define SEND_BUTTON(x_low, x_up) { \
|
||||
if (x_low##_select) { \
|
||||
if (x_low##_state) _mouse.press(MOUSE_##x_up); \
|
||||
else _mouse.release(MOUSE_##x_up); \
|
||||
} \
|
||||
}
|
||||
SEND_BUTTON(left, LEFT);
|
||||
SEND_BUTTON(right, RIGHT);
|
||||
SEND_BUTTON(middle, MIDDLE);
|
||||
# undef SEND_BUTTON
|
||||
}
|
||||
|
||||
void sendRelative(int x, int y) override {
|
||||
_mouse.move(x, y);
|
||||
}
|
||||
|
||||
void sendWheel(int delta_y) override {
|
||||
_mouse.move(0, 0, delta_y);
|
||||
}
|
||||
|
||||
bool isOffline() override {
|
||||
return (USBComposite == false);
|
||||
}
|
||||
|
||||
private:
|
||||
HidWrapper& _hidWrapper;
|
||||
HIDMouse _mouse;
|
||||
};
|
||||
}
|
||||
48
hid/arduino/lib/drivers/aum.h
Normal file
48
hid/arduino/lib/drivers/aum.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <digitalWriteFast.h>
|
||||
|
||||
|
||||
inline void aumInit() {
|
||||
pinModeFast(AUM_IS_USB_POWERED_PIN, INPUT);
|
||||
pinModeFast(AUM_SET_USB_VBUS_PIN, OUTPUT);
|
||||
pinModeFast(AUM_SET_USB_CONNECTED_PIN, OUTPUT);
|
||||
digitalWriteFast(AUM_SET_USB_CONNECTED_PIN, HIGH);
|
||||
}
|
||||
|
||||
inline void aumProxyUsbVbus() {
|
||||
bool vbus = digitalReadFast(AUM_IS_USB_POWERED_PIN);
|
||||
if (digitalReadFast(AUM_SET_USB_VBUS_PIN) != vbus) {
|
||||
digitalWriteFast(AUM_SET_USB_VBUS_PIN, vbus);
|
||||
}
|
||||
}
|
||||
|
||||
inline void aumSetUsbConnected(bool connected) {
|
||||
digitalWriteFast(AUM_SET_USB_CONNECTED_PIN, connected);
|
||||
}
|
||||
|
||||
inline bool aumIsUsbConnected() {
|
||||
return digitalReadFast(AUM_SET_USB_CONNECTED_PIN);
|
||||
}
|
||||
41
hid/arduino/lib/drivers/board.h
Normal file
41
hid/arduino/lib/drivers/board.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
enum status {
|
||||
RX_DATA = 0,
|
||||
KEYBOARD_ONLINE,
|
||||
MOUSE_ONLINE,
|
||||
};
|
||||
|
||||
struct Board : public Driver {
|
||||
using Driver::Driver;
|
||||
virtual void reset() {}
|
||||
virtual void periodic() {}
|
||||
virtual void updateStatus(status status) {}
|
||||
};
|
||||
}
|
||||
54
hid/arduino/lib/drivers/connection.h
Normal file
54
hid/arduino/lib/drivers/connection.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include "driver.h"
|
||||
#include "stdint.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
typedef void (*DataHandler)(const uint8_t *data, size_t size);
|
||||
typedef void (*TimeoutHandler)();
|
||||
|
||||
struct Connection : public Driver {
|
||||
using Driver::Driver;
|
||||
|
||||
virtual void begin() {}
|
||||
|
||||
virtual void periodic() {}
|
||||
|
||||
void onTimeout(TimeoutHandler cb) {
|
||||
_timeout_cb = cb;
|
||||
}
|
||||
|
||||
void onData(DataHandler cb) {
|
||||
_data_cb = cb;
|
||||
}
|
||||
|
||||
virtual void write(const uint8_t *data, size_t size) = 0;
|
||||
|
||||
protected:
|
||||
TimeoutHandler _timeout_cb = nullptr;
|
||||
DataHandler _data_cb = nullptr;
|
||||
};
|
||||
}
|
||||
49
hid/arduino/lib/drivers/driver.h
Normal file
49
hid/arduino/lib/drivers/driver.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
enum type {
|
||||
DUMMY = 0,
|
||||
USB_MOUSE_ABSOLUTE,
|
||||
USB_MOUSE_RELATIVE,
|
||||
USB_MOUSE_ABSOLUTE_WIN98,
|
||||
USB_KEYBOARD,
|
||||
PS2_KEYBOARD,
|
||||
NON_VOLATILE_STORAGE,
|
||||
BOARD,
|
||||
CONNECTION,
|
||||
};
|
||||
|
||||
class Driver {
|
||||
public:
|
||||
Driver(type _type) : _type(_type) {}
|
||||
uint8_t getType() { return _type; }
|
||||
|
||||
private:
|
||||
type _type;
|
||||
};
|
||||
}
|
||||
39
hid/arduino/lib/drivers/factory.h
Normal file
39
hid/arduino/lib/drivers/factory.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "mouse.h"
|
||||
#include "storage.h"
|
||||
#include "board.h"
|
||||
#include "connection.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
struct Factory {
|
||||
static Keyboard *makeKeyboard(type _type);
|
||||
static Mouse *makeMouse(type _type);
|
||||
static Storage *makeStorage(type _type);
|
||||
static Board *makeBoard(type _type);
|
||||
static Connection *makeConnection(type _type);
|
||||
};
|
||||
}
|
||||
68
hid/arduino/lib/drivers/keyboard.h
Normal file
68
hid/arduino/lib/drivers/keyboard.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
typedef struct {
|
||||
bool caps;
|
||||
bool scroll;
|
||||
bool num;
|
||||
} KeyboardLedsState;
|
||||
|
||||
struct Keyboard : public Driver {
|
||||
using Driver::Driver;
|
||||
|
||||
virtual void begin() {}
|
||||
|
||||
/**
|
||||
* Release all keys
|
||||
*/
|
||||
virtual void clear() {}
|
||||
|
||||
/**
|
||||
* Sends key
|
||||
* @param code ???
|
||||
* @param state true pressed, false released
|
||||
*/
|
||||
virtual void sendKey(uint8_t code, bool state) {}
|
||||
|
||||
virtual void periodic() {}
|
||||
|
||||
/**
|
||||
* False if online or unknown. Otherwise true.
|
||||
*/
|
||||
virtual bool isOffline() {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual KeyboardLedsState getLeds() {
|
||||
KeyboardLedsState result = {0};
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
51
hid/arduino/lib/drivers/mouse.h
Normal file
51
hid/arduino/lib/drivers/mouse.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
struct Mouse : public Driver {
|
||||
using Driver::Driver;
|
||||
virtual void begin() {}
|
||||
|
||||
/**
|
||||
* Release all keys
|
||||
*/
|
||||
virtual void clear() {}
|
||||
virtual 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) {}
|
||||
virtual void sendMove(int x, int y) {}
|
||||
virtual void sendRelative(int x, int y) {}
|
||||
virtual void sendWheel(int delta_y) {}
|
||||
virtual bool isOffline() { return false; }
|
||||
virtual void periodic() {}
|
||||
};
|
||||
}
|
||||
68
hid/arduino/lib/drivers/serial.h
Normal file
68
hid/arduino/lib/drivers/serial.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#ifdef CMD_SERIAL
|
||||
#include "connection.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
#ifdef Serial
|
||||
# undef Serial
|
||||
#endif
|
||||
struct Serial : public Connection {
|
||||
Serial() : Connection(CONNECTION) {}
|
||||
|
||||
void begin() override {
|
||||
CMD_SERIAL.begin(CMD_SERIAL_SPEED);
|
||||
}
|
||||
|
||||
void periodic() override {
|
||||
if (CMD_SERIAL.available() > 0) {
|
||||
_buffer[_index] = (uint8_t)CMD_SERIAL.read();
|
||||
if (_index == 7) {
|
||||
_data_cb(_buffer, 8);
|
||||
_index = 0;
|
||||
} else {
|
||||
_last = micros();
|
||||
++_index;
|
||||
}
|
||||
} else if (_index > 0) {
|
||||
if (is_micros_timed_out(_last, CMD_SERIAL_TIMEOUT)) {
|
||||
_timeout_cb();
|
||||
_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write(const uint8_t *data, size_t size) override {
|
||||
CMD_SERIAL.write(data, size);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned long _last = 0;
|
||||
uint8_t _index = 0;
|
||||
uint8_t _buffer[8];
|
||||
};
|
||||
}
|
||||
#endif
|
||||
35
hid/arduino/lib/drivers/storage.h
Normal file
35
hid/arduino/lib/drivers/storage.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include "driver.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
|
||||
namespace DRIVERS {
|
||||
struct Storage : public Driver {
|
||||
using Driver::Driver;
|
||||
virtual void readBlock(void *dest, const void *src, size_t size) {}
|
||||
virtual void updateBlock(const void *src, void *dest, size_t size) {}
|
||||
};
|
||||
}
|
||||
32
hid/arduino/lib/drivers/tools.cpp
Normal file
32
hid/arduino/lib/drivers/tools.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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 "tools.h"
|
||||
|
||||
|
||||
bool is_micros_timed_out(unsigned long start_ts, unsigned long timeout) {
|
||||
unsigned long now = micros();
|
||||
return (
|
||||
(now >= start_ts && now - start_ts > timeout)
|
||||
|| (now < start_ts && ((unsigned long)-1) - start_ts + now > timeout)
|
||||
);
|
||||
}
|
||||
28
hid/arduino/lib/drivers/tools.h
Normal file
28
hid/arduino/lib/drivers/tools.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
bool is_micros_timed_out(unsigned long start_ts, unsigned long timeout);
|
||||
141
hid/arduino/lib/drivers/usb-keymap.h
Normal file
141
hid/arduino/lib/drivers/usb-keymap.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
|
||||
uint8_t keymapUsb(uint8_t code) {
|
||||
switch (code) {
|
||||
case 1: return 4; // KeyA
|
||||
case 2: return 5; // KeyB
|
||||
case 3: return 6; // KeyC
|
||||
case 4: return 7; // KeyD
|
||||
case 5: return 8; // KeyE
|
||||
case 6: return 9; // KeyF
|
||||
case 7: return 10; // KeyG
|
||||
case 8: return 11; // KeyH
|
||||
case 9: return 12; // KeyI
|
||||
case 10: return 13; // KeyJ
|
||||
case 11: return 14; // KeyK
|
||||
case 12: return 15; // KeyL
|
||||
case 13: return 16; // KeyM
|
||||
case 14: return 17; // KeyN
|
||||
case 15: return 18; // KeyO
|
||||
case 16: return 19; // KeyP
|
||||
case 17: return 20; // KeyQ
|
||||
case 18: return 21; // KeyR
|
||||
case 19: return 22; // KeyS
|
||||
case 20: return 23; // KeyT
|
||||
case 21: return 24; // KeyU
|
||||
case 22: return 25; // KeyV
|
||||
case 23: return 26; // KeyW
|
||||
case 24: return 27; // KeyX
|
||||
case 25: return 28; // KeyY
|
||||
case 26: return 29; // KeyZ
|
||||
case 27: return 30; // Digit1
|
||||
case 28: return 31; // Digit2
|
||||
case 29: return 32; // Digit3
|
||||
case 30: return 33; // Digit4
|
||||
case 31: return 34; // Digit5
|
||||
case 32: return 35; // Digit6
|
||||
case 33: return 36; // Digit7
|
||||
case 34: return 37; // Digit8
|
||||
case 35: return 38; // Digit9
|
||||
case 36: return 39; // Digit0
|
||||
case 37: return 40; // Enter
|
||||
case 38: return 41; // Escape
|
||||
case 39: return 42; // Backspace
|
||||
case 40: return 43; // Tab
|
||||
case 41: return 44; // Space
|
||||
case 42: return 45; // Minus
|
||||
case 43: return 46; // Equal
|
||||
case 44: return 47; // BracketLeft
|
||||
case 45: return 48; // BracketRight
|
||||
case 46: return 49; // Backslash
|
||||
case 47: return 51; // Semicolon
|
||||
case 48: return 52; // Quote
|
||||
case 49: return 53; // Backquote
|
||||
case 50: return 54; // Comma
|
||||
case 51: return 55; // Period
|
||||
case 52: return 56; // Slash
|
||||
case 53: return 57; // CapsLock
|
||||
case 54: return 58; // F1
|
||||
case 55: return 59; // F2
|
||||
case 56: return 60; // F3
|
||||
case 57: return 61; // F4
|
||||
case 58: return 62; // F5
|
||||
case 59: return 63; // F6
|
||||
case 60: return 64; // F7
|
||||
case 61: return 65; // F8
|
||||
case 62: return 66; // F9
|
||||
case 63: return 67; // F10
|
||||
case 64: return 68; // F11
|
||||
case 65: return 69; // F12
|
||||
case 66: return 70; // PrintScreen
|
||||
case 67: return 73; // Insert
|
||||
case 68: return 74; // Home
|
||||
case 69: return 75; // PageUp
|
||||
case 70: return 76; // Delete
|
||||
case 71: return 77; // End
|
||||
case 72: return 78; // PageDown
|
||||
case 73: return 79; // ArrowRight
|
||||
case 74: return 80; // ArrowLeft
|
||||
case 75: return 81; // ArrowDown
|
||||
case 76: return 82; // ArrowUp
|
||||
case 77: return 224; // ControlLeft
|
||||
case 78: return 225; // ShiftLeft
|
||||
case 79: return 226; // AltLeft
|
||||
case 80: return 227; // MetaLeft
|
||||
case 81: return 228; // ControlRight
|
||||
case 82: return 229; // ShiftRight
|
||||
case 83: return 230; // AltRight
|
||||
case 84: return 231; // MetaRight
|
||||
case 85: return 72; // Pause
|
||||
case 86: return 71; // ScrollLock
|
||||
case 87: return 83; // NumLock
|
||||
case 88: return 101; // ContextMenu
|
||||
case 89: return 84; // NumpadDivide
|
||||
case 90: return 85; // NumpadMultiply
|
||||
case 91: return 86; // NumpadSubtract
|
||||
case 92: return 87; // NumpadAdd
|
||||
case 93: return 88; // NumpadEnter
|
||||
case 94: return 89; // Numpad1
|
||||
case 95: return 90; // Numpad2
|
||||
case 96: return 91; // Numpad3
|
||||
case 97: return 92; // Numpad4
|
||||
case 98: return 93; // Numpad5
|
||||
case 99: return 94; // Numpad6
|
||||
case 100: return 95; // Numpad7
|
||||
case 101: return 96; // Numpad8
|
||||
case 102: return 97; // Numpad9
|
||||
case 103: return 98; // Numpad0
|
||||
case 104: return 99; // NumpadDecimal
|
||||
case 105: return 102; // Power
|
||||
case 106: return 100; // IntlBackslash
|
||||
case 107: return 137; // IntlYen
|
||||
case 108: return 135; // IntlRo
|
||||
case 109: return 136; // KanaMode
|
||||
case 110: return 138; // Convert
|
||||
case 111: return 139; // NonConvert
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
37
hid/arduino/lib/drivers/usb-keymap.h.mako
Normal file
37
hid/arduino/lib/drivers/usb-keymap.h.mako
Normal file
@@ -0,0 +1,37 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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
|
||||
|
||||
<%! import operator %>
|
||||
uint8_t keymapUsb(uint8_t code) {
|
||||
switch (code) {
|
||||
% for km in sorted(keymap, key=operator.attrgetter("mcu_code")):
|
||||
% if km.usb_key.is_modifier:
|
||||
case ${km.mcu_code}: return ${km.usb_key.arduino_modifier_code}; // ${km.web_name}
|
||||
% else:
|
||||
case ${km.mcu_code}: return ${km.usb_key.code}; // ${km.web_name}
|
||||
% endif
|
||||
% endfor
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
49
hid/arduino/patch.py
Normal file
49
hid/arduino/patch.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# https://docs.platformio.org/en/latest/projectconf/advanced_scripting.html
|
||||
|
||||
|
||||
from os.path import exists
|
||||
from os.path import join
|
||||
from os.path import basename
|
||||
|
||||
from typing import Dict
|
||||
|
||||
Import("env")
|
||||
|
||||
|
||||
# =====
|
||||
def _get_pkg_path(name: str) -> str:
|
||||
path = env.PioPlatform().get_package_dir(name)
|
||||
assert exists(path)
|
||||
return path
|
||||
|
||||
|
||||
def _get_libs() -> Dict[str, str]:
|
||||
return {
|
||||
builder.name: builder.path
|
||||
for builder in env.GetLibBuilders()
|
||||
}
|
||||
|
||||
|
||||
def _patch(path: str, patch_path: str) -> None:
|
||||
assert exists(path)
|
||||
flag_path: str = join(path, f".{basename(patch_path)}.done")
|
||||
if not exists(flag_path):
|
||||
# TODO check for failure
|
||||
env.Execute(f"patch -p1 -d {path} < {patch_path}")
|
||||
env.Execute(lambda *_, **__: open(flag_path, "w").close())
|
||||
|
||||
|
||||
# =====
|
||||
if env.GetProjectOption("platform") == "ststm32":
|
||||
_patch(_get_pkg_path("framework-arduinoststm32-maple"), "patches/platformio-stm32f1-no-serial-usb.patch")
|
||||
elif env.GetProjectOption("platform") == "atmelavr":
|
||||
_patch(_get_pkg_path("framework-arduino-avr"), "patches/arduino-main-no-usb.patch")
|
||||
_patch(_get_pkg_path("framework-arduino-avr"), "patches/arduino-optional-cdc.patch")
|
||||
_patch(_get_pkg_path("framework-arduino-avr"), "patches/arduino-get-plugged-endpoint.patch")
|
||||
|
||||
_libs = _get_libs()
|
||||
_patch(_libs["HID-Project"], "patches/hid-shut-up.patch")
|
||||
_patch(_libs["HID-Project"], "patches/hid-no-singletones.patch")
|
||||
_patch(_libs["HID-Project"], "patches/hid-win98.patch")
|
||||
else:
|
||||
assert(False)
|
||||
11
hid/arduino/patches/arduino-get-plugged-endpoint.patch
Normal file
11
hid/arduino/patches/arduino-get-plugged-endpoint.patch
Normal file
@@ -0,0 +1,11 @@
|
||||
--- a/cores/arduino/PluggableUSB.h 2019-05-16 15:52:01.000000000 +0300
|
||||
+++ b/cores/arduino/PluggableUSB.h 2020-11-14 20:57:30.942432544 +0300
|
||||
@@ -31,6 +31,8 @@
|
||||
numEndpoints(numEps), numInterfaces(numIfs), endpointType(epType)
|
||||
{ }
|
||||
|
||||
+ uint8_t getPluggedEndpoint() { return pluggedEndpoint; }
|
||||
+
|
||||
protected:
|
||||
virtual bool setup(USBSetup& setup) = 0;
|
||||
virtual int getInterface(uint8_t* interfaceCount) = 0;
|
||||
24
hid/arduino/patches/arduino-main-no-usb.patch
Normal file
24
hid/arduino/patches/arduino-main-no-usb.patch
Normal file
@@ -0,0 +1,24 @@
|
||||
diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp
|
||||
index 434cd40..7aba76f 100644
|
||||
--- a/cores/arduino/main.cpp
|
||||
+++ b/cores/arduino/main.cpp
|
||||
@@ -36,15 +36,15 @@ int main(void)
|
||||
|
||||
initVariant();
|
||||
|
||||
-#if defined(USBCON)
|
||||
- USBDevice.attach();
|
||||
-#endif
|
||||
+// #if defined(USBCON)
|
||||
+// USBDevice.attach();
|
||||
+// #endif
|
||||
|
||||
setup();
|
||||
|
||||
for (;;) {
|
||||
loop();
|
||||
- if (serialEventRun) serialEventRun();
|
||||
+ // if (serialEventRun) serialEventRun();
|
||||
}
|
||||
|
||||
return 0;
|
||||
141
hid/arduino/patches/arduino-optional-cdc.patch
Normal file
141
hid/arduino/patches/arduino-optional-cdc.patch
Normal file
@@ -0,0 +1,141 @@
|
||||
From 8e823d276f939d79b2d323fad675fb8442a718c2 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Gibson <metalcaedes@gmail.com>
|
||||
Date: Tue, 5 Jan 2021 13:48:43 +0100
|
||||
Subject: [PATCH] Allow disabling CDC with -DCDC_DISABLED
|
||||
|
||||
https://github.com/arduino/ArduinoCore-avr/pull/383
|
||||
|
||||
Sometimes Arduino-based USB devices don't work because some hardware
|
||||
(like KVM switches) gets confused by the CDC sub-devices.
|
||||
This change makes it relatively easy to disable CDC at compiletime.
|
||||
Disabling it of course means that the serial console won't work anymore,
|
||||
so you need to use the reset button when flashing.
|
||||
|
||||
CDC_DISABLED is also used in ArduinoCore-samd for the same purpose.
|
||||
|
||||
based on
|
||||
https://github.com/gdsports/usb-metamorph/tree/master/USBSerPassThruLine
|
||||
|
||||
See also https://github.com/NicoHood/HID/issues/225 and
|
||||
https://github.com/arduino/Arduino/issues/6387 and
|
||||
https://forum.arduino.cc/index.php?topic=545288.msg3717028#msg3717028
|
||||
---
|
||||
cores/arduino/CDC.cpp | 8 ++++++++
|
||||
cores/arduino/USBCore.cpp | 18 +++++++++++++++++-
|
||||
cores/arduino/USBDesc.h | 17 +++++++++++++++++
|
||||
3 files changed, 42 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/cores/arduino/CDC.cpp b/cores/arduino/CDC.cpp
|
||||
index 4ff6b9b4..7d5afaab 100644
|
||||
--- a/cores/arduino/CDC.cpp
|
||||
+++ b/cores/arduino/CDC.cpp
|
||||
@@ -22,6 +22,13 @@
|
||||
|
||||
#if defined(USBCON)
|
||||
|
||||
+#ifndef CDC_ENABLED
|
||||
+
|
||||
+#warning "! Disabled serial console via USB (CDC)!"
|
||||
+#warning "! With this change you'll have to use the Arduino's reset button/pin to flash (upload)!"
|
||||
+
|
||||
+#else // CDC not disabled
|
||||
+
|
||||
typedef struct
|
||||
{
|
||||
u32 dwDTERate;
|
||||
@@ -299,4 +306,5 @@ int32_t Serial_::readBreak() {
|
||||
|
||||
Serial_ Serial;
|
||||
|
||||
+#endif /* if defined(CDC_ENABLED) */
|
||||
#endif /* if defined(USBCON) */
|
||||
diff --git a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp
|
||||
index dc6bc387..93352387 100644
|
||||
--- a/cores/arduino/USBCore.cpp
|
||||
+++ b/cores/arduino/USBCore.cpp
|
||||
@@ -69,8 +69,18 @@ const u8 STRING_MANUFACTURER[] PROGMEM = USB_MANUFACTURER;
|
||||
#define DEVICE_CLASS 0x02
|
||||
|
||||
// DEVICE DESCRIPTOR
|
||||
+
|
||||
+#ifdef CDC_ENABLED
|
||||
const DeviceDescriptor USB_DeviceDescriptorIAD =
|
||||
D_DEVICE(0xEF,0x02,0x01,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,ISERIAL,1);
|
||||
+#else // CDC_DISABLED
|
||||
+// The default descriptor uses USB class OxEF, subclass 0x02 with protocol 1
|
||||
+// which means "Interface Association Descriptor" - that's needed for the CDC,
|
||||
+// but doesn't make much sense as a default for custom devices when CDC is disabled.
|
||||
+// (0x00 means "Use class information in the Interface Descriptors" which should be generally ok)
|
||||
+const DeviceDescriptor USB_DeviceDescriptorIAD =
|
||||
+ D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,ISERIAL,1);
|
||||
+#endif
|
||||
|
||||
//==================================================================
|
||||
//==================================================================
|
||||
@@ -328,10 +338,12 @@ int USB_Send(u8 ep, const void* d, int len)
|
||||
u8 _initEndpoints[USB_ENDPOINTS] =
|
||||
{
|
||||
0, // Control Endpoint
|
||||
-
|
||||
+
|
||||
+#ifdef CDC_ENABLED
|
||||
EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM
|
||||
EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT
|
||||
EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN
|
||||
+#endif
|
||||
|
||||
// Following endpoints are automatically initialized to 0
|
||||
};
|
||||
@@ -373,10 +385,12 @@ void InitEndpoints()
|
||||
static
|
||||
bool ClassInterfaceRequest(USBSetup& setup)
|
||||
{
|
||||
+#ifdef CDC_ENABLED
|
||||
u8 i = setup.wIndex;
|
||||
|
||||
if (CDC_ACM_INTERFACE == i)
|
||||
return CDC_Setup(setup);
|
||||
+#endif
|
||||
|
||||
#ifdef PLUGGABLE_USB_ENABLED
|
||||
return PluggableUSB().setup(setup);
|
||||
@@ -466,7 +480,9 @@ static u8 SendInterfaces()
|
||||
{
|
||||
u8 interfaces = 0;
|
||||
|
||||
+#ifdef CDC_ENABLED
|
||||
CDC_GetInterface(&interfaces);
|
||||
+#endif
|
||||
|
||||
#ifdef PLUGGABLE_USB_ENABLED
|
||||
PluggableUSB().getInterface(&interfaces);
|
||||
diff --git a/cores/arduino/USBDesc.h b/cores/arduino/USBDesc.h
|
||||
index c0dce079..b55ac20b 100644
|
||||
--- a/cores/arduino/USBDesc.h
|
||||
+++ b/cores/arduino/USBDesc.h
|
||||
@@ -26,8 +26,25 @@
|
||||
|
||||
#define ISERIAL_MAX_LEN 20
|
||||
|
||||
+// Uncomment the following line or pass -DCDC_DISABLED to the compiler
|
||||
+// to disable CDC (serial console via USB).
|
||||
+// That's useful if you want to create an USB device (like an USB Boot Keyboard)
|
||||
+// that works even with problematic devices (like KVM switches).
|
||||
+// Keep in mind that with this change you'll have to use the Arduino's
|
||||
+// reset button to be able to flash it.
|
||||
+//#define CDC_DISABLED
|
||||
+
|
||||
+#ifndef CDC_DISABLED
|
||||
+#define CDC_ENABLED
|
||||
+#endif
|
||||
+
|
||||
+#ifdef CDC_ENABLED
|
||||
#define CDC_INTERFACE_COUNT 2
|
||||
#define CDC_ENPOINT_COUNT 3
|
||||
+#else // CDC_DISABLED
|
||||
+#define CDC_INTERFACE_COUNT 0
|
||||
+#define CDC_ENPOINT_COUNT 0
|
||||
+#endif
|
||||
|
||||
#define CDC_ACM_INTERFACE 0 // CDC ACM
|
||||
#define CDC_DATA_INTERFACE 1 // CDC Data
|
||||
66
hid/arduino/patches/hid-no-singletones.patch
Normal file
66
hid/arduino/patches/hid-no-singletones.patch
Normal file
@@ -0,0 +1,66 @@
|
||||
diff -u -r a/src/SingleReport/BootKeyboard.cpp b/src/SingleReport/BootKeyboard.cpp
|
||||
--- a/src/SingleReport/BootKeyboard.cpp 2019-07-13 21:16:23.000000000 +0300
|
||||
+++ b/src/SingleReport/BootKeyboard.cpp 2020-11-17 18:59:36.618815374 +0300
|
||||
@@ -206,6 +206,6 @@
|
||||
}
|
||||
|
||||
|
||||
-BootKeyboard_ BootKeyboard;
|
||||
+//BootKeyboard_ BootKeyboard;
|
||||
|
||||
|
||||
diff -u -r a/src/SingleReport/BootKeyboard.h b/src/SingleReport/BootKeyboard.h
|
||||
--- a/src/SingleReport/BootKeyboard.h 2019-07-13 21:16:23.000000000 +0300
|
||||
+++ b/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 a/src/SingleReport/BootMouse.cpp b/src/SingleReport/BootMouse.cpp
|
||||
--- a/src/SingleReport/BootMouse.cpp 2019-07-13 21:16:23.000000000 +0300
|
||||
+++ b/src/SingleReport/BootMouse.cpp 2020-11-17 18:59:22.859113905 +0300
|
||||
@@ -139,6 +139,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
-BootMouse_ BootMouse;
|
||||
+//BootMouse_ BootMouse;
|
||||
|
||||
|
||||
diff -u -r a/src/SingleReport/BootMouse.h b/src/SingleReport/BootMouse.h
|
||||
--- a/src/SingleReport/BootMouse.h 2019-07-13 21:16:23.000000000 +0300
|
||||
+++ b/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 a/src/SingleReport/SingleAbsoluteMouse.cpp b/src/SingleReport/SingleAbsoluteMouse.cpp
|
||||
--- a/src/SingleReport/SingleAbsoluteMouse.cpp 2020-11-17 18:39:35.314843889 +0300
|
||||
+++ b/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 a/src/SingleReport/SingleAbsoluteMouse.h b/src/SingleReport/SingleAbsoluteMouse.h
|
||||
--- a/src/SingleReport/SingleAbsoluteMouse.h 2019-07-13 21:16:23.000000000 +0300
|
||||
+++ b/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;
|
||||
|
||||
|
||||
16
hid/arduino/patches/hid-shut-up.patch
Normal file
16
hid/arduino/patches/hid-shut-up.patch
Normal file
@@ -0,0 +1,16 @@
|
||||
diff --git a/src/KeyboardLayouts/ImprovedKeylayouts.h b/src/KeyboardLayouts/ImprovedKeylayouts.h
|
||||
index 03b92a0..ee0bab4 100644
|
||||
--- a/src/KeyboardLayouts/ImprovedKeylayouts.h
|
||||
+++ b/src/KeyboardLayouts/ImprovedKeylayouts.h
|
||||
@@ -51,9 +51,9 @@ enum KeyboardLeds : uint8_t {
|
||||
#ifndef HID_CUSTOM_LAYOUT
|
||||
#define HID_CUSTOM_LAYOUT
|
||||
#define LAYOUT_US_ENGLISH
|
||||
- #pragma message "Using default ASCII layout for keyboard modules"
|
||||
+ //#pragma message "Using default ASCII layout for keyboard modules"
|
||||
#else
|
||||
- #pragma message "Using custom layout for keyboard modules"
|
||||
+ //#pragma message "Using custom layout for keyboard modules"
|
||||
#endif
|
||||
|
||||
// Hut1_12v2.pdf
|
||||
82
hid/arduino/patches/hid-win98.patch
Normal file
82
hid/arduino/patches/hid-win98.patch
Normal file
@@ -0,0 +1,82 @@
|
||||
From 82c8aee0ae3739eb22ae11b8f527d0c50b0ced31 Mon Sep 17 00:00:00 2001
|
||||
From: Maxim Devaev <mdevaev@gmail.com>
|
||||
Date: Sat, 14 Aug 2021 10:10:06 +0300
|
||||
Subject: [PATCH] Fixed absolute mouse positioning in Windows 98
|
||||
|
||||
Windows 98 contains a buggy HID driver. It allows you to move only
|
||||
on the upper right quarter of the screen. Yes, this is indeed exceeding
|
||||
the maximum value from the HID report. Yes, it really should work that way.
|
||||
|
||||
VirtualBox has a similar fix, but with a shift in the other direction
|
||||
(I didn't dig the details). I suppose it can be fixed somehow with a special
|
||||
HID descriptor, but the proposed fix is simpler and really works.
|
||||
|
||||
Related: https://github.com/pikvm/pikvm/issues/159
|
||||
---
|
||||
src/HID-APIs/AbsoluteMouseAPI.h | 3 +++
|
||||
src/HID-APIs/AbsoluteMouseAPI.hpp | 17 ++++++++++++++++-
|
||||
2 files changed, 19 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/HID-APIs/AbsoluteMouseAPI.h b/src/HID-APIs/AbsoluteMouseAPI.h
|
||||
index 66dbe42..c99e6a5 100644
|
||||
--- a/src/HID-APIs/AbsoluteMouseAPI.h
|
||||
+++ b/src/HID-APIs/AbsoluteMouseAPI.h
|
||||
@@ -57,6 +57,7 @@ class AbsoluteMouseAPI
|
||||
int16_t xAxis;
|
||||
int16_t yAxis;
|
||||
uint8_t _buttons;
|
||||
+ bool win98_fix;
|
||||
inline void buttons(uint8_t b);
|
||||
|
||||
inline int16_t qadd16(int16_t base, int16_t increment);
|
||||
@@ -65,6 +66,8 @@ class AbsoluteMouseAPI
|
||||
inline AbsoluteMouseAPI(void);
|
||||
inline void begin(void);
|
||||
inline void end(void);
|
||||
+ inline void setWin98FixEnabled(bool enabled);
|
||||
+ inline bool isWin98FixEnabled(void);
|
||||
|
||||
inline void click(uint8_t b = MOUSE_LEFT);
|
||||
inline void moveTo(int x, int y, signed char wheel = 0);
|
||||
diff --git a/src/HID-APIs/AbsoluteMouseAPI.hpp b/src/HID-APIs/AbsoluteMouseAPI.hpp
|
||||
index 0913c8a..0b9aaa2 100644
|
||||
--- a/src/HID-APIs/AbsoluteMouseAPI.hpp
|
||||
+++ b/src/HID-APIs/AbsoluteMouseAPI.hpp
|
||||
@@ -51,7 +51,7 @@ int16_t AbsoluteMouseAPI::qadd16(int16_t base, int16_t increment) {
|
||||
}
|
||||
|
||||
AbsoluteMouseAPI::AbsoluteMouseAPI(void):
|
||||
-xAxis(0), yAxis(0), _buttons(0)
|
||||
+xAxis(0), yAxis(0), _buttons(0), win98_fix(false)
|
||||
{
|
||||
// Empty
|
||||
}
|
||||
@@ -66,6 +66,14 @@ void AbsoluteMouseAPI::end(void){
|
||||
moveTo(xAxis, yAxis, 0);
|
||||
}
|
||||
|
||||
+void AbsoluteMouseAPI::setWin98FixEnabled(bool enabled){
|
||||
+ win98_fix = enabled;
|
||||
+}
|
||||
+
|
||||
+bool AbsoluteMouseAPI::isWin98FixEnabled(void){
|
||||
+ return win98_fix;
|
||||
+}
|
||||
+
|
||||
void AbsoluteMouseAPI::click(uint8_t b){
|
||||
_buttons = b;
|
||||
moveTo(xAxis, yAxis, 0);
|
||||
@@ -84,6 +92,13 @@ void AbsoluteMouseAPI::moveTo(int x, int y, signed char wheel){
|
||||
// See detauls in AbsoluteMouse sources and here: https://github.com/NicoHood/HID/pull/306
|
||||
report.xAxis = ((int32_t)x + 32768) / 2;
|
||||
report.yAxis = ((int32_t)y + 32768) / 2;
|
||||
+ if (win98_fix) {
|
||||
+ // Windows 98 contains a buggy driver.
|
||||
+ // Yes, this is indeed exceeding the maximum value from the HID report.
|
||||
+ // Yes, it really should work that way.
|
||||
+ report.xAxis <<= 1;
|
||||
+ report.yAxis <<= 1;
|
||||
+ }
|
||||
report.wheel = wheel;
|
||||
SendReport(&report, sizeof(report));
|
||||
}
|
||||
11
hid/arduino/patches/platformio-stm32f1-no-serial-usb.patch
Normal file
11
hid/arduino/patches/platformio-stm32f1-no-serial-usb.patch
Normal file
@@ -0,0 +1,11 @@
|
||||
--- aaa/tools/platformio-build-stm32f1.py 2022-07-16 18:54:42.536695468 +0200
|
||||
+++ bbb/tools/platformio-build-stm32f1.py 2022-07-16 19:03:10.988056751 +0200
|
||||
@@ -121,7 +121,7 @@
|
||||
env.Append(
|
||||
|
||||
CPPDEFINES=[
|
||||
|
||||
("CONFIG_MAPLE_MINI_NO_DISABLE_DEBUG", 1),
|
||||
|
||||
- "SERIAL_USB"
|
||||
|
||||
119
hid/arduino/platformio-avr.ini
Normal file
119
hid/arduino/platformio-avr.ini
Normal file
@@ -0,0 +1,119 @@
|
||||
# http://docs.platformio.org/page/projectconf.html
|
||||
[platformio]
|
||||
core_dir = ./.platformio/
|
||||
|
||||
[env]
|
||||
platform = atmelavr
|
||||
board = micro
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
git+https://github.com/NicoHood/HID#2.8.2
|
||||
git+https://github.com/Harvie/ps2dev#v0.0.3
|
||||
digitalWriteFast@1.0.0
|
||||
HID@1.0
|
||||
drivers-avr
|
||||
extra_scripts =
|
||||
pre:avrdude.py
|
||||
post:patch.py
|
||||
platform_packages =
|
||||
tool-avrdude
|
||||
|
||||
[_common]
|
||||
build_flags =
|
||||
-DHID_USB_CHECK_ENDPOINT
|
||||
# ----- The default config with dynamic switching -----
|
||||
-DHID_DYNAMIC
|
||||
-DHID_WITH_USB
|
||||
-DHID_SET_USB_KBD
|
||||
-DHID_SET_USB_MOUSE_ABS
|
||||
# ----- The USB ABS fix for Windows 98 (https://github.com/pikvm/pikvm/issues/159) -----
|
||||
# -DHID_WITH_USB_WIN98
|
||||
# ----- 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
|
||||
|
||||
[_non_aum_pinout] =
|
||||
build_flags =
|
||||
-DHID_PS2_KBD_CLOCK_PIN=7
|
||||
-DHID_PS2_KBD_DATA_PIN=5
|
||||
|
||||
|
||||
# ===== Serial =====
|
||||
[env:serial]
|
||||
extends =
|
||||
_common
|
||||
_non_aum_pinout
|
||||
build_flags =
|
||||
${_common.build_flags}
|
||||
${_non_aum_pinout.build_flags}
|
||||
-DCMD_SERIAL=Serial1
|
||||
-DCMD_SERIAL_SPEED=115200
|
||||
-DCMD_SERIAL_TIMEOUT=100000
|
||||
upload_port = /dev/ttyACM0
|
||||
|
||||
|
||||
# ===== RPi SPI =====
|
||||
[env:bootloader_spi]
|
||||
upload_protocol = rpi
|
||||
upload_flags =
|
||||
-C
|
||||
+avrdude-rpi.conf
|
||||
-P
|
||||
/dev/spidev0.0:/dev/gpiochip0
|
||||
extra_scripts =
|
||||
pre:avrdude.py
|
||||
|
||||
[_common_spi]
|
||||
extends =
|
||||
_common
|
||||
build_flags =
|
||||
${_common.build_flags}
|
||||
-DCMD_SPI
|
||||
-DCDC_DISABLED
|
||||
upload_protocol = custom
|
||||
upload_flags =
|
||||
-C
|
||||
$PROJECT_PACKAGES_DIR/tool-avrdude/avrdude.conf
|
||||
-C
|
||||
+avrdude-rpi.conf
|
||||
-P
|
||||
/dev/spidev0.0:/dev/gpiochip0
|
||||
-c
|
||||
rpi
|
||||
-p
|
||||
$BOARD_MCU
|
||||
upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i
|
||||
|
||||
[env:spi]
|
||||
extends =
|
||||
_common_spi
|
||||
_non_aum_pinout
|
||||
build_flags =
|
||||
${_common_spi.build_flags}
|
||||
${_non_aum_pinout.build_flags}
|
||||
|
||||
[env:aum]
|
||||
extends =
|
||||
_common_spi
|
||||
build_flags =
|
||||
${_common_spi.build_flags}
|
||||
-DAUM
|
||||
-DAUM_IS_USB_POWERED_PIN=A4
|
||||
-DAUM_SET_USB_VBUS_PIN=11
|
||||
-DAUM_SET_USB_CONNECTED_PIN=A5
|
||||
-DHID_PS2_KBD_VBUS_PIN=8
|
||||
-DHID_PS2_KBD_CLOCK_PIN=10
|
||||
-DHID_PS2_KBD_DATA_PIN=5
|
||||
-DHID_PS2_MOUSE_VBUS_PIN=6
|
||||
-DHID_PS2_MOUSE_CLOCK_PIN=9
|
||||
-DHID_PS2_MOUSE_DATA_PIN=13
|
||||
52
hid/arduino/platformio-stm32.ini
Normal file
52
hid/arduino/platformio-stm32.ini
Normal file
@@ -0,0 +1,52 @@
|
||||
# http://docs.platformio.org/page/projectconf.html
|
||||
[platformio]
|
||||
core_dir = ./.platformio/
|
||||
|
||||
[env]
|
||||
framework = arduino
|
||||
platform = ststm32
|
||||
board = genericSTM32F103C8
|
||||
board_build.core = maple
|
||||
extra_scripts =
|
||||
post:patch.py
|
||||
|
||||
[_common]
|
||||
lib_deps =
|
||||
git+https://github.com/ZulNs/STM32F1_RTC#v1.1.0
|
||||
git+https://github.com/arpruss/USBComposite_stm32f1#3c58f97eb006ee9cd1fb4fd55ac4faeeaead0974
|
||||
drivers-stm32
|
||||
build_flags =
|
||||
# ----- The default config with dynamic switching -----
|
||||
-DHID_DYNAMIC
|
||||
-DHID_WITH_USB
|
||||
-DHID_SET_USB_KBD
|
||||
-DHID_SET_USB_MOUSE_ABS
|
||||
|
||||
[_serial]
|
||||
extends =
|
||||
_common
|
||||
build_flags =
|
||||
${_common.build_flags}
|
||||
-DCMD_SERIAL=Serial1
|
||||
-DCMD_SERIAL_SPEED=115200
|
||||
-DCMD_SERIAL_TIMEOUT=100000
|
||||
# ===== Serial =====
|
||||
[env:serial]
|
||||
extends =
|
||||
_serial
|
||||
upload_flags = -c set CPUTAPID 0x2ba01477
|
||||
debug_tool= stlink
|
||||
debug_build_flags = -Og -ggdb3 -g3
|
||||
debug_server =
|
||||
.platformio/packages/tool-openocd/bin/openocd
|
||||
-s .platformio/packages/tool-openocd/scripts
|
||||
-f interface/stlink.cfg
|
||||
-c "transport select hla_swd"
|
||||
-c "set CPUTAPID 0x2ba01477"
|
||||
-f target/stm32f1x.cfg
|
||||
-c "reset_config none"
|
||||
; build_type = debug
|
||||
[env:patch]
|
||||
; platformio-stm32f1-no-serial-usb.patch requires to running build again
|
||||
; fake target was added to avoid error during first build
|
||||
src_filter = -<src/>
|
||||
253
hid/arduino/src/main.cpp
Normal file
253
hid/arduino/src/main.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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();
|
||||
}
|
||||
122
hid/arduino/src/outputs.h
Normal file
122
hid/arduino/src/outputs.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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;
|
||||
};
|
||||
142
hid/arduino/src/proto.h
Normal file
142
hid/arduino/src/proto.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# 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);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user