Lib compiling.
This commit is contained in:
parent
156db4ba59
commit
8c387da066
|
|
@ -1,2 +1 @@
|
||||||
.vscode/ccls-cache
|
|
||||||
build
|
build
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
"${env:PICO_SDK_PATH}/src/**/include/",
|
"${env:PICO_SDK_PATH}/src/**/include/",
|
||||||
"${env:PICO_SDK_PATH}/lib/**/include/",
|
"${env:PICO_SDK_PATH}/lib/**/include/",
|
||||||
"${env:PICO_SDK_PATH}/lib/**/src/",
|
"${env:PICO_SDK_PATH}/lib/**/src/",
|
||||||
|
"${env:PICO_SDK_PATH}/lib/tinyusb/hw",
|
||||||
"${workspaceFolder}/build/generated/pico_base/",
|
"${workspaceFolder}/build/generated/pico_base/",
|
||||||
"${workspaceFolder}/src/",
|
"${workspaceFolder}/src/",
|
||||||
"${workspaceFolder}/lib/**/"
|
"${workspaceFolder}/lib/**/"
|
||||||
|
|
@ -19,7 +20,10 @@
|
||||||
],
|
],
|
||||||
"limitSymbolsToIncludedHeaders": true,
|
"limitSymbolsToIncludedHeaders": true,
|
||||||
"databaseFilename": ""
|
"databaseFilename": ""
|
||||||
}
|
},
|
||||||
|
"defines": [
|
||||||
|
"CFG_TUSB_MCU=OPT_MCU_RP2040"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version": 4
|
"version": 4
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Flash Access Point",
|
"label": "Flash Host",
|
||||||
"detail": "Build and flash access point",
|
"detail": "Build and flash USB host",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"Configure"
|
"Configure"
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
"-C",
|
"-C",
|
||||||
"build",
|
"build",
|
||||||
"-j$(nproc)",
|
"-j$(nproc)",
|
||||||
"Flash_Access_Point"
|
"Flash_Host"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"presentation": {
|
"presentation": {
|
||||||
|
|
@ -68,8 +68,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Flash Station",
|
"label": "Flash Device",
|
||||||
"detail": "Build and flash station",
|
"detail": "Build and flash USB device",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"Configure"
|
"Configure"
|
||||||
|
|
@ -79,7 +79,7 @@
|
||||||
"-C",
|
"-C",
|
||||||
"build",
|
"build",
|
||||||
"-j$(nproc)",
|
"-j$(nproc)",
|
||||||
"Flash_Station"
|
"Flash_Device"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"presentation": {
|
"presentation": {
|
||||||
|
|
|
||||||
|
|
@ -15,40 +15,41 @@ set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
pico_sdk_init()
|
pico_sdk_init()
|
||||||
|
|
||||||
# Executables and sources
|
# Executables
|
||||||
add_executable(Pico_Host
|
add_executable(Pico_Host)
|
||||||
|
add_executable(Pico_Device)
|
||||||
|
|
||||||
|
target_sources(Pico_Host PUBLIC
|
||||||
src/main_host.c
|
src/main_host.c
|
||||||
|
src/cdc_app.c
|
||||||
|
src/hid_app.c
|
||||||
|
src/msc_app.c
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(Pico_Device
|
target_sources(Pico_Device PUBLIC
|
||||||
src/main_device.c
|
src/main_device.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Libs
|
target_include_directories(Pico_Host PUBLIC
|
||||||
add_subdirectory(lib/Pico_USB_Host)
|
${CMAKE_CURRENT_LIST_DIR}/src/
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(Pico_Host
|
target_link_libraries(Pico_Host
|
||||||
pico_stdlib
|
pico_stdlib
|
||||||
Pico_USB_Host
|
tinyusb_board
|
||||||
|
tinyusb_host
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(Pico_Device
|
target_link_libraries(Pico_Device
|
||||||
pico_stdlib
|
pico_stdlib
|
||||||
)
|
)
|
||||||
|
|
||||||
# Stdio configuration
|
|
||||||
pico_enable_stdio_usb(Pico_Host 1)
|
|
||||||
pico_enable_stdio_uart(Pico_Host 1)
|
|
||||||
|
|
||||||
pico_enable_stdio_usb(Pico_Device 1)
|
|
||||||
pico_enable_stdio_uart(Pico_Device 1)
|
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
pico_add_extra_outputs(Pico_Host)
|
pico_add_extra_outputs(Pico_Host)
|
||||||
pico_add_extra_outputs(Pico_Device)
|
pico_add_extra_outputs(Pico_Device)
|
||||||
|
|
||||||
# Flash target
|
# Flash target
|
||||||
add_custom_target(Flash_host
|
add_custom_target(Flash_Host
|
||||||
DEPENDS Pico_Host
|
DEPENDS Pico_Host
|
||||||
COMMAND picotool load -f ${PROJECT_BINARY_DIR}/Pico_Host.uf2
|
COMMAND picotool load -f ${PROJECT_BINARY_DIR}/Pico_Host.uf2
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit adffbe805b938541659b6fa4688a5665ddbc5b9e
|
Subproject commit 6e3be14cfbe61df4d9a90333765710f8ef711153
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022, Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* This file is part of the TinyUSB stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "bsp/board_api.h"
|
||||||
|
|
||||||
|
size_t get_console_inputs(uint8_t* buf, size_t bufsize) {
|
||||||
|
size_t count = 0;
|
||||||
|
while (count < bufsize) {
|
||||||
|
int ch = board_getchar();
|
||||||
|
if (ch <= 0) break;
|
||||||
|
|
||||||
|
buf[count] = (uint8_t) ch;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cdc_app_task(void) {
|
||||||
|
uint8_t buf[64 + 1]; // +1 for extra null character
|
||||||
|
uint32_t const bufsize = sizeof(buf) - 1;
|
||||||
|
|
||||||
|
uint32_t count = get_console_inputs(buf, bufsize);
|
||||||
|
buf[count] = 0;
|
||||||
|
|
||||||
|
// loop over all mounted interfaces
|
||||||
|
for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) {
|
||||||
|
if (tuh_cdc_mounted(idx)) {
|
||||||
|
// console --> cdc interfaces
|
||||||
|
if (count) {
|
||||||
|
tuh_cdc_write(idx, buf, count);
|
||||||
|
tuh_cdc_write_flush(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// Invoked when received new data
|
||||||
|
void tuh_cdc_rx_cb(uint8_t idx) {
|
||||||
|
uint8_t buf[64 + 1]; // +1 for extra null character
|
||||||
|
uint32_t const bufsize = sizeof(buf) - 1;
|
||||||
|
|
||||||
|
// forward cdc interfaces -> console
|
||||||
|
uint32_t count = tuh_cdc_read(idx, buf, bufsize);
|
||||||
|
buf[count] = 0;
|
||||||
|
|
||||||
|
printf("%s", (char*) buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when a device with CDC interface is mounted
|
||||||
|
// idx is index of cdc interface in the internal pool.
|
||||||
|
void tuh_cdc_mount_cb(uint8_t idx) {
|
||||||
|
tuh_itf_info_t itf_info = {0};
|
||||||
|
tuh_cdc_itf_get_info(idx, &itf_info);
|
||||||
|
|
||||||
|
printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr,
|
||||||
|
itf_info.desc.bInterfaceNumber);
|
||||||
|
|
||||||
|
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
|
||||||
|
// If CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined, line coding will be set by tinyusb stack
|
||||||
|
// while eneumerating new cdc device
|
||||||
|
cdc_line_coding_t line_coding = {0};
|
||||||
|
if (tuh_cdc_get_local_line_coding(idx, &line_coding)) {
|
||||||
|
printf(" Baudrate: %" PRIu32 ", Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits);
|
||||||
|
printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Set Line Coding upon mounted
|
||||||
|
cdc_line_coding_t new_line_coding = { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 };
|
||||||
|
tuh_cdc_set_line_coding(idx, &new_line_coding, NULL, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when a device with CDC interface is unmounted
|
||||||
|
void tuh_cdc_umount_cb(uint8_t idx) {
|
||||||
|
tuh_itf_info_t itf_info = {0};
|
||||||
|
tuh_cdc_itf_get_info(idx, &itf_info);
|
||||||
|
|
||||||
|
printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr,
|
||||||
|
itf_info.desc.bInterfaceNumber);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,298 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021, Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bsp/board_api.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// If your host terminal support ansi escape code such as TeraTerm
|
||||||
|
// it can be use to simulate mouse cursor movement within terminal
|
||||||
|
#define USE_ANSI_ESCAPE 0
|
||||||
|
|
||||||
|
#define MAX_REPORT 4
|
||||||
|
|
||||||
|
static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII };
|
||||||
|
|
||||||
|
// Each HID instance can has multiple reports
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
uint8_t report_count;
|
||||||
|
tuh_hid_report_info_t report_info[MAX_REPORT];
|
||||||
|
}hid_info[CFG_TUH_HID];
|
||||||
|
|
||||||
|
static void process_kbd_report(hid_keyboard_report_t const *report);
|
||||||
|
static void process_mouse_report(hid_mouse_report_t const * report);
|
||||||
|
static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
|
||||||
|
|
||||||
|
void hid_app_task(void)
|
||||||
|
{
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// Invoked when device with hid interface is mounted
|
||||||
|
// Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
|
||||||
|
// can be used to parse common/simple enough descriptor.
|
||||||
|
// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
|
||||||
|
// therefore report_desc = NULL, desc_len = 0
|
||||||
|
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
|
||||||
|
{
|
||||||
|
printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
|
||||||
|
|
||||||
|
// Interface protocol (hid_interface_protocol_enum_t)
|
||||||
|
const char* protocol_str[] = { "None", "Keyboard", "Mouse" };
|
||||||
|
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||||
|
|
||||||
|
printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]);
|
||||||
|
|
||||||
|
// By default host stack will use activate boot protocol on supported interface.
|
||||||
|
// Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser)
|
||||||
|
if ( itf_protocol == HID_ITF_PROTOCOL_NONE )
|
||||||
|
{
|
||||||
|
hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len);
|
||||||
|
printf("HID has %u reports \r\n", hid_info[instance].report_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// request to receive report
|
||||||
|
// tuh_hid_report_received_cb() will be invoked when report is available
|
||||||
|
if ( !tuh_hid_receive_report(dev_addr, instance) )
|
||||||
|
{
|
||||||
|
printf("Error: cannot request to receive report\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when device with hid interface is un-mounted
|
||||||
|
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
|
||||||
|
{
|
||||||
|
printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when received report from device via interrupt endpoint
|
||||||
|
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||||
|
|
||||||
|
switch (itf_protocol)
|
||||||
|
{
|
||||||
|
case HID_ITF_PROTOCOL_KEYBOARD:
|
||||||
|
TU_LOG2("HID receive boot keyboard report\r\n");
|
||||||
|
process_kbd_report( (hid_keyboard_report_t const*) report );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HID_ITF_PROTOCOL_MOUSE:
|
||||||
|
TU_LOG2("HID receive boot mouse report\r\n");
|
||||||
|
process_mouse_report( (hid_mouse_report_t const*) report );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Generic report requires matching ReportID and contents with previous parsed report info
|
||||||
|
process_generic_report(dev_addr, instance, report, len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// continue to request to receive report
|
||||||
|
if ( !tuh_hid_receive_report(dev_addr, instance) )
|
||||||
|
{
|
||||||
|
printf("Error: cannot request to receive report\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Keyboard
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// look up new key in previous keys
|
||||||
|
static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8_t keycode)
|
||||||
|
{
|
||||||
|
for(uint8_t i=0; i<6; i++)
|
||||||
|
{
|
||||||
|
if (report->keycode[i] == keycode) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_kbd_report(hid_keyboard_report_t const *report)
|
||||||
|
{
|
||||||
|
static hid_keyboard_report_t prev_report = { 0, 0, {0} }; // previous report to check key released
|
||||||
|
|
||||||
|
//------------- example code ignore control (non-printable) key affects -------------//
|
||||||
|
for(uint8_t i=0; i<6; i++)
|
||||||
|
{
|
||||||
|
if ( report->keycode[i] )
|
||||||
|
{
|
||||||
|
if ( find_key_in_report(&prev_report, report->keycode[i]) )
|
||||||
|
{
|
||||||
|
// exist in previous report means the current key is holding
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
// not existed in previous report means the current key is pressed
|
||||||
|
bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
|
||||||
|
uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0];
|
||||||
|
putchar(ch);
|
||||||
|
if ( ch == '\r' ) putchar('\n'); // added new line for enter key
|
||||||
|
|
||||||
|
#ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
|
||||||
|
fflush(stdout); // flush right away, else nanolib will wait for newline
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO example skips key released
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_report = *report;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Mouse
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
void cursor_movement(int8_t x, int8_t y, int8_t wheel)
|
||||||
|
{
|
||||||
|
#if USE_ANSI_ESCAPE
|
||||||
|
// Move X using ansi escape
|
||||||
|
if ( x < 0)
|
||||||
|
{
|
||||||
|
printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left
|
||||||
|
}else if ( x > 0)
|
||||||
|
{
|
||||||
|
printf(ANSI_CURSOR_FORWARD(%d), x); // move right
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move Y using ansi escape
|
||||||
|
if ( y < 0)
|
||||||
|
{
|
||||||
|
printf(ANSI_CURSOR_UP(%d), (-y)); // move up
|
||||||
|
}else if ( y > 0)
|
||||||
|
{
|
||||||
|
printf(ANSI_CURSOR_DOWN(%d), y); // move down
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll using ansi escape
|
||||||
|
if (wheel < 0)
|
||||||
|
{
|
||||||
|
printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up
|
||||||
|
}else if (wheel > 0)
|
||||||
|
{
|
||||||
|
printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\r\n");
|
||||||
|
#else
|
||||||
|
printf("(%d %d %d)\r\n", x, y, wheel);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_mouse_report(hid_mouse_report_t const * report)
|
||||||
|
{
|
||||||
|
static hid_mouse_report_t prev_report = { 0 };
|
||||||
|
|
||||||
|
//------------- button state -------------//
|
||||||
|
uint8_t button_changed_mask = report->buttons ^ prev_report.buttons;
|
||||||
|
if ( button_changed_mask & report->buttons)
|
||||||
|
{
|
||||||
|
printf(" %c%c%c ",
|
||||||
|
report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-',
|
||||||
|
report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-',
|
||||||
|
report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- cursor movement -------------//
|
||||||
|
cursor_movement(report->x, report->y, report->wheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Generic Report
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
|
||||||
|
{
|
||||||
|
(void) dev_addr;
|
||||||
|
|
||||||
|
uint8_t const rpt_count = hid_info[instance].report_count;
|
||||||
|
tuh_hid_report_info_t* rpt_info_arr = hid_info[instance].report_info;
|
||||||
|
tuh_hid_report_info_t* rpt_info = NULL;
|
||||||
|
|
||||||
|
if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0)
|
||||||
|
{
|
||||||
|
// Simple report without report ID as 1st byte
|
||||||
|
rpt_info = &rpt_info_arr[0];
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
// Composite report, 1st byte is report ID, data starts from 2nd byte
|
||||||
|
uint8_t const rpt_id = report[0];
|
||||||
|
|
||||||
|
// Find report id in the array
|
||||||
|
for(uint8_t i=0; i<rpt_count; i++)
|
||||||
|
{
|
||||||
|
if (rpt_id == rpt_info_arr[i].report_id )
|
||||||
|
{
|
||||||
|
rpt_info = &rpt_info_arr[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
report++;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rpt_info)
|
||||||
|
{
|
||||||
|
printf("Couldn't find report info !\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For complete list of Usage Page & Usage checkout src/class/hid/hid.h. For examples:
|
||||||
|
// - Keyboard : Desktop, Keyboard
|
||||||
|
// - Mouse : Desktop, Mouse
|
||||||
|
// - Gamepad : Desktop, Gamepad
|
||||||
|
// - Consumer Control (Media Key) : Consumer, Consumer Control
|
||||||
|
// - System Control (Power key) : Desktop, System Control
|
||||||
|
// - Generic (vendor) : 0xFFxx, xx
|
||||||
|
if ( rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP )
|
||||||
|
{
|
||||||
|
switch (rpt_info->usage)
|
||||||
|
{
|
||||||
|
case HID_USAGE_DESKTOP_KEYBOARD:
|
||||||
|
TU_LOG1("HID receive keyboard report\r\n");
|
||||||
|
// Assume keyboard follow boot report layout
|
||||||
|
process_kbd_report( (hid_keyboard_report_t const*) report );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HID_USAGE_DESKTOP_MOUSE:
|
||||||
|
TU_LOG1("HID receive mouse report\r\n");
|
||||||
|
// Assume mouse follow boot report layout
|
||||||
|
process_mouse_report( (hid_mouse_report_t const*) report );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <pico/stdlib.h>
|
#include <pico/stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
|
@ -19,6 +20,8 @@ int main(void)
|
||||||
led_state = !led_state;
|
led_state = !led_state;
|
||||||
|
|
||||||
gpio_put(PICO_DEFAULT_LED_PIN, led_state);
|
gpio_put(PICO_DEFAULT_LED_PIN, led_state);
|
||||||
|
|
||||||
|
printf("led_state : %d\n", led_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
tight_loop_contents();
|
tight_loop_contents();
|
||||||
|
|
|
||||||
119
src/main_host.c
119
src/main_host.c
|
|
@ -1,24 +1,111 @@
|
||||||
#include <pico/stdlib.h>
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
int main(void)
|
#include <stdlib.h>
|
||||||
{
|
#include <stdio.h>
|
||||||
stdio_init_all();
|
#include <string.h>
|
||||||
|
#include <bsp/board_api.h>
|
||||||
|
#include <tusb.h>
|
||||||
|
#include "tusb_config.h"
|
||||||
|
|
||||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
//--------------------------------------------------------------------+
|
||||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
// MACRO CONSTANT TYPEDEF PROTYPES
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void led_blinking_task(void);
|
||||||
|
extern void cdc_app_task(void);
|
||||||
|
extern void hid_app_task(void);
|
||||||
|
|
||||||
for(int i = 0; i < 3; i++)
|
#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
|
||||||
{
|
// API to read/rite MAX3421's register. Implemented by TinyUSB
|
||||||
gpio_put(PICO_DEFAULT_LED_PIN, false);
|
extern uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr);
|
||||||
sleep_ms(100);
|
extern bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr);
|
||||||
gpio_put(PICO_DEFAULT_LED_PIN, true);
|
#endif
|
||||||
sleep_ms(100);
|
|
||||||
|
/*------------- MAIN -------------*/
|
||||||
|
int main(void) {
|
||||||
|
board_init();
|
||||||
|
|
||||||
|
printf("TinyUSB Host CDC MSC HID Example\r\n");
|
||||||
|
|
||||||
|
// init host stack on configured roothub port
|
||||||
|
const tusb_rhport_init_t rh_init = {
|
||||||
|
.role = TUSB_ROLE_HOST,
|
||||||
|
.speed = TUH_OPT_HIGH_SPEED ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL,
|
||||||
|
};
|
||||||
|
TU_ASSERT(tuh_rhport_init(BOARD_TUH_RHPORT, &rh_init));
|
||||||
|
|
||||||
|
board_init_after_tusb();
|
||||||
|
|
||||||
|
#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
|
||||||
|
// FeatherWing MAX3421E use MAX3421E's GPIO0 for VBUS enable
|
||||||
|
enum { IOPINS1_ADDR = 20u << 3, /* 0xA0 */ };
|
||||||
|
tuh_max3421_reg_write(BOARD_TUH_RHPORT, IOPINS1_ADDR, 0x01, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// tinyusb host task
|
||||||
|
tuh_task();
|
||||||
|
|
||||||
|
led_blinking_task();
|
||||||
|
cdc_app_task();
|
||||||
|
hid_app_task();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while(true)
|
//--------------------------------------------------------------------+
|
||||||
{
|
// TinyUSB Callbacks
|
||||||
tight_loop_contents();
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
void tuh_mount_cb(uint8_t dev_addr) {
|
||||||
|
// application set-up
|
||||||
|
printf("A device with address %d is mounted\r\n", dev_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return PICO_OK;
|
void tuh_umount_cb(uint8_t dev_addr) {
|
||||||
|
// application tear-down
|
||||||
|
printf("A device with address %d is unmounted \r\n", dev_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TUSB_VERSION_NUMBER > 1800
|
||||||
|
// board_millis has been removed from tinyusb. Use tusb_time_millis_api instead
|
||||||
|
#define board_millis tusb_time_millis_api
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Blinking Task
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void led_blinking_task(void) {
|
||||||
|
const uint32_t interval_ms = 1000;
|
||||||
|
static uint32_t start_ms = 0;
|
||||||
|
|
||||||
|
static bool led_state = false;
|
||||||
|
|
||||||
|
// Blink every interval ms
|
||||||
|
if (board_millis() - start_ms < interval_ms) return; // not enough time
|
||||||
|
start_ms += interval_ms;
|
||||||
|
|
||||||
|
board_led_write(led_state);
|
||||||
|
led_state = 1 - led_state; // toggle
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
static scsi_inquiry_resp_t inquiry_resp;
|
||||||
|
|
||||||
|
bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
|
||||||
|
{
|
||||||
|
msc_cbw_t const* cbw = cb_data->cbw;
|
||||||
|
msc_csw_t const* csw = cb_data->csw;
|
||||||
|
|
||||||
|
if (csw->status != 0)
|
||||||
|
{
|
||||||
|
printf("Inquiry failed\r\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print out Vendor ID, Product ID and Rev
|
||||||
|
printf("%.8s %.16s rev %.4s\r\n", inquiry_resp.vendor_id, inquiry_resp.product_id, inquiry_resp.product_rev);
|
||||||
|
|
||||||
|
// Get capacity of device
|
||||||
|
uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun);
|
||||||
|
uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun);
|
||||||
|
|
||||||
|
printf("Disk Size: %" PRIu32 " MB\r\n", block_count / ((1024*1024)/block_size));
|
||||||
|
printf("Block Count = %" PRIu32 ", Block Size: %" PRIu32 "\r\n", block_count, block_size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- IMPLEMENTATION -------------//
|
||||||
|
void tuh_msc_mount_cb(uint8_t dev_addr)
|
||||||
|
{
|
||||||
|
printf("A MassStorage device is mounted\r\n");
|
||||||
|
|
||||||
|
uint8_t const lun = 0;
|
||||||
|
tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tuh_msc_umount_cb(uint8_t dev_addr)
|
||||||
|
{
|
||||||
|
(void) dev_addr;
|
||||||
|
printf("A MassStorage device is unmounted\r\n");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TUSB_CONFIG_H_
|
||||||
|
#define _TUSB_CONFIG_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// Common Configuration
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
// defined by compiler flags for flexibility
|
||||||
|
#ifndef CFG_TUSB_MCU
|
||||||
|
#error CFG_TUSB_MCU must be defined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUSB_OS
|
||||||
|
#define CFG_TUSB_OS OPT_OS_NONE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUSB_DEBUG
|
||||||
|
#define CFG_TUSB_DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
* e.g
|
||||||
|
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||||
|
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||||
|
*/
|
||||||
|
#ifndef CFG_TUH_MEM_SECTION
|
||||||
|
#define CFG_TUH_MEM_SECTION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUH_MEM_ALIGN
|
||||||
|
#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// Host Configuration
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Enable Host stack
|
||||||
|
#define CFG_TUH_ENABLED 1
|
||||||
|
|
||||||
|
#if CFG_TUSB_MCU == OPT_MCU_RP2040
|
||||||
|
// #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller
|
||||||
|
// #define CFG_TUH_MAX3421 1 // use max3421 as host controller
|
||||||
|
|
||||||
|
// host roothub port is 1 if using either pio-usb or max3421
|
||||||
|
#if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)
|
||||||
|
#define BOARD_TUH_RHPORT 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Default is max speed that hardware controller could support with on-chip PHY
|
||||||
|
#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
|
||||||
|
|
||||||
|
//------------------------- Board Specific --------------------------
|
||||||
|
|
||||||
|
// RHPort number used for host can be defined by board.mk, default to port 0
|
||||||
|
#ifndef BOARD_TUH_RHPORT
|
||||||
|
#define BOARD_TUH_RHPORT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RHPort max operational speed can defined by board.mk
|
||||||
|
#ifndef BOARD_TUH_MAX_SPEED
|
||||||
|
#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// Driver Configuration
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Size of buffer to hold descriptors and other data used for enumeration
|
||||||
|
#define CFG_TUH_ENUMERATION_BUFSIZE 256
|
||||||
|
|
||||||
|
#define CFG_TUH_HUB 1 // number of supported hubs
|
||||||
|
#define CFG_TUH_CDC 1 // CDC ACM
|
||||||
|
#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
|
||||||
|
#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
|
||||||
|
#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API
|
||||||
|
#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
|
||||||
|
#define CFG_TUH_MSC 1
|
||||||
|
#define CFG_TUH_VENDOR 0
|
||||||
|
|
||||||
|
// max device support (excluding hub device): 1 hub typically has 4 ports
|
||||||
|
#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
|
||||||
|
|
||||||
|
//------------- HID -------------//
|
||||||
|
#define CFG_TUH_HID_EPIN_BUFSIZE 64
|
||||||
|
#define CFG_TUH_HID_EPOUT_BUFSIZE 64
|
||||||
|
|
||||||
|
//------------- CDC -------------//
|
||||||
|
|
||||||
|
// Set Line Control state on enumeration/mounted:
|
||||||
|
// DTR ( bit 0), RTS (bit 1)
|
||||||
|
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
|
||||||
|
|
||||||
|
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
|
||||||
|
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
|
||||||
|
#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _TUSB_CONFIG_H_ */
|
||||||
Loading…
Reference in New Issue