Starting to have functionnal host and device using tu.
This commit is contained in:
parent
8c387da066
commit
1ea377684b
|
|
@ -3,27 +3,13 @@
|
||||||
{
|
{
|
||||||
"name": "Linux",
|
"name": "Linux",
|
||||||
"intelliSenseMode": "linux-gcc-arm",
|
"intelliSenseMode": "linux-gcc-arm",
|
||||||
"includePath": [
|
|
||||||
"${env:PICO_SDK_PATH}/src/**/include/",
|
|
||||||
"${env:PICO_SDK_PATH}/lib/**/include/",
|
|
||||||
"${env:PICO_SDK_PATH}/lib/**/src/",
|
|
||||||
"${env:PICO_SDK_PATH}/lib/tinyusb/hw",
|
|
||||||
"${workspaceFolder}/build/generated/pico_base/",
|
|
||||||
"${workspaceFolder}/src/",
|
|
||||||
"${workspaceFolder}/lib/**/"
|
|
||||||
],
|
|
||||||
"compilerPath": "/usr/bin/arm-none-eabi-gcc",
|
|
||||||
"cStandard": "c17",
|
|
||||||
"browse": {
|
"browse": {
|
||||||
"path": [
|
"path": [
|
||||||
"${workspaceFolder}"
|
"${workspaceFolder}"
|
||||||
],
|
],
|
||||||
"limitSymbolsToIncludedHeaders": true,
|
"limitSymbolsToIncludedHeaders": true
|
||||||
"databaseFilename": ""
|
|
||||||
},
|
},
|
||||||
"defines": [
|
"compileCommands": "build/compile_commands.json"
|
||||||
"CFG_TUSB_MCU=OPT_MCU_RP2040"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version": 4
|
"version": 4
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
"command": "cmake",
|
"command": "cmake",
|
||||||
"args": [
|
"args": [
|
||||||
"-H.",
|
"-H.",
|
||||||
"-Bbuild"
|
"-Bbuild",
|
||||||
|
"-DCMAKE_EXPORT_COMPILE_COMMANDS=1"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"presentation": {
|
"presentation": {
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,6 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
# Explicitely define board
|
# Explicitely define board
|
||||||
set(PICO_BOARD pico)
|
set(PICO_BOARD pico)
|
||||||
if(NOT DEFINED PICO_BOARD)
|
|
||||||
add_definitions(-DPICO_BOARD=${PICO_BOARD})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Include pico-sdk cmake support
|
# Include pico-sdk cmake support
|
||||||
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
|
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
|
||||||
|
|
@ -19,21 +16,37 @@ pico_sdk_init()
|
||||||
add_executable(Pico_Host)
|
add_executable(Pico_Host)
|
||||||
add_executable(Pico_Device)
|
add_executable(Pico_Device)
|
||||||
|
|
||||||
|
# Sources
|
||||||
target_sources(Pico_Host PUBLIC
|
target_sources(Pico_Host PUBLIC
|
||||||
src/main_host.c
|
src_host/main.c
|
||||||
src/cdc_app.c
|
src_host/cdc_app.c
|
||||||
src/hid_app.c
|
|
||||||
src/msc_app.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_sources(Pico_Device PUBLIC
|
target_sources(Pico_Device PUBLIC
|
||||||
src/main_device.c
|
src_device/main.c
|
||||||
|
src_device/usb_descriptor.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Flags
|
||||||
|
# Enable the reset interface
|
||||||
|
target_compile_definitions(Pico_Device PUBLIC
|
||||||
|
PICO_ENABLE_USB_RESET_VIA_VENDOR_INTERFACE=1
|
||||||
|
# use SDK MS_OS_20 descriptor, as this doesn't have a custom one
|
||||||
|
PICO_USB_RESET_SUPPORT_MS_OS_20_DESCRIPTOR=1
|
||||||
|
# pass the interface number to the SDK MS_OS_20 descriptor
|
||||||
|
PICO_USB_RESET_MS_OS_20_DESCRIPTOR_ITF=4
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include paths
|
||||||
target_include_directories(Pico_Host PUBLIC
|
target_include_directories(Pico_Host PUBLIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/
|
${CMAKE_CURRENT_LIST_DIR}/src_host/
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_include_directories(Pico_Device PUBLIC
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src_device/
|
||||||
|
)
|
||||||
|
|
||||||
|
# Libs
|
||||||
target_link_libraries(Pico_Host
|
target_link_libraries(Pico_Host
|
||||||
pico_stdlib
|
pico_stdlib
|
||||||
tinyusb_board
|
tinyusb_board
|
||||||
|
|
@ -42,13 +55,17 @@ target_link_libraries(Pico_Host
|
||||||
|
|
||||||
target_link_libraries(Pico_Device
|
target_link_libraries(Pico_Device
|
||||||
pico_stdlib
|
pico_stdlib
|
||||||
|
tinyusb_board
|
||||||
|
tinyusb_device
|
||||||
)
|
)
|
||||||
|
|
||||||
# Output
|
pico_enable_stdio_usb(Pico_Device 1)
|
||||||
|
|
||||||
|
# Outputs
|
||||||
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 targets
|
||||||
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
|
||||||
|
|
|
||||||
298
src/hid_app.c
298
src/hid_app.c
|
|
@ -1,298 +0,0 @@
|
||||||
/*
|
|
||||||
* 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,31 +0,0 @@
|
||||||
#include <pico/stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
stdio_init_all();
|
|
||||||
|
|
||||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
|
||||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
|
||||||
|
|
||||||
while(true)
|
|
||||||
{
|
|
||||||
static uint64_t last_time = 0;
|
|
||||||
uint64_t time = time_us_64();
|
|
||||||
if(time - last_time > 1000 * 1000)
|
|
||||||
{
|
|
||||||
last_time = time;
|
|
||||||
|
|
||||||
static bool led_state = true;
|
|
||||||
led_state = !led_state;
|
|
||||||
|
|
||||||
gpio_put(PICO_DEFAULT_LED_PIN, led_state);
|
|
||||||
|
|
||||||
printf("led_state : %d\n", led_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
tight_loop_contents();
|
|
||||||
}
|
|
||||||
|
|
||||||
return PICO_OK;
|
|
||||||
}
|
|
||||||
111
src/main_host.c
111
src/main_host.c
|
|
@ -1,111 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <bsp/board_api.h>
|
|
||||||
#include <tusb.h>
|
|
||||||
#include "tusb_config.h"
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// MACRO CONSTANT TYPEDEF PROTYPES
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
void led_blinking_task(void);
|
|
||||||
extern void cdc_app_task(void);
|
|
||||||
extern void hid_app_task(void);
|
|
||||||
|
|
||||||
#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
|
|
||||||
// API to read/rite MAX3421's register. Implemented by TinyUSB
|
|
||||||
extern uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr);
|
|
||||||
extern bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*------------- 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// TinyUSB Callbacks
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
void tuh_mount_cb(uint8_t dev_addr) {
|
|
||||||
// application set-up
|
|
||||||
printf("A device with address %d is mounted\r\n", dev_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
/*
|
|
||||||
* 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,77 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <tusb.h>
|
||||||
|
#include <bsp/board.h>
|
||||||
|
#include <pico/stdio.h>
|
||||||
|
#include <pico/stdlib.h>
|
||||||
|
|
||||||
|
#define LED_BLINK_DELAY_MS 1000
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Initialize TinyUSB stack
|
||||||
|
board_init();
|
||||||
|
tusb_init();
|
||||||
|
|
||||||
|
// let pico sdk use the first cdc interface for std io
|
||||||
|
stdio_init_all();
|
||||||
|
|
||||||
|
uint32_t start_ms = 0;
|
||||||
|
bool led_state = false;
|
||||||
|
|
||||||
|
// main run loop
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// TinyUSB device task | must be called regurlarly
|
||||||
|
tud_task();
|
||||||
|
|
||||||
|
if(board_millis() - start_ms > LED_BLINK_DELAY_MS)
|
||||||
|
{
|
||||||
|
board_led_write(led_state);
|
||||||
|
led_state = ! led_state;
|
||||||
|
start_ms += LED_BLINK_DELAY_MS;
|
||||||
|
|
||||||
|
if(tud_cdc_n_connected(0))
|
||||||
|
{
|
||||||
|
printf("Connected to CDC 0\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tud_cdc_n_connected(1))
|
||||||
|
{
|
||||||
|
printf("Connected to CDC 1\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback when data is received on a CDC interface
|
||||||
|
void tud_cdc_rx_cb(uint8_t itf)
|
||||||
|
{
|
||||||
|
// allocate buffer for the data in the stack
|
||||||
|
uint8_t buf[CFG_TUD_CDC_RX_BUFSIZE];
|
||||||
|
|
||||||
|
printf("RX CDC %d\n", itf);
|
||||||
|
|
||||||
|
// read the available data
|
||||||
|
// | IMPORTANT: also do this for CDC0 because otherwise
|
||||||
|
// | you won't be able to print anymore to CDC0
|
||||||
|
// | next time this function is called
|
||||||
|
uint32_t count = tud_cdc_n_read(itf, buf, sizeof(buf));
|
||||||
|
|
||||||
|
// check if the data was received on the second cdc interface
|
||||||
|
if (itf == 1) {
|
||||||
|
// process the received data
|
||||||
|
buf[count] = 0; // null-terminate the string
|
||||||
|
// now echo data back to the console on CDC 0
|
||||||
|
printf("Received on CDC 1: %s\n", buf);
|
||||||
|
|
||||||
|
// and echo back OK on CDC 1
|
||||||
|
tud_cdc_n_write(itf, (uint8_t const *) "OK\r\n", 4);
|
||||||
|
tud_cdc_n_write_flush(itf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TUSB_CONFIG_H_
|
||||||
|
#define _TUSB_CONFIG_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CFG_TUD_ENABLED (1)
|
||||||
|
|
||||||
|
// Legacy RHPORT configuration
|
||||||
|
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED)
|
||||||
|
#ifndef BOARD_TUD_RHPORT
|
||||||
|
#define BOARD_TUD_RHPORT (0)
|
||||||
|
#endif
|
||||||
|
// end legacy RHPORT
|
||||||
|
|
||||||
|
//------------------------
|
||||||
|
// DEVICE CONFIGURATION //
|
||||||
|
//------------------------
|
||||||
|
|
||||||
|
// Enable 2 CDC classes
|
||||||
|
#define CFG_TUD_CDC (2)
|
||||||
|
// Set CDC FIFO buffer sizes
|
||||||
|
#define CFG_TUD_CDC_RX_BUFSIZE (64)
|
||||||
|
#define CFG_TUD_CDC_TX_BUFSIZE (64)
|
||||||
|
#define CFG_TUD_CDC_EP_BUFSIZE (64)
|
||||||
|
|
||||||
|
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||||
|
#define CFG_TUD_ENDPOINT0_SIZE (64)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _TUSB_CONFIG_H_ */
|
||||||
|
|
@ -0,0 +1,211 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <tusb.h>
|
||||||
|
#include <bsp/board_api.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "pico/usb_reset.h"
|
||||||
|
|
||||||
|
// set some example Vendor and Product ID
|
||||||
|
// the board will use to identify at the host
|
||||||
|
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
|
||||||
|
#define CDC_EXAMPLE_VID 0xCafe
|
||||||
|
// use _PID_MAP to generate unique PID for each interface
|
||||||
|
#define CDC_EXAMPLE_PID (0x4100 | _PID_MAP(CDC, 0))
|
||||||
|
// set to 2.10 so the MS_OS_20_DESCRIPTOR works
|
||||||
|
#define CDC_EXAMPLE_BCD 0x0210
|
||||||
|
|
||||||
|
// String descriptors referenced with .i... in the descriptor tables
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STRID_LANGID = 0, // 0: supported language ID
|
||||||
|
STRID_MANUFACTURER, // 1: Manufacturer
|
||||||
|
STRID_PRODUCT, // 2: Product
|
||||||
|
STRID_SERIAL, // 3: Serials
|
||||||
|
STRID_CDC_0, // 4: CDC Interface 0
|
||||||
|
STRID_CDC_1, // 5: CDC Interface 1
|
||||||
|
STRID_RPI_RESET, // 6: Reset Interface
|
||||||
|
};
|
||||||
|
|
||||||
|
// array of pointer to string descriptors
|
||||||
|
char const *string_desc_arr[] = {
|
||||||
|
// switched because board is little endian
|
||||||
|
(const char[]) { 0x09, 0x04 }, // 0: supported language is English (0x0409)
|
||||||
|
"Raspberry Pi", // 1: Manufacturer
|
||||||
|
"Pico (2)", // 2: Product
|
||||||
|
NULL, // 3: Serials (null so it uses unique ID if available)
|
||||||
|
"Pico SDK stdio", // 4: CDC Interface 0
|
||||||
|
"Custom CDC", // 5: CDC Interface 1,
|
||||||
|
"Reset" // 6: Reset Interface
|
||||||
|
};
|
||||||
|
|
||||||
|
// defines a descriptor that will be communicated to the host
|
||||||
|
tusb_desc_device_t const desc_device = {
|
||||||
|
.bLength = sizeof(tusb_desc_device_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||||
|
.bcdUSB = CDC_EXAMPLE_BCD,
|
||||||
|
|
||||||
|
.bDeviceClass = TUSB_CLASS_MISC, // CDC is a subclass of misc
|
||||||
|
.bDeviceSubClass = MISC_SUBCLASS_COMMON, // CDC uses common subclass
|
||||||
|
.bDeviceProtocol = MISC_PROTOCOL_IAD, // CDC uses IAD
|
||||||
|
|
||||||
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, // 64 bytes
|
||||||
|
|
||||||
|
.idVendor = CDC_EXAMPLE_VID,
|
||||||
|
.idProduct = CDC_EXAMPLE_PID,
|
||||||
|
.bcdDevice = 0x0100, // Device release number
|
||||||
|
|
||||||
|
.iManufacturer = STRID_MANUFACTURER, // Index of manufacturer string
|
||||||
|
.iProduct = STRID_PRODUCT, // Index of product string
|
||||||
|
.iSerialNumber = STRID_SERIAL, // Index of serial number string
|
||||||
|
|
||||||
|
.bNumConfigurations = 0x01 // 1 configuration
|
||||||
|
};
|
||||||
|
|
||||||
|
// called when host requests to get device descriptor
|
||||||
|
uint8_t const *tud_descriptor_device_cb(void);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ITF_NUM_CDC_0 = 0,
|
||||||
|
ITF_NUM_CDC_0_DATA,
|
||||||
|
ITF_NUM_CDC_1,
|
||||||
|
ITF_NUM_CDC_1_DATA,
|
||||||
|
ITF_NUM_RPI_RESET,
|
||||||
|
ITF_NUM_TOTAL
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(ITF_NUM_RPI_RESET == PICO_USB_RESET_MS_OS_20_DESCRIPTOR_ITF, "ITF_NUM_RPI_RESET must be equal to the PICO_USB_RESET_MS_OS_20_DESCRIPTOR_ITF set in CMakeLists.txt");
|
||||||
|
|
||||||
|
// total length of configuration descriptor
|
||||||
|
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN + TUD_RPI_RESET_DESC_LEN)
|
||||||
|
|
||||||
|
// define endpoint numbers
|
||||||
|
#define EPNUM_CDC_0_NOTIF 0x81 // notification endpoint for CDC 0
|
||||||
|
#define EPNUM_CDC_0_OUT 0x02 // out endpoint for CDC 0
|
||||||
|
#define EPNUM_CDC_0_IN 0x82 // in endpoint for CDC 0
|
||||||
|
|
||||||
|
#define EPNUM_CDC_1_NOTIF 0x84 // notification endpoint for CDC 1
|
||||||
|
#define EPNUM_CDC_1_OUT 0x05 // out endpoint for CDC 1
|
||||||
|
#define EPNUM_CDC_1_IN 0x85 // in endpoint for CDC 1
|
||||||
|
|
||||||
|
// configure descriptor (for 2 CDC interfaces)
|
||||||
|
uint8_t const desc_configuration[] = {
|
||||||
|
// config descriptor | how much power in mA, count of interfaces, ...
|
||||||
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x80, 100),
|
||||||
|
|
||||||
|
// CDC 0: Communication Interface - TODO: get 64 from tusb_config.h
|
||||||
|
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, STRID_CDC_0, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
|
||||||
|
// CDC 0: Data Interface
|
||||||
|
//TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0_DATA, 4, 0x01, 0x02),
|
||||||
|
|
||||||
|
// CDC 1: Communication Interface - TODO: get 64 from tusb_config.h
|
||||||
|
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, STRID_CDC_1, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
|
||||||
|
// CDC 1: Data Interface
|
||||||
|
//TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1_DATA, 4, 0x03, 0x04),
|
||||||
|
|
||||||
|
// RPi Reset Interface
|
||||||
|
TUD_RPI_RESET_DESCRIPTOR(ITF_NUM_RPI_RESET, STRID_RPI_RESET),
|
||||||
|
};
|
||||||
|
|
||||||
|
// called when host requests to get configuration descriptor
|
||||||
|
uint8_t const * tud_descriptor_configuration_cb(uint8_t index);
|
||||||
|
|
||||||
|
// more device descriptor this time the qualifier
|
||||||
|
tusb_desc_device_qualifier_t const desc_device_qualifier = {
|
||||||
|
.bLength = sizeof(tusb_desc_device_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||||
|
.bcdUSB = CDC_EXAMPLE_BCD,
|
||||||
|
|
||||||
|
.bDeviceClass = TUSB_CLASS_CDC,
|
||||||
|
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||||
|
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||||
|
|
||||||
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||||
|
.bNumConfigurations = 0x01,
|
||||||
|
.bReserved = 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
// called when host requests to get device qualifier descriptor
|
||||||
|
uint8_t const* tud_descriptor_device_qualifier_cb(void);
|
||||||
|
|
||||||
|
// buffer to hold the string descriptor during the request | plus 1 for the null terminator
|
||||||
|
static uint16_t _desc_str[32 + 1];
|
||||||
|
|
||||||
|
// called when host request to get string descriptor
|
||||||
|
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid);
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------+
|
||||||
|
// IMPLEMENTATION
|
||||||
|
// --------------------------------------------------------------------+
|
||||||
|
|
||||||
|
uint8_t const *tud_descriptor_device_cb(void)
|
||||||
|
{
|
||||||
|
return (uint8_t const *)&desc_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t const* tud_descriptor_device_qualifier_cb(void)
|
||||||
|
{
|
||||||
|
return (uint8_t const *)&desc_device_qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||||
|
{
|
||||||
|
// avoid unused parameter warning and keep function signature consistent
|
||||||
|
(void)index;
|
||||||
|
|
||||||
|
return desc_configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||||
|
{
|
||||||
|
// TODO: check lang id
|
||||||
|
(void) langid;
|
||||||
|
size_t char_count;
|
||||||
|
|
||||||
|
// Determine which string descriptor to return
|
||||||
|
switch (index) {
|
||||||
|
case STRID_LANGID:
|
||||||
|
memcpy(&_desc_str[1], string_desc_arr[STRID_LANGID], 2);
|
||||||
|
char_count = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STRID_SERIAL:
|
||||||
|
// try to read the serial from the board
|
||||||
|
char_count = board_usb_get_serial(_desc_str + 1, 32);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// COPYRIGHT NOTE: Based on TinyUSB example
|
||||||
|
// Windows wants utf16le
|
||||||
|
|
||||||
|
// Determine which string descriptor to return
|
||||||
|
if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy string descriptor into _desc_str
|
||||||
|
const char *str = string_desc_arr[index];
|
||||||
|
|
||||||
|
char_count = strlen(str);
|
||||||
|
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
|
||||||
|
// Cap at max char
|
||||||
|
if (char_count > max_count) {
|
||||||
|
char_count = max_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert ASCII string into UTF-16
|
||||||
|
for (size_t i = 0; i < char_count; i++) {
|
||||||
|
_desc_str[1 + i] = str[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First byte is the length (including header), second byte is string type
|
||||||
|
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (char_count * 2 + 2));
|
||||||
|
|
||||||
|
return _desc_str;
|
||||||
|
}
|
||||||
|
|
@ -24,11 +24,13 @@
|
||||||
* This file is part of the TinyUSB stack.
|
* This file is part of the TinyUSB stack.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tusb.h"
|
#include <tusb.h>
|
||||||
#include "bsp/board_api.h"
|
#include <bsp/board_api.h>
|
||||||
|
|
||||||
size_t get_console_inputs(uint8_t* buf, size_t bufsize) {
|
size_t get_console_inputs(uint8_t* buf, size_t bufsize)
|
||||||
|
{
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
while (count < bufsize) {
|
while (count < bufsize) {
|
||||||
int ch = board_getchar();
|
int ch = board_getchar();
|
||||||
if (ch <= 0) break;
|
if (ch <= 0) break;
|
||||||
|
|
@ -40,7 +42,8 @@ size_t get_console_inputs(uint8_t* buf, size_t bufsize) {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cdc_app_task(void) {
|
void cdc_app_task(void)
|
||||||
|
{
|
||||||
uint8_t buf[64 + 1]; // +1 for extra null character
|
uint8_t buf[64 + 1]; // +1 for extra null character
|
||||||
uint32_t const bufsize = sizeof(buf) - 1;
|
uint32_t const bufsize = sizeof(buf) - 1;
|
||||||
|
|
||||||
|
|
@ -48,10 +51,13 @@ void cdc_app_task(void) {
|
||||||
buf[count] = 0;
|
buf[count] = 0;
|
||||||
|
|
||||||
// loop over all mounted interfaces
|
// loop over all mounted interfaces
|
||||||
for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) {
|
for(uint8_t idx = 0; idx < CFG_TUH_CDC; idx++)
|
||||||
if (tuh_cdc_mounted(idx)) {
|
{
|
||||||
|
if(tuh_cdc_mounted(idx))
|
||||||
|
{
|
||||||
// console --> cdc interfaces
|
// console --> cdc interfaces
|
||||||
if (count) {
|
if(count)
|
||||||
|
{
|
||||||
tuh_cdc_write(idx, buf, count);
|
tuh_cdc_write(idx, buf, count);
|
||||||
tuh_cdc_write_flush(idx);
|
tuh_cdc_write_flush(idx);
|
||||||
}
|
}
|
||||||
|
|
@ -59,9 +65,7 @@ void cdc_app_task(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// TinyUSB callbacks
|
// TinyUSB callbacks
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
// Invoked when received new data
|
// Invoked when received new data
|
||||||
void tuh_cdc_rx_cb(uint8_t idx) {
|
void tuh_cdc_rx_cb(uint8_t idx) {
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <bsp/board_api.h>
|
||||||
|
#include <tusb.h>
|
||||||
|
#include <pico/stdlib.h>
|
||||||
|
|
||||||
|
#define LED_BLINK_DELAY_MS 1000
|
||||||
|
|
||||||
|
extern void cdc_app_task(void);
|
||||||
|
|
||||||
|
/*------------- MAIN -------------*/
|
||||||
|
int main(void) {
|
||||||
|
board_init();
|
||||||
|
|
||||||
|
gpio_set_function(12, UART_FUNCSEL_NUM(uart0, 12));
|
||||||
|
gpio_set_function(13, UART_FUNCSEL_NUM(uart0, 13));
|
||||||
|
|
||||||
|
printf("TinyUSB Host CDC Example\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,
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!tuh_rhport_init(BOARD_TUH_RHPORT, &rh_init))
|
||||||
|
{
|
||||||
|
printf("Failed to init rhport.\n");
|
||||||
|
return PICO_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t start_ms = 0;
|
||||||
|
bool led_state = false;
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// tinyusb host task
|
||||||
|
tuh_task();
|
||||||
|
|
||||||
|
if(board_millis() - start_ms > LED_BLINK_DELAY_MS)
|
||||||
|
{
|
||||||
|
board_led_write(led_state);
|
||||||
|
led_state = ! led_state;
|
||||||
|
start_ms += LED_BLINK_DELAY_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdc_app_task();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TinyUSB Callbacks
|
||||||
|
void tuh_mount_cb(uint8_t dev_addr) {
|
||||||
|
// application set-up
|
||||||
|
printf("A device with address %d is mounted\r\n", dev_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tuh_umount_cb(uint8_t dev_addr) {
|
||||||
|
// application tear-down
|
||||||
|
printf("A device with address %d is unmounted \r\n", dev_addr);
|
||||||
|
}
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#define _TUSB_CONFIG_H_
|
#define _TUSB_CONFIG_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
@ -62,11 +62,7 @@
|
||||||
#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
|
#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
// Enable host stack
|
||||||
// Host Configuration
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Enable Host stack
|
|
||||||
#define CFG_TUH_ENABLED 1
|
#define CFG_TUH_ENABLED 1
|
||||||
|
|
||||||
#if CFG_TUSB_MCU == OPT_MCU_RP2040
|
#if CFG_TUSB_MCU == OPT_MCU_RP2040
|
||||||
|
|
@ -82,8 +78,6 @@
|
||||||
// Default is max speed that hardware controller could support with on-chip PHY
|
// Default is max speed that hardware controller could support with on-chip PHY
|
||||||
#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
|
#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
|
// RHPort number used for host can be defined by board.mk, default to port 0
|
||||||
#ifndef BOARD_TUH_RHPORT
|
#ifndef BOARD_TUH_RHPORT
|
||||||
#define BOARD_TUH_RHPORT 0
|
#define BOARD_TUH_RHPORT 0
|
||||||
|
|
@ -91,12 +85,10 @@
|
||||||
|
|
||||||
// RHPort max operational speed can defined by board.mk
|
// RHPort max operational speed can defined by board.mk
|
||||||
#ifndef BOARD_TUH_MAX_SPEED
|
#ifndef BOARD_TUH_MAX_SPEED
|
||||||
#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
|
#define BOARD_TUH_MAX_SPEED OPT_MODE_FULL_SPEED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// Driver Configuration
|
// Driver Configuration
|
||||||
//--------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Size of buffer to hold descriptors and other data used for enumeration
|
// Size of buffer to hold descriptors and other data used for enumeration
|
||||||
#define CFG_TUH_ENUMERATION_BUFSIZE 256
|
#define CFG_TUH_ENUMERATION_BUFSIZE 256
|
||||||
|
|
@ -106,19 +98,13 @@
|
||||||
#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_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_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_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_HID 0
|
||||||
#define CFG_TUH_MSC 1
|
#define CFG_TUH_MSC 0
|
||||||
#define CFG_TUH_VENDOR 0
|
#define CFG_TUH_VENDOR 0
|
||||||
|
|
||||||
// max device support (excluding hub device): 1 hub typically has 4 ports
|
// max device support (excluding hub device): 1 hub typically has 4 ports
|
||||||
#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
|
#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:
|
// Set Line Control state on enumeration/mounted:
|
||||||
// DTR ( bit 0), RTS (bit 1)
|
// DTR ( bit 0), RTS (bit 1)
|
||||||
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
|
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
|
||||||
|
|
@ -129,7 +115,7 @@
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _TUSB_CONFIG_H_ */
|
#endif /* _TUSB_CONFIG_H_ */
|
||||||
Loading…
Reference in New Issue