mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-30 01:21:54 +08:00
multihid firmware
This commit is contained in:
373
hid/src/main.cpp
373
hid/src/main.cpp
@@ -29,15 +29,13 @@
|
||||
#ifdef CMD_SPI
|
||||
# include <SPI.h>
|
||||
#endif
|
||||
#ifdef HID_DYNAMIC
|
||||
# include <avr/eeprom.h>
|
||||
#endif
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#if defined(HID_USB_KBD) || defined(HID_USB_MOUSE)
|
||||
# include "usb/hid.h"
|
||||
#endif
|
||||
#ifdef HID_PS2_KBD
|
||||
# include "ps2/hid.h"
|
||||
#endif
|
||||
#include "usb/hid.h"
|
||||
#include "ps2/hid.h"
|
||||
|
||||
|
||||
// #define CMD_SERIAL Serial1
|
||||
@@ -48,98 +46,176 @@
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#ifdef HID_USB_KBD
|
||||
UsbHidKeyboard hid_kbd;
|
||||
#elif defined(HID_PS2_KBD)
|
||||
Ps2HidKeyboard hid_kbd;
|
||||
#endif
|
||||
#ifdef HID_USB_MOUSE
|
||||
UsbHidMouse hid_mouse;
|
||||
static UsbKeyboard *_usb_kbd = NULL;
|
||||
static UsbMouseAbsolute *_usb_mouse_abs = NULL;
|
||||
static UsbMouseRelative *_usb_mouse_rel = NULL;
|
||||
|
||||
static Ps2Keyboard *_ps2_kbd = NULL;
|
||||
|
||||
#ifdef HID_DYNAMIC
|
||||
static bool _reset_required = false;
|
||||
|
||||
static void _setOutputs(uint8_t outputs) {
|
||||
uint8_t data[8] = {0};
|
||||
data[0] = PROTO::MAGIC;
|
||||
data[1] = outputs;
|
||||
PROTO::split16(PROTO::crc16(data, 6), &data[6], &data[7]);
|
||||
eeprom_update_block(data, 0, 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _initOutputs() {
|
||||
uint8_t data[8];
|
||||
# ifdef HID_DYNAMIC
|
||||
eeprom_read_block(data, 0, 8);
|
||||
if (
|
||||
PROTO::crc16(data, 6) != PROTO::merge8(data[6], data[7])
|
||||
|| data[0] != PROTO::MAGIC
|
||||
) {
|
||||
# endif
|
||||
data[1] = 0;
|
||||
|
||||
# if defined(HID_WITH_USB) && defined(HID_SET_USB_KBD)
|
||||
data[1] |= PROTO::OUTPUTS::KEYBOARD::USB;
|
||||
# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_KBD)
|
||||
data[1] |= PROTO::OUTPUTS::KEYBOARD::PS2;
|
||||
# endif
|
||||
# if defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_ABS)
|
||||
data[1] |= PROTO::OUTPUTS::MOUSE::USB_ABS;
|
||||
# elif defined(HID_WITH_USB) && defined(HID_SET_USB_MOUSE_REL)
|
||||
data[1] |= PROTO::OUTPUTS::MOUSE::USB_REL;
|
||||
# elif defined(HID_WITH_PS2) && defined(HID_SET_PS2_MOUSE)
|
||||
data[1] |= PROTO::OUTPUTS::MOUSE::PS2;
|
||||
# endif
|
||||
|
||||
# ifdef HID_DYNAMIC
|
||||
_setOutputs(data[1]);
|
||||
}
|
||||
# endif
|
||||
|
||||
uint8_t kbd = data[1] & PROTO::OUTPUTS::KEYBOARD::MASK;
|
||||
switch (kbd) {
|
||||
# ifdef HID_WITH_USB
|
||||
case PROTO::OUTPUTS::KEYBOARD::USB: _usb_kbd = new UsbKeyboard(); break;
|
||||
# endif
|
||||
# ifdef HID_WITH_PS2
|
||||
case PROTO::OUTPUTS::KEYBOARD::PS2: _ps2_kbd = new Ps2Keyboard(); break;
|
||||
# endif
|
||||
}
|
||||
|
||||
uint8_t mouse = data[1] & PROTO::OUTPUTS::MOUSE::MASK;
|
||||
switch (mouse) {
|
||||
# ifdef HID_WITH_USB
|
||||
case PROTO::OUTPUTS::MOUSE::USB_ABS: _usb_mouse_abs = new UsbMouseAbsolute(); break;
|
||||
case PROTO::OUTPUTS::MOUSE::USB_REL: _usb_mouse_rel = new UsbMouseRelative(); break;
|
||||
# endif
|
||||
}
|
||||
|
||||
USBDevice.attach();
|
||||
|
||||
switch (kbd) {
|
||||
# ifdef HID_WITH_USB
|
||||
case PROTO::OUTPUTS::KEYBOARD::USB: _usb_kbd->begin(); break;
|
||||
# endif
|
||||
# ifdef HID_WITH_PS2
|
||||
case PROTO::OUTPUTS::KEYBOARD::PS2: _ps2_kbd->begin(); break;
|
||||
# endif
|
||||
}
|
||||
|
||||
switch (mouse) {
|
||||
# ifdef HID_WITH_USB
|
||||
case PROTO::OUTPUTS::MOUSE::USB_ABS: _usb_mouse_abs->begin(); break;
|
||||
case PROTO::OUTPUTS::MOUSE::USB_REL: _usb_mouse_rel->begin(); break;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
uint8_t cmdPong(const uint8_t *_=NULL) { // 0 bytes
|
||||
return (
|
||||
PROTO::PONG::PREFIX
|
||||
| hid_kbd.getLedsAs(PROTO::PONG::CAPS, PROTO::PONG::SCROLL, PROTO::PONG::NUM)
|
||||
| (hid_kbd.isOnline() ? 0 : PROTO::PONG::KEYBOARD_OFFLINE)
|
||||
# ifdef HID_USB_MOUSE
|
||||
| (hid_mouse.isOnline() ? 0 : PROTO::PONG::MOUSE_OFFLINE)
|
||||
# endif
|
||||
);
|
||||
}
|
||||
|
||||
uint8_t cmdResetHid(const uint8_t *_) { // 0 bytes
|
||||
# ifdef HID_USB_KBD
|
||||
hid_kbd.reset();
|
||||
static void _cmdSetOutputs(const uint8_t *data) { // 1 bytes
|
||||
# ifdef HID_DYNAMIC
|
||||
_setOutputs(data[0]);
|
||||
_reset_required = true;
|
||||
# endif
|
||||
# ifdef HID_USB_MOUSE
|
||||
hid_mouse.reset();
|
||||
# endif
|
||||
return cmdPong();
|
||||
}
|
||||
|
||||
uint8_t cmdKeyEvent(const uint8_t *buffer) { // 2 bytes
|
||||
hid_kbd.sendKey(buffer[0], buffer[1]);
|
||||
return cmdPong();
|
||||
static void _cmdClearHid(const uint8_t *_) { // 0 bytes
|
||||
if (_usb_kbd) {
|
||||
_usb_kbd->clear();
|
||||
}
|
||||
if (_usb_mouse_abs) {
|
||||
_usb_mouse_abs->clear();
|
||||
} else if (_usb_mouse_rel) {
|
||||
_usb_mouse_rel->clear();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t cmdMouseButtonEvent(const uint8_t *buffer) { // 2 bytes
|
||||
# ifdef HID_USB_MOUSE
|
||||
uint8_t main_state = buffer[0];
|
||||
uint8_t extra_state = buffer[1];
|
||||
static void _cmdKeyEvent(const uint8_t *data) { // 2 bytes
|
||||
if (_usb_kbd) {
|
||||
_usb_kbd->sendKey(data[0], data[1]);
|
||||
} else if (_ps2_kbd) {
|
||||
_ps2_kbd->sendKey(data[0], data[1]);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
hid_mouse.sendButtons(
|
||||
MOUSE_PAIR(main_state, LEFT),
|
||||
MOUSE_PAIR(main_state, RIGHT),
|
||||
MOUSE_PAIR(main_state, MIDDLE),
|
||||
MOUSE_PAIR(extra_state, EXTRA_UP),
|
||||
MOUSE_PAIR(extra_state, EXTRA_DOWN)
|
||||
);
|
||||
# define SEND_BUTTONS(_hid) \
|
||||
_hid->sendButtons( \
|
||||
MOUSE_PAIR(data[0], LEFT), \
|
||||
MOUSE_PAIR(data[0], RIGHT), \
|
||||
MOUSE_PAIR(data[0], MIDDLE), \
|
||||
MOUSE_PAIR(data[1], EXTRA_UP), \
|
||||
MOUSE_PAIR(data[1], EXTRA_DOWN) \
|
||||
);
|
||||
if (_usb_mouse_abs) {
|
||||
SEND_BUTTONS(_usb_mouse_abs);
|
||||
} else if (_usb_mouse_rel) {
|
||||
SEND_BUTTONS(_usb_mouse_rel);
|
||||
}
|
||||
# undef SEND_BUTTONS
|
||||
# undef MOUSE_PAIR
|
||||
# endif
|
||||
return cmdPong();
|
||||
}
|
||||
|
||||
uint8_t cmdMouseMoveEvent(const uint8_t *buffer) { // 4 bytes
|
||||
# ifdef HID_USB_MOUSE
|
||||
int x = (int)buffer[0] << 8;
|
||||
x |= (int)buffer[1];
|
||||
x = (x + 32768) / 2; // See /kvmd/apps/otg/hid/keyboard.py for details
|
||||
|
||||
int y = (int)buffer[2] << 8;
|
||||
y |= (int)buffer[3];
|
||||
y = (y + 32768) / 2; // See /kvmd/apps/otg/hid/keyboard.py for details
|
||||
|
||||
hid_mouse.sendMove(x, y);
|
||||
# endif
|
||||
return cmdPong();
|
||||
static void _cmdMouseMoveEvent(const uint8_t *data) { // 4 bytes
|
||||
// See /kvmd/apps/otg/hid/keyboard.py for details
|
||||
if (_usb_mouse_abs) {
|
||||
_usb_mouse_abs->sendMove(
|
||||
(PROTO::merge8_int(data[0], data[1]) + 32768) / 2,
|
||||
(PROTO::merge8_int(data[2], data[3]) + 32768) / 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t cmdMouseWheelEvent(const uint8_t *buffer) { // 2 bytes
|
||||
# ifdef HID_USB_MOUSE
|
||||
hid_mouse.sendWheel(buffer[1]); // Y only, X is not supported
|
||||
# endif
|
||||
return cmdPong();
|
||||
static void _cmdMouseRelativeEvent(const uint8_t *data) { // 2 bytes
|
||||
if (_usb_mouse_rel) {
|
||||
_usb_mouse_rel->sendRelative(data[0], data[1]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t handleCmdBuffer(const uint8_t *buffer) { // 8 bytes
|
||||
uint16_t crc = (uint16_t)buffer[6] << 8;
|
||||
crc |= (uint16_t)buffer[7];
|
||||
static void _cmdMouseWheelEvent(const uint8_t *data) { // 2 bytes
|
||||
// Y only, X is not supported
|
||||
if (_usb_mouse_abs) {
|
||||
_usb_mouse_abs->sendWheel(data[1]);
|
||||
} else if (_usb_mouse_rel) {
|
||||
_usb_mouse_rel->sendWheel(data[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (protoCrc16(buffer, 6) == crc) {
|
||||
# define HANDLE(_handler) { return _handler(buffer + 2); }
|
||||
switch (buffer[1]) {
|
||||
case PROTO::CMD::RESET_HID: HANDLE(cmdResetHid);
|
||||
case PROTO::CMD::KEYBOARD::KEY: HANDLE(cmdKeyEvent);
|
||||
case PROTO::CMD::MOUSE::BUTTON: HANDLE(cmdMouseButtonEvent);
|
||||
case PROTO::CMD::MOUSE::MOVE: HANDLE(cmdMouseMoveEvent);
|
||||
case PROTO::CMD::MOUSE::WHEEL: HANDLE(cmdMouseWheelEvent);
|
||||
case PROTO::CMD::PING: HANDLE(cmdPong);
|
||||
static uint8_t _handleRequest(const uint8_t *data) { // 8 bytes
|
||||
if (PROTO::crc16(data, 6) == PROTO::merge8(data[6], data[7])) {
|
||||
# define HANDLE(_handler) { _handler(data + 2); return PROTO::PONG::OK; }
|
||||
switch (data[1]) {
|
||||
case PROTO::CMD::PING: return PROTO::PONG::OK;
|
||||
case PROTO::CMD::SET_OUTPUTS: HANDLE(_cmdSetOutputs);
|
||||
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;
|
||||
}
|
||||
@@ -151,33 +227,33 @@ uint8_t handleCmdBuffer(const uint8_t *buffer) { // 8 bytes
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#ifdef CMD_SPI
|
||||
volatile uint8_t spi_in[8] = {0};
|
||||
volatile uint8_t spi_in_index = 0;
|
||||
static volatile uint8_t _spi_in[8] = {0};
|
||||
static volatile uint8_t _spi_in_index = 0;
|
||||
|
||||
volatile uint8_t spi_out[4] = {0};
|
||||
volatile uint8_t spi_out_index = 0;
|
||||
static volatile uint8_t _spi_out[8] = {0};
|
||||
static volatile uint8_t _spi_out_index = 0;
|
||||
|
||||
bool spiReady() {
|
||||
return (!spi_out[0] && spi_in_index == 8);
|
||||
static bool _spiReady() {
|
||||
return (!_spi_out[0] && _spi_in_index == 8);
|
||||
}
|
||||
|
||||
void spiWrite(const uint8_t *buffer) {
|
||||
spi_out[3] = buffer[3];
|
||||
spi_out[2] = buffer[2];
|
||||
spi_out[1] = buffer[1];
|
||||
spi_out[0] = buffer[0]; // Меджик разрешает начать ответ
|
||||
static void _spiWrite(const uint8_t *data) {
|
||||
// Меджик в нулевом байте разрешает начать ответ
|
||||
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 < 4) {
|
||||
SPDR = spi_out[spi_out_index];
|
||||
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 == 4) {
|
||||
spi_out_index = 0;
|
||||
spi_in_index = 0;
|
||||
spi_out[0] = 0;
|
||||
++_spi_out_index;
|
||||
if (_spi_out_index == 8) {
|
||||
_spi_out_index = 0;
|
||||
_spi_in_index = 0;
|
||||
_spi_out[0] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -185,11 +261,11 @@ ISR(SPI_STC_vect) {
|
||||
if (!receiving && in == PROTO::MAGIC) {
|
||||
receiving = true;
|
||||
}
|
||||
if (receiving && spi_in_index < 8) {
|
||||
spi_in[spi_in_index] = in;
|
||||
++spi_in_index;
|
||||
if (receiving && _spi_in_index < 8) {
|
||||
_spi_in[_spi_in_index] = in;
|
||||
++_spi_in_index;
|
||||
}
|
||||
if (spi_in_index == 8) {
|
||||
if (_spi_in_index == 8) {
|
||||
receiving = false;
|
||||
}
|
||||
SPDR = 0;
|
||||
@@ -199,7 +275,7 @@ ISR(SPI_STC_vect) {
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void sendCmdResponse(uint8_t code) {
|
||||
static void _sendResponse(uint8_t code) {
|
||||
static uint8_t prev_code = PROTO::RESP::NONE;
|
||||
if (code == 0) {
|
||||
code = prev_code; // Repeat the last code
|
||||
@@ -207,51 +283,71 @@ void sendCmdResponse(uint8_t code) {
|
||||
prev_code = code;
|
||||
}
|
||||
|
||||
uint8_t buffer[4];
|
||||
buffer[0] = PROTO::MAGIC;
|
||||
buffer[1] = code;
|
||||
uint16_t crc = protoCrc16(buffer, 2);
|
||||
buffer[2] = (uint8_t)(crc >> 8);
|
||||
buffer[3] = (uint8_t)(crc & 0xFF);
|
||||
uint8_t data[8] = {0};
|
||||
data[0] = PROTO::MAGIC;
|
||||
if (code & PROTO::PONG::OK) {
|
||||
data[1] = PROTO::PONG::OK;
|
||||
# ifdef HID_DYNAMIC
|
||||
if (_reset_required) {
|
||||
data[1] |= PROTO::PONG::RESET_REQUIRED;
|
||||
}
|
||||
data[2] = PROTO::OUTPUTS::DYNAMIC;
|
||||
# endif
|
||||
if (_usb_kbd) {
|
||||
data[1] |= _usb_kbd->getOfflineAs(PROTO::PONG::KEYBOARD_OFFLINE);
|
||||
data[1] |= _usb_kbd->getLedsAs(PROTO::PONG::CAPS, PROTO::PONG::SCROLL, PROTO::PONG::NUM);
|
||||
data[2] |= PROTO::OUTPUTS::KEYBOARD::USB;
|
||||
} else if (_ps2_kbd) {
|
||||
data[1] |= _ps2_kbd->getOfflineAs(PROTO::PONG::KEYBOARD_OFFLINE);
|
||||
data[1] |= _ps2_kbd->getLedsAs(PROTO::PONG::CAPS, PROTO::PONG::SCROLL, PROTO::PONG::NUM);
|
||||
data[2] |= PROTO::OUTPUTS::KEYBOARD::PS2;
|
||||
}
|
||||
if (_usb_mouse_abs) {
|
||||
data[1] |= _usb_mouse_abs->getOfflineAs(PROTO::PONG::MOUSE_OFFLINE);
|
||||
data[2] |= PROTO::OUTPUTS::MOUSE::USB_ABS;
|
||||
} else if (_usb_mouse_rel) {
|
||||
data[1] |= _usb_mouse_rel->getOfflineAs(PROTO::PONG::MOUSE_OFFLINE);
|
||||
data[2] |= PROTO::OUTPUTS::MOUSE::USB_REL;
|
||||
} // TODO: ps2
|
||||
# ifdef HID_WITH_USB
|
||||
data[3] |= PROTO::FEATURES::HAS_USB;
|
||||
# endif
|
||||
# ifdef HID_WITH_PS2
|
||||
data[3] |= PROTO::FEATURES::HAS_PS2;
|
||||
# endif
|
||||
} else {
|
||||
data[1] = code;
|
||||
}
|
||||
PROTO::split16(PROTO::crc16(data, 6), &data[6], &data[7]);
|
||||
|
||||
# ifdef CMD_SERIAL
|
||||
CMD_SERIAL.write(buffer, 4);
|
||||
CMD_SERIAL.write(data, 8);
|
||||
# elif defined(CMD_SPI)
|
||||
spiWrite(buffer);
|
||||
_spiWrite(data);
|
||||
# endif
|
||||
}
|
||||
|
||||
void setup() {
|
||||
hid_kbd.begin();
|
||||
# ifdef HID_USB_MOUSE
|
||||
hid_mouse.begin();
|
||||
# endif
|
||||
int main() {
|
||||
init(); // Embedded
|
||||
initVariant(); // Arduino
|
||||
_initOutputs();
|
||||
|
||||
# ifdef CMD_SERIAL
|
||||
CMD_SERIAL.begin(CMD_SERIAL_SPEED);
|
||||
# elif defined(CMD_SPI)
|
||||
pinMode(MISO, OUTPUT);
|
||||
SPCR = (1 << SPE) | (1 << SPIE); // Slave, SPI En, IRQ En
|
||||
# endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
# ifdef CMD_SERIAL
|
||||
unsigned long last = micros();
|
||||
uint8_t buffer[8];
|
||||
uint8_t index = 0;
|
||||
# endif
|
||||
|
||||
while (true) {
|
||||
# ifdef HID_PS2_KBD
|
||||
hid_kbd.periodic();
|
||||
# ifdef HID_WITH_PS2
|
||||
if (_ps2_kbd) {
|
||||
_ps2_kbd->periodic();
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef CMD_SERIAL
|
||||
if (CMD_SERIAL.available() > 0) {
|
||||
buffer[index] = (uint8_t)CMD_SERIAL.read();
|
||||
if (index == 7) {
|
||||
sendCmdResponse(handleCmdBuffer(buffer));
|
||||
_sendResponse(_handleRequest(buffer));
|
||||
index = 0;
|
||||
} else {
|
||||
last = micros();
|
||||
@@ -263,14 +359,27 @@ void loop() {
|
||||
(now >= last && now - last > CMD_SERIAL_TIMEOUT)
|
||||
|| (now < last && ((unsigned long)-1) - last + now > CMD_SERIAL_TIMEOUT)
|
||||
) {
|
||||
sendCmdResponse(PROTO::RESP::TIMEOUT_ERROR);
|
||||
_sendResponse(PROTO::RESP::TIMEOUT_ERROR);
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
# elif defined(CMD_SPI)
|
||||
if (spiReady()) {
|
||||
sendCmdResponse(handleCmdBuffer(spi_in));
|
||||
}
|
||||
|
||||
# elif defined(CMD_SPI)
|
||||
pinMode(MISO, OUTPUT);
|
||||
SPCR = (1 << SPE) | (1 << SPIE); // Slave, SPI En, IRQ En
|
||||
|
||||
while (true) {
|
||||
# ifdef HID_WITH_PS2
|
||||
if (_ps2_kbd) {
|
||||
_ps2_kbd->periodic();
|
||||
}
|
||||
# endif
|
||||
if (_spiReady()) {
|
||||
_sendResponse(_handleRequest((const uint8_t *)_spi_in));
|
||||
}
|
||||
}
|
||||
|
||||
# endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user