diff options
| author | hathach <[email protected]> | 2026-03-06 17:22:38 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-03-06 17:22:38 +0700 |
| commit | 73cd53129529f2dce70072953bfd50ec9dc6b8ea (patch) | |
| tree | e4fcc75febdc1af7f56973fed061bd2a671f48a2 /examples | |
| parent | 988b18a40a4276eb731c80bc4cec3bf5750523f9 (diff) | |
replace printer_to_hid example with printer_to_cdc example
fix printer GET_DEVICE_ID request weird wIndex (interface high, alt low)
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/device/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | examples/device/printer_to_cdc/CMakeLists.txt (renamed from examples/device/printer_to_hid/CMakeLists.txt) | 2 | ||||
| -rw-r--r-- | examples/device/printer_to_cdc/Makefile (renamed from examples/device/printer_to_hid/Makefile) | 0 | ||||
| -rw-r--r-- | examples/device/printer_to_cdc/src/main.c | 115 | ||||
| -rw-r--r-- | examples/device/printer_to_cdc/src/tusb_config.h (renamed from examples/device/printer_to_hid/src/tusb_config.h) | 12 | ||||
| -rw-r--r-- | examples/device/printer_to_cdc/src/usb_descriptors.c (renamed from examples/device/printer_to_hid/src/usb_descriptors.c) | 59 | ||||
| -rw-r--r-- | examples/device/printer_to_cdc/src/usb_descriptors.h (renamed from examples/device/printer_to_hid/src/usb_descriptors.h) | 12 | ||||
| -rw-r--r-- | examples/device/printer_to_hid/CMakePresets.json | 6 | ||||
| -rw-r--r-- | examples/device/printer_to_hid/README.md | 0 | ||||
| -rw-r--r-- | examples/device/printer_to_hid/src/main.c | 175 |
10 files changed, 155 insertions, 228 deletions
diff --git a/examples/device/CMakeLists.txt b/examples/device/CMakeLists.txt index dbcb8df6a..7173f455e 100644 --- a/examples/device/CMakeLists.txt +++ b/examples/device/CMakeLists.txt @@ -30,7 +30,7 @@ set(EXAMPLE_LIST msc_dual_lun mtp net_lwip_webserver - printer_to_hid + printer_to_cdc uac2_headset uac2_speaker_fb usbtmc diff --git a/examples/device/printer_to_hid/CMakeLists.txt b/examples/device/printer_to_cdc/CMakeLists.txt index f58759059..3c8ab3653 100644 --- a/examples/device/printer_to_hid/CMakeLists.txt +++ b/examples/device/printer_to_cdc/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20) include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) -project(printer_to_hid C CXX ASM) +project(printer_to_cdc C CXX ASM) # Checks this example is valid for the family and initializes the project family_initialize_project(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}) diff --git a/examples/device/printer_to_hid/Makefile b/examples/device/printer_to_cdc/Makefile index 1a4b428dc..1a4b428dc 100644 --- a/examples/device/printer_to_hid/Makefile +++ b/examples/device/printer_to_cdc/Makefile diff --git a/examples/device/printer_to_cdc/src/main.c b/examples/device/printer_to_cdc/src/main.c new file mode 100644 index 000000000..aba79025c --- /dev/null +++ b/examples/device/printer_to_cdc/src/main.c @@ -0,0 +1,115 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2026 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 example demonstrates a USB Printer + CDC composite device. + * Data received on the Printer interface is forwarded to the CDC serial port, + * and data received on the CDC serial port is forwarded back to the Printer interface. + * + * To test: + * 1. Flash the device + * 2. Open a serial terminal on the CDC port (e.g. /dev/ttyACM0) + * 3. Send data to the printer: echo "hello" > /dev/usb/lp0 + * 4. The data appears on the CDC serial terminal + * 5. Type in the serial terminal to send data back through the printer TX + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "bsp/board_api.h" +#include "tusb.h" + +#include "usb_descriptors.h" + +// -------------------------------------------------------------------+ +// Tasks +// -------------------------------------------------------------------+ + +// Forward data from Printer RX to CDC TX +static void printer_to_cdc_task(void) { + if (tud_printer_read_available() == 0 || !tud_cdc_write_available()) { + return; + } + + uint8_t buf[64]; + uint32_t count = tud_printer_read(buf, sizeof(buf)); + if (count > 0) { + tud_cdc_write(buf, count); + tud_cdc_write_flush(); + } +} + +// Forward data from CDC RX to Printer TX +static void cdc_to_printer_task(void) { + if (tud_cdc_available() == 0 || !tud_printer_write_available()) { + return; + } + + uint8_t buf[64]; + uint32_t count = tud_cdc_read(buf, sizeof(buf)); + if (count > 0) { + tud_printer_write(buf, count); + tud_printer_write_flush(); + } +} + +int main(void) { + board_init(); + // init device stack on configured roothub port + tusb_rhport_init_t dev_init = {.role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_AUTO}; + tusb_init(BOARD_TUD_RHPORT, &dev_init); + board_init_after_tusb(); + + while (1) { + tud_task(); // tinyusb device task + printer_to_cdc_task(); // forward printer data to CDC + cdc_to_printer_task(); // forward CDC data to printer + } +} + +//--------------------------------------------------------------------+ +// Printer callbacks +//--------------------------------------------------------------------+ + +void tud_printer_rx_cb(uint8_t itf) { + (void)itf; +} + +// IEEE 1284 Device ID: first 2 bytes are big-endian total length (including the 2 length bytes). +// The rest is the Device ID string using standard abbreviated keys. +static const char printer_device_id[] = + "\x00\x34" // total length = 52 = 0x0034 (big-endian) + "MFG:TinyUSB;" + "MDL:Printer to CDC;" + "CMD:PS;" + "CLS:PRINTER;"; + +TU_VERIFY_STATIC(sizeof(printer_device_id) - 1 == 52, "device ID length mismatch"); + +uint8_t const *tud_printer_get_device_id_cb(uint8_t itf) { + (void)itf; + return (uint8_t const *)printer_device_id; +} diff --git a/examples/device/printer_to_hid/src/tusb_config.h b/examples/device/printer_to_cdc/src/tusb_config.h index 0988be166..50ef41762 100644 --- a/examples/device/printer_to_hid/src/tusb_config.h +++ b/examples/device/printer_to_cdc/src/tusb_config.h @@ -91,15 +91,19 @@ extern "C" { #endif //------------- CLASS -------------// -#define CFG_TUD_HID 1 -#define CFG_TUD_CDC 0 +#define CFG_TUD_HID 0 +#define CFG_TUD_CDC 1 #define CFG_TUD_MSC 0 #define CFG_TUD_MIDI 0 #define CFG_TUD_VENDOR 0 #define CFG_TUD_PRINTER 1 -// HID buffer size Should be sufficient to hold ID (if any) + Data -#define CFG_TUD_HID_EP_BUFSIZE 16 +// CDC FIFO size of TX and RX +#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) + +// CDC Endpoint transfer buffer size +#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) // Printer buffer sizes #define CFG_TUD_PRINTER_RX_BUFSIZE 512 diff --git a/examples/device/printer_to_hid/src/usb_descriptors.c b/examples/device/printer_to_cdc/src/usb_descriptors.c index 1cbabb02e..30d309ed4 100644 --- a/examples/device/printer_to_hid/src/usb_descriptors.c +++ b/examples/device/printer_to_cdc/src/usb_descriptors.c @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2026 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 @@ -29,7 +29,7 @@ #include "usb_descriptors.h" #define USB_VID 0xCafe -#define USB_PID 0x4004 +#define USB_PID 0x4005 #define USB_BCD 0x0200 //--------------------------------------------------------------------+ @@ -39,9 +39,12 @@ static tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, .bcdUSB = USB_BCD, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, + + // Use Interface Association Descriptor (IAD) for CDC + // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, .idVendor = USB_VID, @@ -60,30 +63,22 @@ uint8_t const *tud_descriptor_device_cb(void) { } //--------------------------------------------------------------------+ -// HID Report Descriptor -//--------------------------------------------------------------------+ -static uint8_t const desc_hid_report[] = { - TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD)) -}; - -uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) { - (void)instance; - return desc_hid_report; -} - -//--------------------------------------------------------------------+ // Configuration Descriptor //--------------------------------------------------------------------+ // Endpoint numbers #if defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) - #define EPNUM_HID 0x81 - #define EPNUM_PRINTER_OUT 0x02 - #define EPNUM_PRINTER_IN 0x83 + #define EPNUM_CDC_NOTIF 0x81 + #define EPNUM_CDC_OUT 0x02 + #define EPNUM_CDC_IN 0x83 + #define EPNUM_PRINTER_OUT 0x04 + #define EPNUM_PRINTER_IN 0x85 #else - #define EPNUM_HID 0x81 - #define EPNUM_PRINTER_OUT 0x02 - #define EPNUM_PRINTER_IN 0x82 + #define EPNUM_CDC_NOTIF 0x81 + #define EPNUM_CDC_OUT 0x02 + #define EPNUM_CDC_IN 0x82 + #define EPNUM_PRINTER_OUT 0x03 + #define EPNUM_PRINTER_IN 0x83 #endif // full speed configuration @@ -91,9 +86,8 @@ static uint8_t const desc_fs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), - // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval - TUD_HID_DESCRIPTOR(ITF_NUM_HID, 4, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, - CFG_TUD_HID_EP_BUFSIZE, 5), + // Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), // Interface number, string index, EP Bulk Out address, EP Bulk In address, EP size TUD_PRINTER_DESCRIPTOR(ITF_NUM_PRINTER, 5, EPNUM_PRINTER_OUT, EPNUM_PRINTER_IN, 64), @@ -104,8 +98,7 @@ static uint8_t const desc_fs_configuration[] = { static uint8_t const desc_hs_configuration[] = { TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), - TUD_HID_DESCRIPTOR(ITF_NUM_HID, 4, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, - CFG_TUD_HID_EP_BUFSIZE, 5), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512), TUD_PRINTER_DESCRIPTOR(ITF_NUM_PRINTER, 5, EPNUM_PRINTER_OUT, EPNUM_PRINTER_IN, 512), }; @@ -119,9 +112,9 @@ static tusb_desc_device_qualifier_t const desc_device_qualifier = { .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, .bcdUSB = USB_BCD, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, .bNumConfigurations = 0x01, @@ -166,7 +159,7 @@ enum { STRID_MANUFACTURER, STRID_PRODUCT, STRID_SERIAL, - STRID_HID, + STRID_CDC, STRID_PRINTER, }; @@ -175,7 +168,7 @@ static char const *string_desc_arr[] = { "TinyUSB", // 1: Manufacturer "TinyUSB Device", // 2: Product NULL, // 3: Serial, use unique ID if possible - "TinyUSB HID", // 4: HID Interface + "TinyUSB CDC", // 4: CDC Interface "TinyUSB Printer", // 5: Printer Interface }; diff --git a/examples/device/printer_to_hid/src/usb_descriptors.h b/examples/device/printer_to_cdc/src/usb_descriptors.h index 20c34f151..830593b4d 100644 --- a/examples/device/printer_to_hid/src/usb_descriptors.h +++ b/examples/device/printer_to_cdc/src/usb_descriptors.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2026 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 @@ -25,17 +25,13 @@ #ifndef USB_DESCRIPTORS_H_ #define USB_DESCRIPTORS_H_ -// HID report ID enum { - REPORT_ID_KEYBOARD = 1, -}; - -enum { - ITF_NUM_HID, + ITF_NUM_CDC, + ITF_NUM_CDC_DATA, ITF_NUM_PRINTER, ITF_NUM_TOTAL, }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_PRINTER_DESC_LEN) +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_PRINTER_DESC_LEN) #endif /* USB_DESCRIPTORS_H_ */ diff --git a/examples/device/printer_to_hid/CMakePresets.json b/examples/device/printer_to_hid/CMakePresets.json deleted file mode 100644 index 5cd8971e9..000000000 --- a/examples/device/printer_to_hid/CMakePresets.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "version": 6, - "include": [ - "../../../hw/bsp/BoardPresets.json" - ] -} diff --git a/examples/device/printer_to_hid/README.md b/examples/device/printer_to_hid/README.md deleted file mode 100644 index e69de29bb..000000000 --- a/examples/device/printer_to_hid/README.md +++ /dev/null diff --git a/examples/device/printer_to_hid/src/main.c b/examples/device/printer_to_hid/src/main.c deleted file mode 100644 index 0d14147b4..000000000 --- a/examples/device/printer_to_hid/src/main.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2026 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 "usb_descriptors.h" - -// -------------------------------------------------------------------+ -// Variables -// -------------------------------------------------------------------+ - -// next keycode to send on usb/hid -static uint8_t next_keycode = 0; -// next key modifiers to send on usb/hid -static uint8_t next_modifiers = 0; -// whether the next usb/hid report must be NULL to release the last keystroke -static bool next_keycode_is_release = false; - - -// -------------------------------------------------------------------+ -// Tasks -// -------------------------------------------------------------------+ - -// Every 10ms, we will place HID data in the usb/hid endpoint, ready to -// sent to the host when required. The tasks will read the keycode in -// next_keycode and place it in the HID report, then set next_is_null -// such that the key is released by the next report. This seem to help -// stroking the same key twice when the character is repeated in the data. -static void hid_tx_task(void) { - // Poll every 10ms - const uint32_t interval_ms = 10; - static uint32_t start_ms = 0; - - if (!tud_hid_ready()) { - return; - } - - if (tusb_time_millis_api() - start_ms < interval_ms) { - return; // not enough time - } - start_ms += interval_ms; - - if (next_keycode_is_release || next_keycode == 0) { - tud_hid_keyboard_report(1, 0, NULL); - next_keycode_is_release = false; - return; - } - - uint8_t keycode_array[6] = {0}; - keycode_array[0] = next_keycode; - tud_hid_keyboard_report(1, next_modifiers, keycode_array); - next_keycode_is_release = true; - next_keycode = 0; -} - -// Read one byte from printer FIFO and translate to HID keycode. -// Only a-zA-Z0-9 are translated; everything else becomes space. -static void printer_to_hid_task(void) { - if (next_keycode != 0) { - return; // previous key not yet sent - } - - uint8_t ch; - if (tud_printer_read(&ch, 1) == 0) { - return; // no data available - } - - uint8_t m = 0; - if ('a' <= ch && ch <= 'z') { - ch = (uint8_t)(ch - 'a' + HID_KEY_A); - } else if ('A' <= ch && ch <= 'Z') { - ch = (uint8_t)(ch - 'A' + HID_KEY_A); - m = KEYBOARD_MODIFIER_LEFTSHIFT; - } else if ('1' <= ch && ch <= '9') { - ch = (uint8_t)(ch - '1' + HID_KEY_1); - } else if (ch == '0') { - ch = HID_KEY_0; - } else { - ch = HID_KEY_SPACE; - } - - next_keycode = ch; - next_modifiers = m; -} - -int main(void) { - board_init(); - // init device and host stack on configured roothub port - tusb_rhport_init_t dev_init = {.role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_AUTO}; - tusb_init(BOARD_TUD_RHPORT, &dev_init); - board_init_after_tusb(); - - while (1) { - tud_task(); // tinyusb device task - printer_to_hid_task(); // read printer data and translate to HID keycodes - hid_tx_task(); // send keycodes to host via HID - } -} - - -//--------------------------------------------------------------------+ -// Printer callbacks -//--------------------------------------------------------------------+ - -void tud_printer_rx_cb(uint8_t itf) { - (void)itf; -} - -// IEEE 1284 Device ID: first 2 bytes are big-endian total length (including the 2 length bytes). -// The rest is the Device ID string using standard abbreviated keys. -static const char printer_device_id[] = - "\x00\x34" // total length = 52 = 0x0034 (big-endian) - "MFG:TinyUSB;" - "MDL:Printer to HID;" - "CMD:PS;" - "CLS:PRINTER;"; - -TU_VERIFY_STATIC(sizeof(printer_device_id) - 1 == 52, "device ID length mismatch"); - -uint8_t const *tud_printer_get_device_id_cb(uint8_t itf) { - (void)itf; - return (uint8_t const *)printer_device_id; -} - - -//--------------------------------------------------------------------+ -// HID callbacks -//--------------------------------------------------------------------+ - -uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, - uint16_t reqlen) { - (void)instance; - (void)report_id; - (void)report_type; - (void)buffer; - (void)reqlen; - return 0; -} - -void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, const uint8_t *buffer, - uint16_t bufsize) { - (void)instance; - (void)report_id; - (void)report_type; - (void)buffer; - (void)bufsize; - return; -} |
