moved arduino hid to hid/arduino

This commit is contained in:
Maxim Devaev
2023-07-31 02:17:23 +03:00
parent cf44668af9
commit 1a8f98a64f
50 changed files with 5 additions and 6 deletions

0
hid/arduino/lib/.gitignore vendored Normal file
View File

View 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);
}
};
}

View 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
}
}

View 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;
};

View 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
}
}

View 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
}
}

View 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

View 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;
};
}

View 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

View 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

View 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;
};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

View 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;
};
}

View 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
}
}

View 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;
};
}

View 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;
};
}

View 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;
};
}

View 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;
};
}

View 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);
}

View 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) {}
};
}

View 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;
};
}

View 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;
};
}

View 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);
};
}

View 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;
}
};
}

View 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() {}
};
}

View 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

View 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) {}
};
}

View 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)
);
}

View 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);

View 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;
}
}

View 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;
}
}