summaryrefslogtreecommitdiff
path: root/hid
diff options
context:
space:
mode:
authorMaxim Devaev <[email protected]>2023-08-25 12:35:28 +0300
committerMaxim Devaev <[email protected]>2023-08-25 12:35:28 +0300
commit21eddbde1c11961d7fb958422d6dd72b94c33375 (patch)
tree2a869d17932914a4481e6356dc78ab8690cd872c /hid
parent82ca2b1caed602030d2d849a9e61748ea7249ac9 (diff)
pico hid bridge mode
Diffstat (limited to 'hid')
-rw-r--r--hid/pico/src/CMakeLists.txt1
-rw-r--r--hid/pico/src/main.c2
-rw-r--r--hid/pico/src/ph_com.c32
-rw-r--r--hid/pico/src/ph_com_bridge.c84
-rw-r--r--hid/pico/src/ph_com_bridge.h30
-rw-r--r--hid/pico/src/ph_outputs.c9
-rw-r--r--hid/pico/src/ph_outputs.h1
-rw-r--r--hid/pico/src/ph_usb.c58
-rw-r--r--hid/pico/src/tusb_config.h12
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