mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
rp2040 hid
This commit is contained in:
parent
1a8f98a64f
commit
c96057772c
@ -8,8 +8,14 @@
|
||||
/testenv/.tox/
|
||||
/testenv/.mypy_cache/
|
||||
/testenv/.ssl/
|
||||
/hid/.pio/
|
||||
/hid/.platformio/
|
||||
/hid/arduino/.pio/
|
||||
/hid/arduino/.platformio/
|
||||
/hid/pico/.pico-sdk.tmp/
|
||||
/hid/pico/.pico-sdk/
|
||||
/hid/pico/.tinyusb.tmp/
|
||||
/hid/pico/.tinyusb/
|
||||
/hid/pico/.build/
|
||||
/hid/pico/*.uf2
|
||||
/.git/
|
||||
/v*.tar.gz
|
||||
/*.pkg.tar.xz
|
||||
|
||||
3
Makefile
3
Makefile
@ -213,6 +213,7 @@ keymap: testenv
|
||||
&& ./genmap.py keymap.csv kvmd/keyboard/mappings.py.mako kvmd/keyboard/mappings.py \
|
||||
&& ./genmap.py keymap.csv hid/arduino/lib/drivers/usb-keymap.h.mako hid/arduino/lib/drivers/usb-keymap.h \
|
||||
&& ./genmap.py keymap.csv hid/arduino/lib/drivers-avr/ps2/keymap.h.mako hid/arduino/lib/drivers-avr/ps2/keymap.h \
|
||||
&& ./genmap.py keymap.csv hid/pico/src/ph_usb_keymap.h.mako hid/pico/src/ph_usb_keymap.h \
|
||||
"
|
||||
|
||||
|
||||
@ -251,10 +252,12 @@ clean:
|
||||
rm -rf testenv/run/*.{pid,sock} build site dist pkg src v*.tar.gz *.pkg.tar.{xz,zst} *.egg-info kvmd-*.tar.gz
|
||||
find kvmd testenv/tests -name __pycache__ | xargs rm -rf
|
||||
make -C hid/arduino clean
|
||||
make -C hid/pico clean
|
||||
|
||||
|
||||
clean-all: testenv clean
|
||||
make -C hid/arduino clean-all
|
||||
make -C hid/pico clean-all
|
||||
- $(DOCKER) run --rm \
|
||||
--volume `pwd`:/src \
|
||||
-it $(TESTENV_IMAGE) bash -c "cd src && rm -rf testenv/{.ssl,.tox,.mypy_cache,.coverage}"
|
||||
|
||||
6
hid/pico/.gitignore
vendored
Normal file
6
hid/pico/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/.pico-sdk.tmp/
|
||||
/.pico-sdk/
|
||||
/.tinyusb.tmp/
|
||||
/.tinyusb/
|
||||
/.build/
|
||||
/*.uf2
|
||||
21
hid/pico/CMakeLists.txt
Normal file
21
hid/pico/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
set(PICO_SDK_PATH ${CMAKE_CURRENT_LIST_DIR}/.pico-sdk)
|
||||
set(PICO_TINYUSB_PATH ${CMAKE_CURRENT_LIST_DIR}/.tinyusb)
|
||||
|
||||
# For TinyUSB
|
||||
set(FAMILY rp2040)
|
||||
|
||||
# Include pico_sdk_import.cmake from pico-sdk (instead of copying)
|
||||
include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)
|
||||
|
||||
# Generic setup
|
||||
set(PROJECT hid)
|
||||
project(${PROJECT})
|
||||
|
||||
# Initialize Pico-SDK
|
||||
pico_sdk_init()
|
||||
|
||||
# Set the path to the source code to build
|
||||
set(SRC_TO_BUILD_PATH ${CMAKE_CURRENT_LIST_DIR}/src)
|
||||
add_subdirectory(${SRC_TO_BUILD_PATH})
|
||||
36
hid/pico/Makefile
Normal file
36
hid/pico/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
all: .pico-sdk .tinyusb
|
||||
rm -f hid.uf2
|
||||
cmake -B .build
|
||||
cmake --build .build --config Release -- -j
|
||||
ln .build/src/hid.uf2 .
|
||||
|
||||
|
||||
upload: install
|
||||
install: all
|
||||
sudo mount /dev/sda1 /mnt
|
||||
sudo cp hid.uf2 /mnt
|
||||
sudo umount /mnt
|
||||
|
||||
|
||||
clean:
|
||||
rm -rf .build hid.uf2
|
||||
clean-all: clean
|
||||
rm -rf .pico-sdk.tmp .pico-sdk .tinyusb.tmp .tinyusb
|
||||
|
||||
|
||||
.pico-sdk:
|
||||
rm -rf .pico-sdk.tmp
|
||||
git clone https://github.com/raspberrypi/pico-sdk .pico-sdk.tmp
|
||||
cd .pico-sdk.tmp \
|
||||
&& git checkout 62201a83e2693ea165fdc7669b4ab2f3b4f43c36 \
|
||||
&& git submodule update --init
|
||||
mv .pico-sdk.tmp .pico-sdk
|
||||
|
||||
|
||||
.tinyusb:
|
||||
rm -rf .tinyusb.tmp
|
||||
git clone https://github.com/hathach/tinyusb .tinyusb.tmp
|
||||
cd .tinyusb.tmp \
|
||||
&& git checkout c998e9c60bc76894006c3bd049d661124a9bfbfd \
|
||||
&& git submodule update --init
|
||||
mv .tinyusb.tmp .tinyusb
|
||||
25
hid/pico/src/CMakeLists.txt
Normal file
25
hid/pico/src/CMakeLists.txt
Normal file
@ -0,0 +1,25 @@
|
||||
set(target_name hid)
|
||||
add_executable(${target_name})
|
||||
|
||||
target_sources(${target_name} PRIVATE
|
||||
main.c
|
||||
ph_outputs.c
|
||||
ph_usb.c
|
||||
ph_usb_kbd.c
|
||||
ph_usb_mouse.c
|
||||
ph_cmds.c
|
||||
ph_spi.c
|
||||
ph_debug.c
|
||||
)
|
||||
target_link_options(${target_name} PRIVATE -Xlinker --print-memory-usage)
|
||||
target_compile_options(${target_name} PRIVATE -Wall -Wextra)
|
||||
target_include_directories(${target_name} PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
target_link_libraries(${target_name} PRIVATE
|
||||
pico_stdlib
|
||||
pico_unique_id
|
||||
hardware_spi
|
||||
hardware_watchdog
|
||||
tinyusb_device
|
||||
)
|
||||
pico_add_extra_outputs(${target_name})
|
||||
122
hid/pico/src/main.c
Normal file
122
hid/pico/src/main.c
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 "pico/stdlib.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/watchdog.h"
|
||||
|
||||
#include "ph_types.h"
|
||||
#include "ph_tools.h"
|
||||
#include "ph_outputs.h"
|
||||
#include "ph_usb.h"
|
||||
#include "ph_spi.h"
|
||||
#include "ph_proto.h"
|
||||
#include "ph_cmds.h"
|
||||
#include "ph_debug.h"
|
||||
|
||||
|
||||
static bool _reset_required = false;
|
||||
|
||||
|
||||
static u8 _handle_request(const u8 *data) { // 8 bytes
|
||||
// FIXME: See kvmd/kvmd#80
|
||||
// Should input buffer be cleared in this case?
|
||||
if (data[0] == PH_PROTO_MAGIC && ph_crc16(data, 6) == ph_merge8_u16(data[6], data[7])) {
|
||||
# define HANDLE(x_handler, x_reset) { \
|
||||
x_handler(data + 2); \
|
||||
if (x_reset) { _reset_required = true; } \
|
||||
return PH_PROTO_PONG_OK; \
|
||||
}
|
||||
switch (data[1]) {
|
||||
case PH_PROTO_CMD_PING: return PH_PROTO_PONG_OK;
|
||||
case PH_PROTO_CMD_SET_KBD: HANDLE(ph_cmd_set_kbd, true);
|
||||
case PH_PROTO_CMD_SET_MOUSE: HANDLE(ph_cmd_set_mouse, true);
|
||||
case PH_PROTO_CMD_SET_CONNECTED: return PH_PROTO_PONG_OK; // Arduino AUM
|
||||
case PH_PROTO_CMD_CLEAR_HID: HANDLE(ph_cmd_send_clear, false);
|
||||
case PH_PROTO_CMD_KBD_KEY: HANDLE(ph_cmd_kbd_send_key, false);
|
||||
case PH_PROTO_CMD_MOUSE_BUTTON: HANDLE(ph_cmd_mouse_send_button, false);
|
||||
case PH_PROTO_CMD_MOUSE_ABS: HANDLE(ph_cmd_mouse_send_abs, false);
|
||||
case PH_PROTO_CMD_MOUSE_REL: HANDLE(ph_cmd_mouse_send_rel, false);
|
||||
case PH_PROTO_CMD_MOUSE_WHEEL: HANDLE(ph_cmd_mouse_send_wheel, false);
|
||||
case PH_PROTO_CMD_REPEAT: return 0;
|
||||
}
|
||||
# undef HANDLE
|
||||
return PH_PROTO_RESP_INVALID_ERROR;
|
||||
}
|
||||
return PH_PROTO_RESP_CRC_ERROR;
|
||||
}
|
||||
|
||||
static void _send_response(u8 code) {
|
||||
static u8 prev_code = PH_PROTO_RESP_NONE;
|
||||
if (code == 0) {
|
||||
code = prev_code; // Repeat the last code
|
||||
} else {
|
||||
prev_code = code;
|
||||
}
|
||||
|
||||
u8 resp[8] = {0};
|
||||
resp[0] = PH_PROTO_MAGIC_RESP;
|
||||
|
||||
if (code & PH_PROTO_PONG_OK) {
|
||||
resp[1] = PH_PROTO_PONG_OK;
|
||||
if (_reset_required) {
|
||||
resp[1] |= PH_PROTO_PONG_RESET_REQUIRED;
|
||||
}
|
||||
resp[2] = PH_PROTO_OUT1_DYNAMIC;
|
||||
|
||||
resp[1] |= ph_cmd_get_offlines();
|
||||
resp[1] |= ph_cmd_kbd_get_leds();
|
||||
resp[2] |= ph_g_outputs_active;
|
||||
resp[3] |= ph_g_outputs_avail;
|
||||
} else {
|
||||
resp[1] = code;
|
||||
}
|
||||
|
||||
ph_split16(ph_crc16(resp, 6), &resp[6], &resp[7]);
|
||||
|
||||
ph_spi_write(resp);
|
||||
|
||||
if (_reset_required) {
|
||||
watchdog_reboot(0, 0, 100); // Даем немного времени чтобы отправить ответ, а потом ребутимся
|
||||
}
|
||||
}
|
||||
|
||||
static void _spi_data_handler(const u8 *data) {
|
||||
_send_response(_handle_request(data));
|
||||
}
|
||||
|
||||
|
||||
int main(void) {
|
||||
ph_debug_init(false); // No UART
|
||||
ph_outputs_init();
|
||||
ph_usb_init();
|
||||
ph_spi_init(_spi_data_handler);
|
||||
|
||||
while (true) {
|
||||
ph_usb_task();
|
||||
if (!_reset_required) {
|
||||
ph_spi_task();
|
||||
ph_debug_act_pulse(50);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
105
hid/pico/src/ph_cmds.c
Normal file
105
hid/pico/src/ph_cmds.c
Normal file
@ -0,0 +1,105 @@
|
||||
/* ========================================================================= #
|
||||
# #
|
||||
# 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 "tusb.h"
|
||||
|
||||
#include "ph_types.h"
|
||||
#include "ph_tools.h"
|
||||
#include "ph_proto.h"
|
||||
#include "ph_outputs.h"
|
||||
#include "ph_usb.h"
|
||||
#include "ph_usb_keymap.h"
|
||||
|
||||
|
||||
u8 ph_cmd_kbd_get_leds(void) {
|
||||
u8 retval = 0;
|
||||
if (PH_O_IS_KBD_USB) {
|
||||
# define GET(x_mod) ((ph_g_usb_kbd_leds & KEYBOARD_LED_##x_mod##LOCK) ? PH_PROTO_PONG_##x_mod : 0)
|
||||
retval = GET(CAPS) | GET(SCROLL) | GET(NUM);
|
||||
# undef GET
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
u8 ph_cmd_get_offlines(void) {
|
||||
u8 retval = 0;
|
||||
if (PH_O_IS_KBD_USB) {
|
||||
if (!ph_g_usb_kbd_online) {
|
||||
retval |= PH_PROTO_PONG_KBD_OFFLINE;
|
||||
}
|
||||
}
|
||||
if (PH_O_IS_MOUSE_USB) {
|
||||
if (!ph_g_usb_mouse_online) {
|
||||
retval |= PH_PROTO_PONG_MOUSE_OFFLINE;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ph_cmd_set_kbd(const u8 *args) { // 1 byte
|
||||
ph_outputs_write(PH_PROTO_OUT1_KBD_MASK, args[0], false);
|
||||
}
|
||||
|
||||
void ph_cmd_set_mouse(const u8 *args) { // 1 byte
|
||||
ph_outputs_write(PH_PROTO_OUT1_MOUSE_MASK, args[0], false);
|
||||
}
|
||||
|
||||
void ph_cmd_send_clear(const u8 *args) { // 0 bytes
|
||||
(void)args;
|
||||
ph_usb_send_clear();
|
||||
}
|
||||
|
||||
void ph_cmd_kbd_send_key(const u8 *args) { // 2 bytes
|
||||
const u8 key = ph_usb_keymap(args[0]);
|
||||
if (key > 0) {
|
||||
ph_usb_kbd_send_key(key, args[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void ph_cmd_mouse_send_button(const u8 *args) { // 2 bytes
|
||||
# define HANDLE(x_byte_n, x_button) { \
|
||||
if (args[x_byte_n] & PH_PROTO_CMD_MOUSE_##x_button##_SELECT) { \
|
||||
const bool m_state = !!(args[x_byte_n] & PH_PROTO_CMD_MOUSE_##x_button##_STATE); \
|
||||
ph_usb_mouse_send_button(MOUSE_BUTTON_##x_button, m_state); \
|
||||
} \
|
||||
}
|
||||
HANDLE(0, LEFT);
|
||||
HANDLE(0, RIGHT);
|
||||
HANDLE(0, MIDDLE);
|
||||
HANDLE(1, BACKWARD);
|
||||
HANDLE(1, FORWARD);
|
||||
# undef HANDLE
|
||||
}
|
||||
|
||||
void ph_cmd_mouse_send_abs(const u8 *args) { // 4 bytes
|
||||
ph_usb_mouse_send_abs(
|
||||
ph_merge8_s16(args[0], args[1]),
|
||||
ph_merge8_s16(args[2], args[3]));
|
||||
}
|
||||
|
||||
void ph_cmd_mouse_send_rel(const u8 *args) { // 2 bytes
|
||||
ph_usb_mouse_send_rel(args[0], args[1]);
|
||||
}
|
||||
|
||||
void ph_cmd_mouse_send_wheel(const u8 *args) { // 2 bytes
|
||||
ph_usb_mouse_send_wheel(args[0], args[1]);
|
||||
}
|
||||
37
hid/pico/src/ph_cmds.h
Normal file
37
hid/pico/src/ph_cmds.h
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/>. #
|
||||
# #
|
||||
# ========================================================================= */
|
||||
|
||||
|
||||
#include "ph_types.h"
|
||||
|
||||
|
||||
u8 ph_cmd_kbd_get_leds(void);
|
||||
u8 ph_cmd_get_offlines(void);
|
||||
|
||||
void ph_cmd_set_kbd(const u8 *args);
|
||||
void ph_cmd_set_mouse(const u8 *args);
|
||||
|
||||
void ph_cmd_send_clear(const u8 *args);
|
||||
void ph_cmd_kbd_send_key(const u8 *args);
|
||||
void ph_cmd_mouse_send_button(const u8 *args);
|
||||
void ph_cmd_mouse_send_abs(const u8 *args);
|
||||
void ph_cmd_mouse_send_rel(const u8 *args);
|
||||
void ph_cmd_mouse_send_wheel(const u8 *args);
|
||||
53
hid/pico/src/ph_debug.c
Normal file
53
hid/pico/src/ph_debug.c
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/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
#include "ph_types.h"
|
||||
|
||||
|
||||
#define _UART uart0
|
||||
#define _SPEED 3000000
|
||||
#define _RX_PIN -1 // 1 - No stdin
|
||||
#define _TX_PIN 0
|
||||
#define _ACT_PIN 25
|
||||
|
||||
|
||||
void ph_debug_init(bool enable_uart) {
|
||||
if (enable_uart) {
|
||||
stdio_uart_init_full(_UART, _SPEED, _TX_PIN, _RX_PIN);
|
||||
}
|
||||
gpio_init(_ACT_PIN);
|
||||
gpio_set_dir(_ACT_PIN, GPIO_OUT);
|
||||
}
|
||||
|
||||
void ph_debug_act_pulse(u64 delay_ms) {
|
||||
static bool flag = false;
|
||||
static u64 next_ts = 0;
|
||||
const u64 now_ts = time_us_64();
|
||||
if (now_ts >= next_ts) {
|
||||
gpio_put(_ACT_PIN, flag);
|
||||
flag = !flag;
|
||||
next_ts = now_ts + (delay_ms * 1000);
|
||||
}
|
||||
}
|
||||
27
hid/pico/src/ph_debug.h
Normal file
27
hid/pico/src/ph_debug.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# 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 "ph_types.h"
|
||||
|
||||
|
||||
void ph_debug_init(bool enable_uart);
|
||||
void ph_debug_act_pulse(u64 delay_ms);
|
||||
137
hid/pico/src/ph_outputs.c
Normal file
137
hid/pico/src/ph_outputs.c
Normal file
@ -0,0 +1,137 @@
|
||||
/* ========================================================================= #
|
||||
# #
|
||||
# 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 "ph_outputs.h"
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/structs/watchdog.h"
|
||||
|
||||
#include "ph_types.h"
|
||||
#include "ph_tools.h"
|
||||
#include "ph_proto.h"
|
||||
|
||||
|
||||
#define _PS2_ENABLED_PIN 2
|
||||
#define _PS2_SET_KBD_PIN 3
|
||||
#define _PS2_SET_MOUSE_PIN 4
|
||||
|
||||
#define _USB_DISABLED_PIN 6
|
||||
#define _USB_ENABLE_W98_PIN 7
|
||||
#define _USB_SET_MOUSE_REL_PIN 8
|
||||
#define _USB_SET_MOUSE_W98_PIN 9
|
||||
|
||||
|
||||
u8 ph_g_outputs_active = 0;
|
||||
u8 ph_g_outputs_avail = 0;
|
||||
|
||||
|
||||
static int _read_outputs(void);
|
||||
|
||||
|
||||
void ph_outputs_init(void) {
|
||||
# define INIT_SWITCH(x_pin) { gpio_init(x_pin); gpio_set_dir(x_pin, GPIO_IN); gpio_pull_down(x_pin); }
|
||||
INIT_SWITCH(_PS2_ENABLED_PIN);
|
||||
INIT_SWITCH(_PS2_SET_KBD_PIN);
|
||||
INIT_SWITCH(_PS2_SET_MOUSE_PIN);
|
||||
|
||||
INIT_SWITCH(_USB_DISABLED_PIN);
|
||||
INIT_SWITCH(_USB_ENABLE_W98_PIN);
|
||||
INIT_SWITCH(_USB_SET_MOUSE_REL_PIN);
|
||||
INIT_SWITCH(_USB_SET_MOUSE_W98_PIN);
|
||||
# undef INIT_SWITCH
|
||||
|
||||
const bool o_ps2_enabled = gpio_get(_PS2_ENABLED_PIN);
|
||||
const bool o_ps2_kbd = gpio_get(_PS2_SET_KBD_PIN);
|
||||
const bool o_ps2_mouse = gpio_get(_PS2_SET_MOUSE_PIN);
|
||||
|
||||
const bool o_usb_disabled = gpio_get(_USB_DISABLED_PIN);
|
||||
const bool o_usb_enabled_w98 = gpio_get(_USB_ENABLE_W98_PIN);
|
||||
const bool o_usb_mouse_rel = gpio_get(_USB_SET_MOUSE_REL_PIN);
|
||||
const bool o_usb_mouse_w98 = gpio_get(_USB_SET_MOUSE_W98_PIN);
|
||||
|
||||
int outputs = _read_outputs();
|
||||
if (outputs < 0) {
|
||||
outputs = 0;
|
||||
|
||||
if (o_ps2_enabled && o_ps2_kbd) {
|
||||
outputs |= PH_PROTO_OUT1_KBD_PS2;
|
||||
} else if (!o_usb_disabled) {
|
||||
outputs |= PH_PROTO_OUT1_KBD_USB;
|
||||
}
|
||||
|
||||
if (o_ps2_enabled && o_ps2_mouse) {
|
||||
outputs |= PH_PROTO_OUT1_MOUSE_PS2;
|
||||
} else if (!o_usb_disabled) {
|
||||
if (o_usb_enabled_w98 && o_usb_mouse_w98) {
|
||||
outputs |= PH_PROTO_OUT1_MOUSE_USB_W98;
|
||||
} else if (o_usb_mouse_rel) {
|
||||
outputs |= PH_PROTO_OUT1_MOUSE_USB_REL;
|
||||
} else {
|
||||
outputs |= PH_PROTO_OUT1_MOUSE_USB_ABS;
|
||||
}
|
||||
}
|
||||
|
||||
ph_outputs_write(0xFF, outputs, true);
|
||||
}
|
||||
|
||||
if (!o_usb_disabled) {
|
||||
ph_g_outputs_avail |= PH_PROTO_OUT2_HAS_USB;
|
||||
if (o_usb_enabled_w98) {
|
||||
ph_g_outputs_avail |= PH_PROTO_OUT2_HAS_USB_W98;
|
||||
}
|
||||
}
|
||||
if (o_ps2_enabled) {
|
||||
ph_g_outputs_avail |= PH_PROTO_OUT2_HAS_PS2;
|
||||
}
|
||||
|
||||
ph_g_outputs_active = outputs & 0xFF;
|
||||
}
|
||||
|
||||
void ph_outputs_write(u8 mask, u8 outputs, bool force) {
|
||||
int old = 0;
|
||||
if (!force) {
|
||||
old = _read_outputs();
|
||||
if (old < 0) {
|
||||
old = 0;
|
||||
}
|
||||
}
|
||||
u8 data[4] = {0};
|
||||
data[0] = PH_PROTO_MAGIC;
|
||||
data[1] = (old & ~mask) | outputs;
|
||||
ph_split16(ph_crc16(data, 2), &data[2], &data[3]);
|
||||
const u32 s0 = ((u32)data[0] << 24) | ((u32)data[1] << 16) | ((u32)data[2] << 8) | (u32)data[3];
|
||||
watchdog_hw->scratch[0] = s0;
|
||||
}
|
||||
|
||||
static int _read_outputs(void) {
|
||||
const u32 s0 = watchdog_hw->scratch[0];
|
||||
const u8 data[4] = {
|
||||
(s0 >> 24) & 0xFF,
|
||||
(s0 >> 16) & 0xFF,
|
||||
(s0 >> 8) & 0xFF,
|
||||
s0 & 0xFF,
|
||||
};
|
||||
if (data[0] != PH_PROTO_MAGIC || ph_crc16(data, 2) != ph_merge8_u16(data[2], data[3])) {
|
||||
return -1;
|
||||
}
|
||||
return data[1];
|
||||
}
|
||||
42
hid/pico/src/ph_outputs.h
Normal file
42
hid/pico/src/ph_outputs.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* ========================================================================= #
|
||||
# #
|
||||
# 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 "ph_types.h"
|
||||
#include "ph_proto.h"
|
||||
|
||||
|
||||
#define PH_O_KBD(x_id) ((ph_g_outputs_active & PH_PROTO_OUT1_KBD_MASK) == PH_PROTO_OUT1_KBD_##x_id)
|
||||
#define PH_O_MOUSE(x_id) ((ph_g_outputs_active & PH_PROTO_OUT1_MOUSE_MASK) == PH_PROTO_OUT1_MOUSE_##x_id)
|
||||
#define PH_O_IS_KBD_USB PH_O_KBD(USB)
|
||||
#define PH_O_IS_MOUSE_USB (PH_O_MOUSE(USB_ABS) || PH_O_MOUSE(USB_REL) || PH_O_MOUSE(USB_W98))
|
||||
#define PH_O_IS_MOUSE_USB_ABS (PH_O_MOUSE(USB_ABS) || PH_O_MOUSE(USB_W98))
|
||||
#define PH_O_IS_MOUSE_USB_REL PH_O_MOUSE(USB_REL)
|
||||
|
||||
|
||||
extern u8 ph_g_outputs_active;
|
||||
extern u8 ph_g_outputs_avail;
|
||||
|
||||
|
||||
void ph_outputs_init(void);
|
||||
void ph_outputs_write(u8 mask, u8 outputs, bool force);
|
||||
92
hid/pico/src/ph_proto.h
Normal file
92
hid/pico/src/ph_proto.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 "ph_types.h"
|
||||
|
||||
|
||||
#define PH_PROTO_MAGIC ((u8)0x33)
|
||||
#define PH_PROTO_MAGIC_RESP ((u8)0x34)
|
||||
|
||||
//#define PH_PROTO_RESP_OK ((u8)0x20) // Legacy
|
||||
#define PH_PROTO_RESP_NONE ((u8)0x24)
|
||||
#define PH_PROTO_RESP_CRC_ERROR ((u8)0x40)
|
||||
#define PH_PROTO_RESP_INVALID_ERROR ((u8)0x45)
|
||||
#define PH_PROTO_RESP_TIMEOUT_ERROR ((u8)0x48)
|
||||
|
||||
// Complex response flags
|
||||
#define PH_PROTO_PONG_OK ((u8)0b10000000)
|
||||
#define PH_PROTO_PONG_CAPS ((u8)0b00000001)
|
||||
#define PH_PROTO_PONG_SCROLL ((u8)0b00000010)
|
||||
#define PH_PROTO_PONG_NUM ((u8)0b00000100)
|
||||
#define PH_PROTO_PONG_KBD_OFFLINE ((u8)0b00001000)
|
||||
#define PH_PROTO_PONG_MOUSE_OFFLINE ((u8)0b00010000)
|
||||
#define PH_PROTO_PONG_RESET_REQUIRED ((u8)0b01000000)
|
||||
|
||||
// Complex request/response flags
|
||||
#define PH_PROTO_OUT1_DYNAMIC ((u8)0b10000000)
|
||||
#define PH_PROTO_OUT1_KBD_MASK ((u8)0b00000111)
|
||||
#define PH_PROTO_OUT1_KBD_USB ((u8)0b00000001)
|
||||
#define PH_PROTO_OUT1_KBD_PS2 ((u8)0b00000011)
|
||||
// +
|
||||
#define PH_PROTO_OUT1_MOUSE_MASK ((u8)0b00111000)
|
||||
#define PH_PROTO_OUT1_MOUSE_USB_ABS ((u8)0b00001000)
|
||||
#define PH_PROTO_OUT1_MOUSE_USB_REL ((u8)0b00010000)
|
||||
#define PH_PROTO_OUT1_MOUSE_PS2 ((u8)0b00011000)
|
||||
#define PH_PROTO_OUT1_MOUSE_USB_W98 ((u8)0b00100000)
|
||||
|
||||
// Complex response
|
||||
#define PH_PROTO_OUT2_CONNECTABLE ((u8)0b10000000)
|
||||
#define PH_PROTO_OUT2_CONNECTED ((u8)0b01000000)
|
||||
#define PH_PROTO_OUT2_HAS_USB ((u8)0b00000001)
|
||||
#define PH_PROTO_OUT2_HAS_PS2 ((u8)0b00000010)
|
||||
#define PH_PROTO_OUT2_HAS_USB_W98 ((u8)0b00000100)
|
||||
|
||||
#define PH_PROTO_CMD_PING ((u8)0x01)
|
||||
#define PH_PROTO_CMD_REPEAT ((u8)0x02)
|
||||
#define PH_PROTO_CMD_SET_KBD ((u8)0x03)
|
||||
#define PH_PROTO_CMD_SET_MOUSE ((u8)0x04)
|
||||
#define PH_PROTO_CMD_SET_CONNECTED ((u8)0x05)
|
||||
#define PH_PROTO_CMD_CLEAR_HID ((u8)0x10)
|
||||
// +
|
||||
#define PH_PROTO_CMD_KBD_KEY ((u8)0x11)
|
||||
// +
|
||||
#define PH_PROTO_CMD_MOUSE_ABS ((u8)0x12)
|
||||
#define PH_PROTO_CMD_MOUSE_BUTTON ((u8)0x13)
|
||||
#define PH_PROTO_CMD_MOUSE_WHEEL ((u8)0x14)
|
||||
#define PH_PROTO_CMD_MOUSE_REL ((u8)0x15)
|
||||
// +
|
||||
#define PH_PROTO_CMD_MOUSE_LEFT_SELECT ((u8)0b10000000)
|
||||
#define PH_PROTO_CMD_MOUSE_LEFT_STATE ((u8)0b00001000)
|
||||
// +
|
||||
#define PH_PROTO_CMD_MOUSE_RIGHT_SELECT ((u8)0b01000000)
|
||||
#define PH_PROTO_CMD_MOUSE_RIGHT_STATE ((u8)0b00000100)
|
||||
// +
|
||||
#define PH_PROTO_CMD_MOUSE_MIDDLE_SELECT ((u8)0b00100000)
|
||||
#define PH_PROTO_CMD_MOUSE_MIDDLE_STATE ((u8)0b00000010)
|
||||
// +
|
||||
#define PH_PROTO_CMD_MOUSE_BACKWARD_SELECT ((u8)0b10000000) // Previous/Up
|
||||
#define PH_PROTO_CMD_MOUSE_BACKWARD_STATE ((u8)0b00001000) // Previous/Up
|
||||
// +
|
||||
#define PH_PROTO_CMD_MOUSE_FORWARD_SELECT ((u8)0b01000000) // Next/Down
|
||||
#define PH_PROTO_CMD_MOUSE_FORWARD_STATE ((u8)0b00000100) // Next/Down
|
||||
120
hid/pico/src/ph_spi.c
Normal file
120
hid/pico/src/ph_spi.c
Normal file
@ -0,0 +1,120 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# 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 "ph_spi.h"
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/spi.h"
|
||||
#include "hardware/regs/spi.h"
|
||||
|
||||
#include "ph_types.h"
|
||||
|
||||
|
||||
#define _BUS spi0
|
||||
#define _IRQ SPI0_IRQ
|
||||
#define _FREQ (2 * 1000 * 1000)
|
||||
#define _CS_PIN 21
|
||||
#define _RX_PIN 20
|
||||
#define _TX_PIN 19
|
||||
#define _CLK_PIN 18
|
||||
|
||||
|
||||
static volatile u8 _in_buf[8] = {0};
|
||||
static volatile u8 _in_index = 0;
|
||||
|
||||
static volatile u8 _out_buf[8] = {0};
|
||||
static volatile u8 _out_index = 0;
|
||||
|
||||
static void (*_data_cb)(const u8 *) = NULL;
|
||||
|
||||
|
||||
static void _xfer_isr(void);
|
||||
|
||||
|
||||
void ph_spi_init(void (*data_cb)(const u8 *)) {
|
||||
_data_cb = data_cb;
|
||||
|
||||
spi_init(_BUS, _FREQ);
|
||||
spi_set_slave(_BUS, true);
|
||||
spi_set_format(_BUS, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
|
||||
|
||||
gpio_set_function(_CS_PIN, GPIO_FUNC_SPI);
|
||||
gpio_set_function(_RX_PIN, GPIO_FUNC_SPI);
|
||||
gpio_set_function(_TX_PIN, GPIO_FUNC_SPI);
|
||||
gpio_set_function(_CLK_PIN, GPIO_FUNC_SPI);
|
||||
|
||||
// https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2040/hardware_regs/include/hardware/regs/spi.h
|
||||
irq_set_exclusive_handler(_IRQ, _xfer_isr);
|
||||
spi_get_hw(_BUS)->imsc = SPI_SSPIMSC_RXIM_BITS | SPI_SSPIMSC_TXIM_BITS;
|
||||
irq_set_enabled(_IRQ, true);
|
||||
}
|
||||
|
||||
void ph_spi_task(void) {
|
||||
if (!_out_buf[0] && _in_index == 8) {
|
||||
_data_cb((const u8 *)_in_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void ph_spi_write(const u8 *data) {
|
||||
// Меджик в нулевом байте разрешает начать ответ
|
||||
for (s8 i = 7; i >= 0; --i) {
|
||||
_out_buf[i] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
void __isr __not_in_flash_func(_xfer_isr)(void) {
|
||||
# define SR (spi_get_hw(_BUS)->sr)
|
||||
# define DR (spi_get_hw(_BUS)->dr)
|
||||
|
||||
while (SR & SPI_SSPSR_TNF_BITS) {
|
||||
if (_out_buf[0] && _out_index < 8) {
|
||||
DR = (u32)_out_buf[_out_index];
|
||||
++_out_index;
|
||||
if (_out_index == 8) {
|
||||
_out_index = 0;
|
||||
_in_index = 0;
|
||||
_out_buf[0] = 0;
|
||||
}
|
||||
} else {
|
||||
DR = (u32)0;
|
||||
}
|
||||
}
|
||||
|
||||
while (SR & SPI_SSPSR_RNE_BITS) {
|
||||
static bool receiving = false;
|
||||
const u8 in = DR;
|
||||
if (!receiving && in != 0) {
|
||||
receiving = true;
|
||||
}
|
||||
if (receiving && _in_index < 8) {
|
||||
_in_buf[_in_index] = in;
|
||||
++_in_index;
|
||||
}
|
||||
if (_in_index == 8) {
|
||||
receiving = false;
|
||||
}
|
||||
}
|
||||
|
||||
# undef DR
|
||||
# undef SR
|
||||
}
|
||||
30
hid/pico/src/ph_spi.h
Normal file
30
hid/pico/src/ph_spi.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# 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 "ph_types.h"
|
||||
|
||||
|
||||
void ph_spi_init(void (*data_cb)(const u8 *));
|
||||
void ph_spi_task(void);
|
||||
void ph_spi_write(const u8 *data);
|
||||
57
hid/pico/src/ph_tools.h
Normal file
57
hid/pico/src/ph_tools.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# 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 "ph_types.h"
|
||||
|
||||
|
||||
inline u16 ph_crc16(const u8 *buf, uz len) {
|
||||
const u16 polinom = 0xA001;
|
||||
u16 crc = 0xFFFF;
|
||||
|
||||
for (uz byte_count = 0; byte_count < len; ++byte_count) {
|
||||
crc = crc ^ buf[byte_count];
|
||||
for (uz 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 s16 ph_merge8_s16(u8 a, u8 b) {
|
||||
return (((int)a << 8) | (int)b);
|
||||
}
|
||||
|
||||
inline u16 ph_merge8_u16(u8 a, u8 b) {
|
||||
return (((u16)a << 8) | (u16)b);
|
||||
}
|
||||
|
||||
inline void ph_split16(u16 from, u8 *to_a, u8 *to_b) {
|
||||
*to_a = (u8)(from >> 8);
|
||||
*to_b = (u8)(from & 0xFF);
|
||||
}
|
||||
38
hid/pico/src/ph_types.h
Normal file
38
hid/pico/src/ph_types.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* ========================================================================= #
|
||||
# #
|
||||
# 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 <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
|
||||
typedef size_t uz;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
394
hid/pico/src/ph_usb.c
Normal file
394
hid/pico/src/ph_usb.c
Normal file
@ -0,0 +1,394 @@
|
||||
/* ========================================================================= #
|
||||
# #
|
||||
# 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 "ph_usb.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/unique_id.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#if TUD_OPT_HIGH_SPEED
|
||||
# error "High-Speed is not supported"
|
||||
#endif
|
||||
|
||||
#include "ph_types.h"
|
||||
#include "ph_outputs.h"
|
||||
#include "ph_usb_kbd.h"
|
||||
#include "ph_usb_mouse.h"
|
||||
|
||||
|
||||
u8 ph_g_usb_kbd_leds = 0;
|
||||
bool ph_g_usb_kbd_online = true;
|
||||
bool ph_g_usb_mouse_online = true;
|
||||
|
||||
static int _kbd_iface = -1;
|
||||
static int _mouse_iface = -1;
|
||||
|
||||
static u8 _kbd_mods = 0;
|
||||
static u8 _kbd_keys[6] = {0};
|
||||
#define _KBD_CLEAR { _kbd_mods = 0; memset(_kbd_keys, 0, 6); }
|
||||
|
||||
static u8 _mouse_buttons = 0;
|
||||
static s16 _mouse_abs_x = 0;
|
||||
static s16 _mouse_abs_y = 0;
|
||||
#define _MOUSE_CLEAR { _mouse_buttons = 0; _mouse_abs_x = 0; _mouse_abs_y = 0; }
|
||||
|
||||
|
||||
static void _kbd_sync_report(bool new);
|
||||
static void _mouse_abs_send_report(s8 h, s8 v);
|
||||
static void _mouse_rel_send_report(s8 x, s8 y, s8 h, s8 v);
|
||||
|
||||
|
||||
void ph_usb_init(void) {
|
||||
if (PH_O_IS_KBD_USB || PH_O_IS_MOUSE_USB) {
|
||||
tud_init(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ph_usb_task(void) {
|
||||
if (PH_O_IS_KBD_USB || PH_O_IS_MOUSE_USB) {
|
||||
tud_task();
|
||||
|
||||
static u64 next_ts = 0;
|
||||
const u64 now_ts = time_us_64();
|
||||
if (next_ts == 0 || now_ts >= next_ts) {
|
||||
# define CHECK_IFACE(x_dev) \
|
||||
static u64 offline_ts = 0; \
|
||||
static bool prev_online = true; \
|
||||
const bool online = (tud_ready() && tud_hid_n_ready(_##x_dev##_iface)); \
|
||||
bool force = false; \
|
||||
if (online) { \
|
||||
if (!ph_g_usb_##x_dev##_online) { \
|
||||
force = true; /* Если был переход из долгого оффлайна в онлайн */ \
|
||||
} \
|
||||
ph_g_usb_##x_dev##_online = true; \
|
||||
offline_ts = 0; \
|
||||
} else if (prev_online && !online) { \
|
||||
offline_ts = now_ts; /* Начинаем отсчет для долгого оффлайна */ \
|
||||
} else if (!prev_online && !online && offline_ts + 50000 < now_ts) { \
|
||||
ph_g_usb_##x_dev##_online = false; /* Долгий оффлайн найден */ \
|
||||
} \
|
||||
prev_online = online;
|
||||
|
||||
if (_kbd_iface >= 0) {
|
||||
CHECK_IFACE(kbd);
|
||||
_kbd_sync_report(force);
|
||||
}
|
||||
|
||||
if (_mouse_iface >= 0) {
|
||||
CHECK_IFACE(mouse);
|
||||
(void)force;
|
||||
}
|
||||
|
||||
# undef CHECK_IFACE
|
||||
next_ts = time_us_64() + 1000; // Every 1 ms
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ph_usb_kbd_send_key(u8 key, bool state) {
|
||||
if (_kbd_iface < 0) {
|
||||
return; // Допускаем планирование нажатия, пока устройство не готово
|
||||
}
|
||||
|
||||
if (key >= HID_KEY_CONTROL_LEFT && key <= HID_KEY_GUI_RIGHT) { // 0xE0...0xE7 - Modifiers
|
||||
key = 1 << (key & 0x07); // Номер означает сдвиг
|
||||
if (state) {
|
||||
_kbd_mods |= key;
|
||||
} else {
|
||||
_kbd_mods &= ~key;
|
||||
}
|
||||
|
||||
} else { // Regular keys
|
||||
if (state) {
|
||||
s8 pos = -1;
|
||||
for (u8 i = 0; i < 6; ++i) {
|
||||
if (_kbd_keys[i] == key) {
|
||||
goto already_pressed;
|
||||
} else if (_kbd_keys[i] == 0) {
|
||||
pos = i;
|
||||
}
|
||||
}
|
||||
_kbd_keys[pos >= 0 ? pos : 0] = key;
|
||||
already_pressed:
|
||||
} else {
|
||||
for (u8 i = 0; i < 6; ++i) {
|
||||
if (_kbd_keys[i] == key) {
|
||||
_kbd_keys[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_kbd_sync_report(true);
|
||||
}
|
||||
|
||||
void ph_usb_mouse_send_button(u8 button, bool state) {
|
||||
if (!PH_O_IS_MOUSE_USB) {
|
||||
return;
|
||||
}
|
||||
if (state) {
|
||||
_mouse_buttons |= button;
|
||||
} else {
|
||||
_mouse_buttons &= ~button;
|
||||
}
|
||||
if (PH_O_IS_MOUSE_USB_ABS) {
|
||||
_mouse_abs_send_report(0, 0);
|
||||
} else { // PH_O_IS_MOUSE_USB_REL
|
||||
_mouse_rel_send_report(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ph_usb_mouse_send_abs(s16 x, s16 y) {
|
||||
if (PH_O_IS_MOUSE_USB_ABS) {
|
||||
_mouse_abs_x = x;
|
||||
_mouse_abs_y = y;
|
||||
_mouse_abs_send_report(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ph_usb_mouse_send_rel(s8 x, s8 y) {
|
||||
if (PH_O_IS_MOUSE_USB_REL) {
|
||||
_mouse_rel_send_report(x, y, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ph_usb_mouse_send_wheel(s8 h, s8 v) {
|
||||
if (PH_O_IS_MOUSE_USB_ABS) {
|
||||
_mouse_abs_send_report(h, v);
|
||||
} else { // PH_O_IS_MOUSE_USB_REL
|
||||
_mouse_rel_send_report(0, 0, h, v);
|
||||
}
|
||||
}
|
||||
|
||||
void ph_usb_send_clear(void) {
|
||||
if (PH_O_IS_KBD_USB) {
|
||||
_KBD_CLEAR;
|
||||
_kbd_sync_report(true);
|
||||
}
|
||||
if (PH_O_IS_MOUSE_USB) {
|
||||
_MOUSE_CLEAR;
|
||||
if (PH_O_IS_MOUSE_USB_ABS) {
|
||||
_mouse_abs_send_report(0, 0);
|
||||
} else { // PH_O_IS_MOUSE_USB_REL
|
||||
_mouse_rel_send_report(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// RAW report senders
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
static void _kbd_sync_report(bool new) {
|
||||
static bool sent = true;
|
||||
if (_kbd_iface < 0 || !PH_O_IS_KBD_USB) {
|
||||
_KBD_CLEAR;
|
||||
sent = true;
|
||||
return;
|
||||
}
|
||||
if (new) {
|
||||
sent = false;
|
||||
}
|
||||
if (!sent) {
|
||||
if (tud_suspended()) {
|
||||
tud_remote_wakeup();
|
||||
//_KBD_CLEAR;
|
||||
//sent = true;
|
||||
} else {
|
||||
sent = tud_hid_n_keyboard_report(_kbd_iface, 0, _kbd_mods, _kbd_keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define _CHECK_MOUSE(x_mode) { \
|
||||
if (_mouse_iface < 0 || !PH_O_IS_MOUSE_USB_##x_mode) { _MOUSE_CLEAR; return; } \
|
||||
if (tud_suspended()) { tud_remote_wakeup(); _MOUSE_CLEAR; return; } \
|
||||
}
|
||||
|
||||
|
||||
static void _mouse_abs_send_report(s8 h, s8 v) {
|
||||
(void)h; // Horizontal scrolling is not supported due BIOS/UEFI compatibility reasons
|
||||
_CHECK_MOUSE(ABS);
|
||||
u16 x = ((s32)_mouse_abs_x + 32768) / 2;
|
||||
u16 y = ((s32)_mouse_abs_y + 32768) / 2;
|
||||
if (PH_O_MOUSE(USB_W98)) {
|
||||
x <<= 1;
|
||||
y <<= 1;
|
||||
}
|
||||
struct TU_ATTR_PACKED {
|
||||
u8 buttons;
|
||||
u16 x;
|
||||
u16 y;
|
||||
s8 v;
|
||||
} report = {_mouse_buttons, x, y, v};
|
||||
tud_hid_n_report(_mouse_iface, 0, &report, sizeof(report));
|
||||
}
|
||||
|
||||
static void _mouse_rel_send_report(s8 x, s8 y, s8 h, s8 v) {
|
||||
(void)h; // Horizontal scrolling is not supported due BIOS/UEFI compatibility reasons
|
||||
_CHECK_MOUSE(REL);
|
||||
struct TU_ATTR_PACKED {
|
||||
u8 buttons;
|
||||
s8 x;
|
||||
s8 y;
|
||||
s8 v;
|
||||
} report = {_mouse_buttons, x, y, v};
|
||||
tud_hid_n_report(_mouse_iface, 0, &report, sizeof(report));
|
||||
}
|
||||
|
||||
#undef _CHECK_MOUSE
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Device callbacks
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
u16 tud_hid_get_report_cb(u8 iface, u8 report_id, hid_report_type_t report_type, u8 *buf, u16 len) {
|
||||
// Invoked when received GET_REPORT control request, return 0 == STALL
|
||||
(void)iface;
|
||||
(void)report_id;
|
||||
(void)report_type;
|
||||
(void)buf;
|
||||
(void)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tud_hid_set_report_cb(u8 iface, u8 report_id, hid_report_type_t report_type, const u8 *buf, u16 len) {
|
||||
// Invoked when received SET_REPORT control request
|
||||
// or received data on OUT endpoint (ReportID=0, Type=0)
|
||||
(void)report_id;
|
||||
if (iface == _kbd_iface && report_type == HID_REPORT_TYPE_OUTPUT && len >= 1) {
|
||||
ph_g_usb_kbd_leds = buf[0];
|
||||
}
|
||||
}
|
||||
|
||||
const u8 *tud_hid_descriptor_report_cb(u8 iface) {
|
||||
if ((int)iface == _mouse_iface) {
|
||||
if (PH_O_IS_MOUSE_USB_ABS) {
|
||||
return PH_USB_MOUSE_ABS_DESC;
|
||||
} else { // PH_O_IS_MOUSE_USB_REL
|
||||
return PH_USB_MOUSE_REL_DESC;
|
||||
}
|
||||
}
|
||||
return PH_USB_KBD_DESC; // _kbd_iface, PH_O_IS_KBD_USB
|
||||
}
|
||||
|
||||
const u8 *tud_descriptor_configuration_cb(u8 index) {
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||
(void)index;
|
||||
|
||||
static u8 desc[TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN * 2] = {0};
|
||||
static bool filled = false;
|
||||
|
||||
if (!filled) {
|
||||
uz offset = TUD_CONFIG_DESC_LEN;
|
||||
u8 iface = 0;
|
||||
u8 ep = 0x81;
|
||||
|
||||
# define APPEND_DESC(x_proto, x_desc, x_iface_to) { \
|
||||
const u8 part[] = {TUD_HID_DESCRIPTOR( \
|
||||
(x_iface_to = iface), /* Interface number */ \
|
||||
0, x_proto, x_desc##_LEN, /* String index, protocol, report descriptor len */ \
|
||||
ep, CFG_TUD_HID_EP_BUFSIZE, 1)}; /* EP In address, size, polling interval */ \
|
||||
memcpy(desc + offset, part, TUD_HID_DESC_LEN); \
|
||||
offset += TUD_HID_DESC_LEN; ++iface; ++ep; \
|
||||
}
|
||||
|
||||
if (PH_O_IS_KBD_USB) {
|
||||
APPEND_DESC(HID_ITF_PROTOCOL_KEYBOARD, PH_USB_KBD_DESC, _kbd_iface);
|
||||
}
|
||||
if (PH_O_IS_MOUSE_USB_ABS) {
|
||||
APPEND_DESC(HID_ITF_PROTOCOL_NONE, PH_USB_MOUSE_ABS_DESC, _mouse_iface);
|
||||
} else if (PH_O_IS_MOUSE_USB_REL) {
|
||||
APPEND_DESC(HID_ITF_PROTOCOL_MOUSE, PH_USB_MOUSE_REL_DESC, _mouse_iface);
|
||||
}
|
||||
|
||||
# undef APPEND_DESC
|
||||
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
const u8 part[] = {TUD_CONFIG_DESCRIPTOR(1, iface, 0, offset, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100)};
|
||||
memcpy(desc, part, TUD_CONFIG_DESC_LEN);
|
||||
filled = true;
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
const u8 *tud_descriptor_device_cb(void) {
|
||||
// Invoked when received GET DEVICE DESCRIPTOR
|
||||
|
||||
static const tusb_desc_device_t desc = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
|
||||
.bDeviceClass = 0,
|
||||
.bDeviceSubClass = 0,
|
||||
.bDeviceProtocol = 0,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = 0x1209, // https://pid.codes/org/Pi-KVM
|
||||
.idProduct = 0xEDA2,
|
||||
.bcdDevice = 0x0100,
|
||||
|
||||
.iManufacturer = 1,
|
||||
.iProduct = 2,
|
||||
.iSerialNumber = 3,
|
||||
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
return (const u8 *)&desc;
|
||||
}
|
||||
|
||||
const u16 *tud_descriptor_string_cb(u8 index, u16 lang_id) {
|
||||
// Invoked when received GET STRING DESCRIPTOR request.
|
||||
(void)lang_id;
|
||||
|
||||
static u16 desc_str[32];
|
||||
uz desc_str_len;
|
||||
|
||||
if (index == 0) {
|
||||
desc_str[1] = 0x0409; // Supported language is English (0x0409)
|
||||
desc_str_len = 1;
|
||||
} else {
|
||||
char str[32];
|
||||
switch (index) {
|
||||
case 1: strcpy(str, "PiKVM"); break; // Manufacturer
|
||||
case 2: strcpy(str, "PiKVM HID"); break; // Product
|
||||
case 3: pico_get_unique_board_id_string(str, 32); break; // Serial
|
||||
default: return NULL;
|
||||
}
|
||||
desc_str_len = strlen(str);
|
||||
for (uz i = 0; i < desc_str_len; ++i) {
|
||||
desc_str[i + 1] = str[i]; // Convert ASCII string into UTF-16
|
||||
}
|
||||
}
|
||||
|
||||
// First byte is length (including header), second byte is string type
|
||||
desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * desc_str_len + 2);
|
||||
return desc_str;
|
||||
}
|
||||
43
hid/pico/src/ph_usb.h
Normal file
43
hid/pico/src/ph_usb.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* ========================================================================= #
|
||||
# #
|
||||
# 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 "ph_types.h"
|
||||
|
||||
|
||||
extern u8 ph_g_usb_kbd_leds;
|
||||
extern bool ph_g_usb_kbd_online;
|
||||
extern bool ph_g_usb_mouse_online;
|
||||
|
||||
|
||||
void ph_usb_init(void);
|
||||
void ph_usb_task(void);
|
||||
|
||||
void ph_usb_kbd_send_key(u8 key, bool state);
|
||||
|
||||
void ph_usb_mouse_send_button(u8 button, bool state);
|
||||
void ph_usb_mouse_send_abs(s16 x, s16 y);
|
||||
void ph_usb_mouse_send_rel(s8 x, s8 y);
|
||||
void ph_usb_mouse_send_wheel(s8 h, s8 v);
|
||||
|
||||
void ph_usb_send_clear(void);
|
||||
78
hid/pico/src/ph_usb_kbd.c
Normal file
78
hid/pico/src/ph_usb_kbd.c
Normal file
@ -0,0 +1,78 @@
|
||||
/* ========================================================================= #
|
||||
# #
|
||||
# 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 "ph_usb_kbd.h"
|
||||
|
||||
#include "ph_types.h"
|
||||
|
||||
|
||||
const u8 PH_USB_KBD_DESC[] = {
|
||||
// Logitech descriptor. It's very similar to https://www.kernel.org/doc/Documentation/usb/gadget_hid.txt
|
||||
// Dumped using usbhid-dump; parsed using https://eleccelerator.com/usbdescreqparser
|
||||
|
||||
// Keyboard
|
||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||
0x09, 0x06, // USAGE (Keyboard)
|
||||
0xA1, 0x01, // COLLECTION (Application)
|
||||
|
||||
// Modifiers
|
||||
0x05, 0x07, // USAGE_PAGE (Keyboard)
|
||||
0x19, 0xE0, // USAGE_MINIMUM (Keyboard LeftControl)
|
||||
0x29, 0xE7, // USAGE_MAXIMUM (Keyboard Right GUI)
|
||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
||||
0x75, 0x01, // REPORT_SIZE (1)
|
||||
0x95, 0x08, // REPORT_COUNT (8)
|
||||
0x81, 0x02, // INPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
|
||||
// Reserved byte
|
||||
0x95, 0x01, // REPORT_COUNT (1)
|
||||
0x75, 0x08, // REPORT_SIZE (8)
|
||||
0x81, 0x01, // INPUT (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
|
||||
// LEDs output
|
||||
0x95, 0x05, // REPORT_COUNT (5)
|
||||
0x75, 0x01, // REPORT_SIZE (1)
|
||||
0x05, 0x08, // USAGE_PAGE (LEDs)
|
||||
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
|
||||
0x29, 0x05, // USAGE_MAXIMUM (Kana)
|
||||
0x91, 0x02, // OUTPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
|
||||
// Reserved 3 bits in output
|
||||
0x95, 0x01, // REPORT_COUNT (1)
|
||||
0x75, 0x03, // REPORT_SIZE (3)
|
||||
0x91, 0x01, // OUTPUT (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
|
||||
// 6 keys
|
||||
0x95, 0x06, // REPORT_COUNT (6)
|
||||
0x75, 0x08, // REPORT_SIZE (8)
|
||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (0xFF)
|
||||
0x05, 0x07, // USAGE_PAGE (Keyboard)
|
||||
0x19, 0x00, // USAGE_MINIMUM (Reserved)
|
||||
0x2A, 0xFF, 0x00, // USAGE_MAXIMUM (0xFF)
|
||||
0x81, 0x00, // INPUT (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
|
||||
0xC0, // END_COLLECTION
|
||||
};
|
||||
|
||||
const uz PH_USB_KBD_DESC_LEN = sizeof(PH_USB_KBD_DESC);
|
||||
29
hid/pico/src/ph_usb_kbd.h
Normal file
29
hid/pico/src/ph_usb_kbd.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* ========================================================================= #
|
||||
# #
|
||||
# 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 "ph_types.h"
|
||||
|
||||
|
||||
extern const u8 PH_USB_KBD_DESC[];
|
||||
extern const uz PH_USB_KBD_DESC_LEN;
|
||||
143
hid/pico/src/ph_usb_keymap.h
Normal file
143
hid/pico/src/ph_usb_keymap.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# 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 "ph_types.h"
|
||||
|
||||
|
||||
u8 ph_usb_keymap(u8 key) {
|
||||
switch (key) {
|
||||
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
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
39
hid/pico/src/ph_usb_keymap.h.mako
Normal file
39
hid/pico/src/ph_usb_keymap.h.mako
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 "ph_types.h"
|
||||
|
||||
<%! import operator %>
|
||||
u8 ph_usb_keymap(u8 key) {
|
||||
switch (key) {
|
||||
% 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
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
120
hid/pico/src/ph_usb_mouse.c
Normal file
120
hid/pico/src/ph_usb_mouse.c
Normal file
@ -0,0 +1,120 @@
|
||||
/* ========================================================================= #
|
||||
# #
|
||||
# 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 "ph_usb_mouse.h"
|
||||
|
||||
#include "ph_types.h"
|
||||
|
||||
|
||||
const u8 PH_USB_MOUSE_ABS_DESC[] = {
|
||||
// https://github.com/NicoHood/HID/blob/0835e6a/src/SingleReport/SingleAbsoluteMouse.cpp
|
||||
// Репорт взят отсюда ^^^, но изменен диапазон значений координат перемещений.
|
||||
// Автор предлагает использовать -32768...32767, но семерка почему-то не хочет работать
|
||||
// с отрицательными значениями координат, как не хочет хавать 65536 и 32768.
|
||||
// Так что мы ей скармливаем диапазон 0...32767, и передаем рукожопам из микрософта привет,
|
||||
// потому что линуксы прекрасно работают с любыми двухбайтовыми диапазонами.
|
||||
|
||||
// Absolute mouse
|
||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||
0x09, 0x02, // USAGE (Mouse)
|
||||
0xA1, 0x01, // COLLECTION (Application)
|
||||
|
||||
// Pointer and Physical are required by Apple Recovery
|
||||
0x09, 0x01, // USAGE (Pointer)
|
||||
0xA1, 0x00, // COLLECTION (Physical)
|
||||
|
||||
// 8 Buttons
|
||||
0x05, 0x09, // USAGE_PAGE (Button)
|
||||
0x19, 0x01, // USAGE_MINIMUM (Button 1)
|
||||
0x29, 0x08, // USAGE_MAXIMUM (Button 8)
|
||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
||||
0x95, 0x08, // REPORT_COUNT (8)
|
||||
0x75, 0x01, // REPORT_SIZE (1)
|
||||
0x81, 0x02, // INPUT (Data,Var,Abs)
|
||||
|
||||
// X, Y
|
||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||
0x09, 0x30, // USAGE (X)
|
||||
0x09, 0x31, // USAGE (Y)
|
||||
0x16, 0x00, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x26, 0xFF, 0x7F, // LOGICAL_MAXIMUM (32767)
|
||||
0x75, 0x10, // REPORT_SIZE (16)
|
||||
0x95, 0x02, // REPORT_COUNT (2)
|
||||
0x81, 0x02, // INPUT (Data,Var,Abs)
|
||||
|
||||
// Wheel
|
||||
0x09, 0x38, // USAGE (Wheel)
|
||||
0x15, 0x81, // LOGICAL_MINIMUM (-127)
|
||||
0x25, 0x7F, // LOGICAL_MAXIMUM (127)
|
||||
0x75, 0x08, // REPORT_SIZE (8)
|
||||
0x95, 0x01, // REPORT_COUNT (1)
|
||||
0x81, 0x06, // INPUT (Data,Var,Rel)
|
||||
|
||||
// End
|
||||
0xC0, // END_COLLECTION (Physical)
|
||||
0xC0, // END_COLLECTION
|
||||
};
|
||||
|
||||
const uz PH_USB_MOUSE_ABS_DESC_LEN = sizeof(PH_USB_MOUSE_ABS_DESC);
|
||||
|
||||
const u8 PH_USB_MOUSE_REL_DESC[] = {
|
||||
// https://github.com/NicoHood/HID/blob/0835e6a/src/SingleReport/BootMouse.cpp
|
||||
|
||||
// Relative mouse
|
||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||
0x09, 0x02, // USAGE (Mouse)
|
||||
0xA1, 0x01, // COLLECTION (Application)
|
||||
|
||||
// Pointer and Physical are required by Apple Recovery
|
||||
0x09, 0x01, // USAGE (Pointer)
|
||||
0xA1, 0x00, // COLLECTION (Physical)
|
||||
|
||||
// 8 Buttons
|
||||
0x05, 0x09, // USAGE_PAGE (Button)
|
||||
0x19, 0x01, // USAGE_MINIMUM (Button 1)
|
||||
0x29, 0x08, // USAGE_MAXIMUM (Button 8)
|
||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
||||
0x95, 0x08, // REPORT_COUNT (8)
|
||||
0x75, 0x01, // REPORT_SIZE (1)
|
||||
0x81, 0x02, // INPUT (Data,Var,Abs)
|
||||
|
||||
// X, Y
|
||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||
0x09, 0x30, // USAGE (X)
|
||||
0x09, 0x31, // USAGE (Y)
|
||||
|
||||
// Wheel
|
||||
0x09, 0x38, // USAGE (Wheel)
|
||||
0x15, 0x81, // LOGICAL_MINIMUM (-127)
|
||||
0x25, 0x7F, // LOGICAL_MAXIMUM (127)
|
||||
0x75, 0x08, // REPORT_SIZE (8)
|
||||
0x95, 0x03, // REPORT_COUNT (3)
|
||||
0x81, 0x06, // INPUT (Data,Var,Rel)
|
||||
|
||||
// End
|
||||
0xC0, // END_COLLECTION (Physical)
|
||||
0xC0, // END_COLLECTION
|
||||
};
|
||||
|
||||
const uz PH_USB_MOUSE_REL_DESC_LEN = sizeof(PH_USB_MOUSE_REL_DESC);
|
||||
32
hid/pico/src/ph_usb_mouse.h
Normal file
32
hid/pico/src/ph_usb_mouse.h
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/>. #
|
||||
# #
|
||||
# ========================================================================= */
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ph_types.h"
|
||||
|
||||
|
||||
extern const u8 PH_USB_MOUSE_ABS_DESC[];
|
||||
extern const uz PH_USB_MOUSE_ABS_DESC_LEN;
|
||||
|
||||
extern const u8 PH_USB_MOUSE_REL_DESC[];
|
||||
extern const uz PH_USB_MOUSE_REL_DESC_LEN;
|
||||
67
hid/pico/src/tusb_config.h
Normal file
67
hid/pico/src/tusb_config.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* ========================================================================= #
|
||||
# #
|
||||
# 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
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Common config
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
//#define CFG_TUSB_DEBUG 100
|
||||
|
||||
#define CFG_TUSB_OS OPT_OS_PICO
|
||||
|
||||
// Enable device stack
|
||||
#define CFG_TUD_ENABLED 1
|
||||
|
||||
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||
//#define CFG_TUSB_DEBUG 100
|
||||
|
||||
// USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
// Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
// into those specific section.
|
||||
// - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
// - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
# define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
# define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4)))
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Device config
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
# define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
#define CFG_TUD_HID 2
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#ifndef CFG_TUD_HID_EP_BUFSIZE
|
||||
# define CFG_TUD_HID_EP_BUFSIZE 16
|
||||
#endif
|
||||
@ -108,6 +108,7 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
|
||||
reset_pin: int,
|
||||
reset_inverted: bool,
|
||||
reset_delay: float,
|
||||
reset_self: bool,
|
||||
|
||||
read_retries: int,
|
||||
common_retries: int,
|
||||
@ -126,6 +127,7 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
|
||||
|
||||
self.__phy = phy
|
||||
self.__gpio = Gpio(gpio_device_path, reset_pin, reset_inverted, reset_delay)
|
||||
self.__reset_self = reset_self
|
||||
|
||||
self.__reset_required_event = multiprocessing.Event()
|
||||
self.__events_queue: "multiprocessing.Queue[BaseEvent]" = multiprocessing.Queue()
|
||||
@ -146,6 +148,7 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
|
||||
"reset_pin": Option(4, type=valid_gpio_pin_optional),
|
||||
"reset_inverted": Option(False, type=valid_bool),
|
||||
"reset_delay": Option(0.1, type=valid_float_f01),
|
||||
"reset_self": Option(False, type=valid_bool),
|
||||
|
||||
"read_retries": Option(5, type=valid_int_f1),
|
||||
"common_retries": Option(5, type=valid_int_f1),
|
||||
@ -418,4 +421,7 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
|
||||
reset_required = (1 if response[1] & 0b01000000 else 0)
|
||||
self.__state_flags.update(online=1, busy=reset_required, status=status)
|
||||
if reset_required:
|
||||
self.__reset_required_event.set()
|
||||
if self.__reset_self:
|
||||
time.sleep(1) # Pico перезагружается сам вскоре после ответа
|
||||
else:
|
||||
self.__reset_required_event.set()
|
||||
|
||||
@ -100,6 +100,7 @@ class _SpiPhy(BasePhy): # pylint: disable=too-many-instance-attributes
|
||||
chip: int,
|
||||
hw_cs: bool,
|
||||
sw_cs_pin: int,
|
||||
sw_cs_per_byte: bool,
|
||||
max_freq: int,
|
||||
block_usec: int,
|
||||
read_timeout: float,
|
||||
@ -110,6 +111,7 @@ class _SpiPhy(BasePhy): # pylint: disable=too-many-instance-attributes
|
||||
self.__chip = chip
|
||||
self.__hw_cs = hw_cs
|
||||
self.__sw_cs_pin = sw_cs_pin
|
||||
self.__sw_cs_per_byte = sw_cs_per_byte
|
||||
self.__max_freq = max_freq
|
||||
self.__block_usec = block_usec
|
||||
self.__read_timeout = read_timeout
|
||||
@ -125,7 +127,7 @@ class _SpiPhy(BasePhy): # pylint: disable=too-many-instance-attributes
|
||||
spi.no_cs = (not self.__hw_cs)
|
||||
spi.max_speed_hz = self.__max_freq
|
||||
|
||||
def xfer(data: bytes) -> bytes:
|
||||
def inner_xfer(data: bytes) -> bytes:
|
||||
try:
|
||||
if sw_cs_line is not None:
|
||||
sw_cs_line.set_value(0)
|
||||
@ -134,6 +136,17 @@ class _SpiPhy(BasePhy): # pylint: disable=too-many-instance-attributes
|
||||
if sw_cs_line is not None:
|
||||
sw_cs_line.set_value(1)
|
||||
|
||||
if self.__sw_cs_per_byte:
|
||||
# Режим для Pico, когда CS должен взводиться для отдельных байтов
|
||||
def xfer(data: bytes) -> bytes:
|
||||
got: list[int] = []
|
||||
for byte in data:
|
||||
got.extend(inner_xfer(byte.to_bytes(1, "big")))
|
||||
return bytes(got)
|
||||
else:
|
||||
# Режим для Arduino, когда CS взводится для целого блока данных
|
||||
xfer = inner_xfer
|
||||
|
||||
yield _SpiPhyConnection(
|
||||
xfer=xfer,
|
||||
read_timeout=self.__read_timeout,
|
||||
@ -167,11 +180,12 @@ class Plugin(BaseMcuHid):
|
||||
@classmethod
|
||||
def __get_phy_options(cls) -> dict:
|
||||
return {
|
||||
"bus": Option(-1, type=valid_int_f0),
|
||||
"chip": Option(-1, type=valid_int_f0),
|
||||
"hw_cs": Option(False, type=valid_bool),
|
||||
"sw_cs_pin": Option(-1, type=valid_gpio_pin_optional),
|
||||
"max_freq": Option(100000, type=valid_int_f1),
|
||||
"block_usec": Option(1, type=valid_int_f0),
|
||||
"read_timeout": Option(0.5, type=valid_float_f01),
|
||||
"bus": Option(-1, type=valid_int_f0),
|
||||
"chip": Option(-1, type=valid_int_f0),
|
||||
"hw_cs": Option(False, type=valid_bool),
|
||||
"sw_cs_pin": Option(-1, type=valid_gpio_pin_optional),
|
||||
"sw_cs_per_byte": Option(False, type=valid_bool),
|
||||
"max_freq": Option(100000, type=valid_int_f1),
|
||||
"block_usec": Option(1, type=valid_int_f0),
|
||||
"read_timeout": Option(0.5, type=valid_float_f01),
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user