diff options
author | Maxim Devaev <[email protected]> | 2023-08-25 12:35:28 +0300 |
---|---|---|
committer | Maxim Devaev <[email protected]> | 2023-08-25 12:35:28 +0300 |
commit | 21eddbde1c11961d7fb958422d6dd72b94c33375 (patch) | |
tree | 2a869d17932914a4481e6356dc78ab8690cd872c /hid/pico | |
parent | 82ca2b1caed602030d2d849a9e61748ea7249ac9 (diff) |
pico hid bridge mode
Diffstat (limited to 'hid/pico')
-rw-r--r-- | hid/pico/src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | hid/pico/src/main.c | 2 | ||||
-rw-r--r-- | hid/pico/src/ph_com.c | 32 | ||||
-rw-r--r-- | hid/pico/src/ph_com_bridge.c | 84 | ||||
-rw-r--r-- | hid/pico/src/ph_com_bridge.h | 30 | ||||
-rw-r--r-- | hid/pico/src/ph_outputs.c | 9 | ||||
-rw-r--r-- | hid/pico/src/ph_outputs.h | 1 | ||||
-rw-r--r-- | hid/pico/src/ph_usb.c | 58 | ||||
-rw-r--r-- | hid/pico/src/tusb_config.h | 12 |
9 files changed, 203 insertions, 26 deletions
diff --git a/hid/pico/src/CMakeLists.txt b/hid/pico/src/CMakeLists.txt index 5353a0c8..cb1c7feb 100644 --- a/hid/pico/src/CMakeLists.txt +++ b/hid/pico/src/CMakeLists.txt @@ -10,6 +10,7 @@ target_sources(${target_name} PRIVATE ph_ps2.c ph_cmds.c ph_com.c + ph_com_bridge.c ph_com_spi.c ph_com_uart.c ph_debug.c diff --git a/hid/pico/src/main.c b/hid/pico/src/main.c index a1c9531f..f1d266a5 100644 --- a/hid/pico/src/main.c +++ b/hid/pico/src/main.c @@ -114,8 +114,8 @@ int main(void) { //ph_debug_act_init(); //ph_debug_uart_init(); ph_outputs_init(); - ph_usb_init(); ph_ps2_init(); + ph_usb_init(); // Тут может быть инициализация USB-CDC для бриджа ph_com_init(_data_handler, _timeout_handler); while (true) { diff --git a/hid/pico/src/ph_com.c b/hid/pico/src/ph_com.c index 697edac9..85a7923a 100644 --- a/hid/pico/src/ph_com.c +++ b/hid/pico/src/ph_com.c @@ -26,6 +26,8 @@ #include "hardware/gpio.h" #include "ph_types.h" +#include "ph_outputs.h" +#include "ph_com_bridge.h" #include "ph_com_spi.h" #include "ph_com_uart.h" @@ -36,32 +38,30 @@ static bool _use_spi = true; +#define _COM(x_func, ...) { \ + if (ph_g_is_bridge) { \ + ph_com_bridge_##x_func(__VA_ARGS__); \ + } else if (_use_spi) { \ + ph_com_spi_##x_func(__VA_ARGS__); \ + } else { \ + ph_com_uart_##x_func(__VA_ARGS__); \ + } \ + } + + void ph_com_init(void (*data_cb)(const u8 *), void (*timeout_cb)(void)) { gpio_init(_USE_SPI_PIN); gpio_set_dir(_USE_SPI_PIN, GPIO_IN); gpio_pull_up(_USE_SPI_PIN); sleep_ms(10); // Нужен небольшой слип для активации pull-up _use_spi = gpio_get(_USE_SPI_PIN); - - if (_use_spi) { - ph_com_spi_init(data_cb, timeout_cb); - } else { - ph_com_uart_init(data_cb, timeout_cb); - } + _COM(init, data_cb, timeout_cb); } void ph_com_task(void) { - if (_use_spi) { - ph_com_spi_task(); - } else { - ph_com_uart_task(); - } + _COM(task); } void ph_com_write(const u8 *data) { - if (_use_spi) { - ph_com_spi_write(data); - } else { - ph_com_uart_write(data); - } + _COM(write, data); } diff --git a/hid/pico/src/ph_com_bridge.c b/hid/pico/src/ph_com_bridge.c new file mode 100644 index 00000000..6731527b --- /dev/null +++ b/hid/pico/src/ph_com_bridge.c @@ -0,0 +1,84 @@ +/***************************************************************************** +# # +# KVMD - The main PiKVM daemon. # +# # +# Copyright (C) 2018-2023 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +*****************************************************************************/ + + +#include "ph_com_bridge.h" + +#include "pico/stdlib.h" + +#include "tusb.h" + +#include "ph_types.h" + + +#define _TIMEOUT_US 100000 + + +static u8 _buf[8] = {0}; +static u8 _index = 0; +static u64 _last_ts = 0; + +static void (*_data_cb)(const u8 *) = NULL; +static void (*_timeout_cb)(void) = NULL; + + +void ph_com_bridge_init(void (*data_cb)(const u8 *), void (*timeout_cb)(void)) { + _data_cb = data_cb; + _timeout_cb = timeout_cb; +} + +void ph_com_bridge_task(void) { + if (!tud_cdc_connected()) { + tud_cdc_write_clear(); + return; + } + + if (tud_cdc_available() > 0) { + const s32 ch = tud_cdc_read_char(); + if (ch < 0) { + goto no_data; + } + _buf[_index] = (u8)ch; + if (_index == 7) { + _data_cb(_buf); + _index = 0; + } else { + _last_ts = time_us_64(); + ++_index; + } + return; + } + + no_data: + if (_index > 0) { + if (_last_ts + _TIMEOUT_US < time_us_64()) { + _timeout_cb(); + _index = 0; + } + } +} + +void ph_com_bridge_write(const u8 *data) { + if (tud_cdc_connected()) { + tud_cdc_write(data, 8); + tud_cdc_write_flush(); + } +} diff --git a/hid/pico/src/ph_com_bridge.h b/hid/pico/src/ph_com_bridge.h new file mode 100644 index 00000000..7bfd5d31 --- /dev/null +++ b/hid/pico/src/ph_com_bridge.h @@ -0,0 +1,30 @@ +/***************************************************************************** +# # +# KVMD - The main PiKVM daemon. # +# # +# Copyright (C) 2018-2023 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +*****************************************************************************/ + + +#pragma once + +#include "ph_types.h" + + +void ph_com_bridge_init(void (*data_cb)(const u8 *), void (*timeout_cb)(void)); +void ph_com_bridge_task(void); +void ph_com_bridge_write(const u8 *data); diff --git a/hid/pico/src/ph_outputs.c b/hid/pico/src/ph_outputs.c index 307b25db..a61b659f 100644 --- a/hid/pico/src/ph_outputs.c +++ b/hid/pico/src/ph_outputs.c @@ -35,6 +35,8 @@ #define _PS2_SET_KBD_PIN 3 #define _PS2_SET_MOUSE_PIN 4 +#define _BRIDGE_MODE_PIN 5 + #define _USB_DISABLED_PIN 6 #define _USB_ENABLE_W98_PIN 7 #define _USB_SET_MOUSE_REL_PIN 8 @@ -43,6 +45,7 @@ u8 ph_g_outputs_active = 0; u8 ph_g_outputs_avail = 0; +bool ph_g_is_bridge = false; static int _read_outputs(void); @@ -54,6 +57,8 @@ void ph_outputs_init(void) { INIT_SWITCH(_PS2_SET_KBD_PIN); INIT_SWITCH(_PS2_SET_MOUSE_PIN); + INIT_SWITCH(_BRIDGE_MODE_PIN); + INIT_SWITCH(_USB_DISABLED_PIN); INIT_SWITCH(_USB_ENABLE_W98_PIN); INIT_SWITCH(_USB_SET_MOUSE_REL_PIN); @@ -65,7 +70,9 @@ void ph_outputs_init(void) { 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); + ph_g_is_bridge = !gpio_get(_BRIDGE_MODE_PIN); + + const bool o_usb_disabled = (ph_g_is_bridge || !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); diff --git a/hid/pico/src/ph_outputs.h b/hid/pico/src/ph_outputs.h index 13f1bbda..ce68ac30 100644 --- a/hid/pico/src/ph_outputs.h +++ b/hid/pico/src/ph_outputs.h @@ -36,6 +36,7 @@ #define PH_O_IS_MOUSE_PS2 PH_O_MOUSE(PS2) +extern bool ph_g_is_bridge; extern u8 ph_g_outputs_active; extern u8 ph_g_outputs_avail; diff --git a/hid/pico/src/ph_usb.c b/hid/pico/src/ph_usb.c index fbca5e90..0358e724 100644 --- a/hid/pico/src/ph_usb.c +++ b/hid/pico/src/ph_usb.c @@ -62,13 +62,13 @@ 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) { + if (ph_g_is_bridge || 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) { + if (ph_g_is_bridge || PH_O_IS_KBD_USB || PH_O_IS_MOUSE_USB) { tud_task(); static u64 next_ts = 0; @@ -298,10 +298,31 @@ const u8 *tud_hid_descriptor_report_cb(u8 iface) { 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; +const u8 *_bridge_tud_descriptor_configuration_cb(void) { + enum {num_cdc = 0, num_cdc_data, num_total}; + static const u8 desc[] = { + TUD_CONFIG_DESCRIPTOR( + 1, // Config number + num_total,// Interface count + 0, // String index + (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN), // Total length + 0, // Attribute + 100 // Power in mA + ), + TUD_CDC_DESCRIPTOR( + num_cdc,// Interface number + 4, // String index + 0x81, // EPNUM_CDC_NOTIF - EP notification address + 8, // EP notification size + 0x02, // EPNUM_CDC_OUT - EP OUT data address + 0x82, // EPNUM_CDC_IN - EP IN data address + 64 // EP size + ), + }; + return desc; +} +const u8 *_hid_tud_descriptor_configuration_cb(void) { static u8 desc[TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN * 2] = {0}; static bool filled = false; @@ -338,10 +359,18 @@ const u8 *tud_descriptor_configuration_cb(u8 index) { return desc; } +const u8 *tud_descriptor_configuration_cb(u8 index) { + // Invoked when received GET CONFIGURATION DESCRIPTOR + (void)index; + if (ph_g_is_bridge) { + return _bridge_tud_descriptor_configuration_cb(); + } + return _hid_tud_descriptor_configuration_cb(); +} + const u8 *tud_descriptor_device_cb(void) { // Invoked when received GET DEVICE DESCRIPTOR - - static const tusb_desc_device_t desc = { + static tusb_desc_device_t desc = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, .bcdUSB = 0x0200, @@ -362,6 +391,12 @@ const u8 *tud_descriptor_device_cb(void) { .bNumConfigurations = 1, }; + if (ph_g_is_bridge) { + desc.bDeviceClass = TUSB_CLASS_MISC; + desc.bDeviceSubClass = MISC_SUBCLASS_COMMON; + desc.bDeviceProtocol = MISC_PROTOCOL_IAD; + desc.idProduct = 0xEDA3; + } return (const u8 *)&desc; } @@ -379,8 +414,15 @@ const u16 *tud_descriptor_string_cb(u8 index, u16 lang_id) { char str[32]; switch (index) { case 1: strcpy(str, "PiKVM"); break; // Manufacturer - case 2: strcpy(str, "PiKVM HID"); break; // Product + case 2: strcpy(str, (ph_g_is_bridge ? "PiKVM HID Bridge" : "PiKVM HID")); break; // Product case 3: pico_get_unique_board_id_string(str, 32); break; // Serial + case 4: { + if (ph_g_is_bridge) { + strcpy(str, "PiKVM HID Bridge CDC"); + } else { + return NULL; + } + }; break; default: return NULL; } desc_str_len = strlen(str); diff --git a/hid/pico/src/tusb_config.h b/hid/pico/src/tusb_config.h index c29b23ad..dae732a8 100644 --- a/hid/pico/src/tusb_config.h +++ b/hid/pico/src/tusb_config.h @@ -59,9 +59,21 @@ # define CFG_TUD_ENDPOINT0_SIZE 64 #endif +// HID: Keyboard + Mouse #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 + + +// CDC for the bridge mode +#define CFG_TUD_CDC 1 + +// CDC FIFO size of TX and RX +#define CFG_TUD_CDC_RX_BUFSIZE 4096 +#define CFG_TUD_CDC_TX_BUFSIZE 4096 + +// CDC Endpoint transfer buffer size, more is faster +#define CFG_TUD_CDC_EP_BUFSIZE 64 |