mirror of
https://github.com/hathach/tinyusb.git
synced 2026-03-08 00:24:50 +00:00
replace printer_to_hid example with printer_to_cdc example
fix printer GET_DEVICE_ID request weird wIndex (interface high, alt low)
This commit is contained in:
@ -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
|
||||
|
||||
@ -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})
|
||||
115
examples/device/printer_to_cdc/src/main.c
Normal file
115
examples/device/printer_to_cdc/src/main.c
Normal file
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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,
|
||||
@ -59,31 +62,23 @@ uint8_t const *tud_descriptor_device_cb(void) {
|
||||
return (uint8_t const *) &desc_device;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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
|
||||
};
|
||||
|
||||
@ -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_ */
|
||||
@ -1,6 +0,0 @@
|
||||
{
|
||||
"version": 6,
|
||||
"include": [
|
||||
"../../../hw/bsp/BoardPresets.json"
|
||||
]
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -35,9 +35,9 @@ extern "C" {
|
||||
|
||||
/// Printer Class Specific Control Request
|
||||
typedef enum {
|
||||
TUSB_PRINTER_REQUEST_GET_DEVICE_ID = 0x01, ///< Get device ID
|
||||
TUSB_PRINTER_REQUEST_GET_PORT_STATUS = 0x02, ///< Get port status
|
||||
TUSB_PRINTER_REQUEST_SOFT_RESET = 0x03, ///< Soft reset
|
||||
TUSB_PRINTER_REQUEST_GET_DEVICE_ID = 0x00, ///< Get device ID
|
||||
TUSB_PRINTER_REQUEST_GET_PORT_STATUS = 0x01, ///< Get port status
|
||||
TUSB_PRINTER_REQUEST_SOFT_RESET = 0x02, ///< Soft reset
|
||||
} tusb_printer_request_type_t;
|
||||
|
||||
/// Printer Port Status (returned by GET_PORT_STATUS request)
|
||||
|
||||
@ -242,43 +242,54 @@ uint16_t printerd_open(uint8_t rhport, const tusb_desc_interface_t *itf_desc, ui
|
||||
}
|
||||
|
||||
bool printerd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_request_t *request) {
|
||||
TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
|
||||
uint8_t const itf_num = (uint8_t)request->wIndex;
|
||||
TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE &&
|
||||
request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
||||
|
||||
if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) {
|
||||
if (stage != CONTROL_STAGE_SETUP) {
|
||||
return true;
|
||||
}
|
||||
} else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) {
|
||||
// https://www.usb.org/sites/default/files/usbprint11a021811.pdf
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
switch (request->bRequest) {
|
||||
case TUSB_PRINTER_REQUEST_GET_DEVICE_ID: {
|
||||
const uint8_t *device_id = tud_printer_get_device_id_cb(itf_num);
|
||||
TU_VERIFY(device_id);
|
||||
const uint16_t total_len = (uint16_t)((device_id[0] << 8) | device_id[1]);
|
||||
return tud_control_xfer(rhport, request, (void *)(uintptr_t)device_id, total_len);
|
||||
}
|
||||
|
||||
case TUSB_PRINTER_REQUEST_GET_PORT_STATUS: {
|
||||
static uint8_t port_status;
|
||||
port_status = tud_printer_get_port_status_cb(itf_num);
|
||||
return tud_control_xfer(rhport, request, &port_status, sizeof(port_status));
|
||||
}
|
||||
|
||||
case TUSB_PRINTER_REQUEST_SOFT_RESET:
|
||||
tud_printer_soft_reset_cb(itf_num);
|
||||
tud_control_status(rhport, request);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else if (stage == CONTROL_STAGE_ACK) {
|
||||
tud_printer_request_complete_cb(itf_num, request);
|
||||
}
|
||||
// GET_DEVICE_ID: wIndex = (interface_number << 8) | alt_setting
|
||||
// GET_PORT_STATUS / SOFT_RESET: wIndex = interface_number
|
||||
uint8_t itf_num;
|
||||
if (TUSB_PRINTER_REQUEST_GET_DEVICE_ID == request->bRequest) {
|
||||
itf_num = tu_u16_high(request->wIndex);
|
||||
} else {
|
||||
return false;
|
||||
itf_num = tu_u16_low(request->wIndex);
|
||||
}
|
||||
|
||||
// Find the printer instance index from the USB interface number
|
||||
uint8_t itf = TUSB_INDEX_INVALID_8;
|
||||
for (uint8_t i = 0; i < CFG_TUD_PRINTER; i++) {
|
||||
if (_printer_itf[i].itf_num == itf_num) {
|
||||
itf = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
TU_VERIFY(itf < CFG_TUD_PRINTER);
|
||||
|
||||
// https://www.usb.org/sites/default/files/usbprint11a021811.pdf
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
switch (request->bRequest) {
|
||||
case TUSB_PRINTER_REQUEST_GET_DEVICE_ID: {
|
||||
const uint8_t *device_id = tud_printer_get_device_id_cb(itf);
|
||||
TU_VERIFY(device_id);
|
||||
const uint16_t total_len = (uint16_t)((device_id[0] << 8) | device_id[1]);
|
||||
return tud_control_xfer(rhport, request, (void *)(uintptr_t)device_id, total_len);
|
||||
}
|
||||
|
||||
case TUSB_PRINTER_REQUEST_GET_PORT_STATUS: {
|
||||
static uint8_t port_status;
|
||||
port_status = tud_printer_get_port_status_cb(itf);
|
||||
return tud_control_xfer(rhport, request, &port_status, sizeof(port_status));
|
||||
}
|
||||
|
||||
case TUSB_PRINTER_REQUEST_SOFT_RESET:
|
||||
tud_printer_soft_reset_cb(itf);
|
||||
tud_control_status(rhport, request);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else if (stage == CONTROL_STAGE_ACK) {
|
||||
tud_printer_request_complete_cb(itf, request);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -836,7 +836,9 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) {
|
||||
TU_LOG_USBD(" %s", tu_str_std_request[p_request->bRequest]);
|
||||
if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG_USBD("\r\n");
|
||||
if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) {
|
||||
TU_LOG_USBD("\r\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -972,7 +974,25 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
||||
|
||||
//------------- Class/Interface Specific Request -------------//
|
||||
case TUSB_REQ_RCPT_INTERFACE: {
|
||||
uint8_t const itf = tu_u16_low(p_request->wIndex);
|
||||
uint8_t itf;
|
||||
#if CFG_TUD_PRINTER
|
||||
// Printer GET_DEVICE_ID has a weird wIndex = interface (high) | alt (low)
|
||||
// attempt to interpret this as a printer request if matched
|
||||
if (TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type &&
|
||||
TUSB_DIR_IN == p_request->bmRequestType_bit.direction &&
|
||||
TUSB_PRINTER_REQUEST_GET_DEVICE_ID == p_request->bRequest) {
|
||||
itf = tu_u16_high(p_request->wIndex);
|
||||
if (itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)) {
|
||||
const usbd_class_driver_t * driver = get_driver(_usbd_dev.itf2drv[itf]);
|
||||
if (driver != NULL && driver->control_xfer_cb == printerd_control_xfer_cb) {
|
||||
if (invoke_class_control(rhport, driver, p_request)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
itf = tu_u16_low(p_request->wIndex);
|
||||
TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv));
|
||||
|
||||
usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]);
|
||||
|
||||
Reference in New Issue
Block a user