#include <EspUsbHost.h>
class EspUsbHostPrinter : public EspUsbHost {
public:
bool outputEndpointAvailable = false;
uint8_t outputEndpointAddress = 0;
bool inputEndpointAvailable = false;
uint8_t inputEndpointAddress = 0;
bool dataReceived = false;
uint8_t receivedData[512];
size_t receivedLength = 0;
// 添加传输状态跟踪和超时机制
bool sendTransferPending = false;
unsigned long sendTransferStartTime = 0;
const unsigned long sendTransferTimeout = 5000; // 5秒超时
// 传输统计
unsigned long transfersSubmitted = 0;
unsigned long transfersCompleted = 0;
unsigned long transfersFailed = 0;
// 设备信息
uint16_t vendorId = 0;
uint16_t productId = 0;
uint8_t deviceClass = 0;
uint8_t deviceSubClass = 0;
uint8_t deviceProtocol = 0;
// 设备连接状态跟踪
bool deviceInfoReceived = false;
unsigned long deviceConnectedTime = 0;
bool enumerationAttempted = false;
/**
* @brief 检查USB设备是否已连接
*/
bool isDeviceConnected() {
return deviceHandle != nullptr;
}
/**
* @brief USB传输完成回调函数(用于发送数据)
*/
static void transferCallback(usb_transfer_t *transfer) {
if (transfer) {
EspUsbHostPrinter *host = (EspUsbHostPrinter *)transfer->context;
host->sendTransferPending = false;
host->sendTransferStartTime = 0;
host->transfersCompleted++;
ESP_LOGI("EspUsbHostPrinter", "Send Transfer completed, status: %d, bytes: %d",
transfer->status, transfer->actual_num_bytes);
// 打印传输的详细信息
if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) {
ESP_LOGW("EspUsbHostPrinter", "Send transfer not completed successfully, status: %d", transfer->status);
host->transfersFailed++;
}
usb_host_transfer_free(transfer);
}
}
/**
* @brief USB接收传输完成回调函数
*/
static void receiveCallback(usb_transfer_t *transfer) {
EspUsbHostPrinter *host = (EspUsbHostPrinter *)transfer->context;
if (transfer) {
ESP_LOGI("EspUsbHostPrinter", "Receive Transfer status: %d, bytes: %d",
transfer->status, transfer->actual_num_bytes);
if (transfer->status == USB_TRANSFER_STATUS_COMPLETED && transfer->actual_num_bytes > 0) {
size_t actual_bytes = transfer->actual_num_bytes;
host->dataReceived = true;
host->receivedLength = actual_bytes;
if (host->receivedLength > sizeof(host->receivedData) - 1) {
host->receivedLength = sizeof(host->receivedData) - 1;
}
memcpy(host->receivedData, transfer->data_buffer, host->receivedLength);
host->receivedData[host->receivedLength] = '\0';
ESP_LOGI("EspUsbHostPrinter", "Data received: %d bytes", host->receivedLength);
// 打印接收到的原始数据
ESP_LOG_BUFFER_HEX("USB_RX", host->receivedData, host->receivedLength);
} else if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) {
ESP_LOGW("EspUsbHostPrinter", "Receive transfer not completed, status: %d", transfer->status);
}
}
// 重新提交接收传输以继续监听数据
if (transfer) {
esp_err_t err = usb_host_transfer_submit(transfer);
if (err != ESP_OK) {
ESP_LOGE("EspUsbHostPrinter", "Failed to re-submit receive transfer: %d", err);
usb_host_transfer_free(transfer);
}
}
}
/**
* @brief 处理USB设备连接事件
*/
void onEvent(const usb_host_client_event_msg_t *event) {
if (event->event == USB_HOST_CLIENT_EVENT_NEW_DEV) {
ESP_LOGI("EspUsbHostPrinter", "New USB device connected");
deviceInfoReceived = false; // 重置设备信息接收状态
enumerationAttempted = false;
deviceConnectedTime = millis();
} else if (event->event == USB_HOST_CLIENT_EVENT_DEV_GONE) {
ESP_LOGI("EspUsbHostPrinter", "USB device disconnected");
resetEndpoint();
} else {
ESP_LOGI("EspUsbHostPrinter", "USB Event: %d", event->event);
}
}
/**
* @brief 处理USB配置描述符的回调函数
*/
void onConfig(const uint8_t bDescriptorType, const uint8_t *p) override {
switch (bDescriptorType) {
case USB_B_DESCRIPTOR_TYPE_DEVICE: {
if (p == nullptr) {
ESP_LOGW("EspUsbHostPrinter", "Device descriptor pointer is null");
break;
}
const usb_device_desc_t *device_desc = (const usb_device_desc_t *)p;
vendorId = device_desc->idVendor;
productId = device_desc->idProduct;
deviceClass = device_desc->bDeviceClass;
deviceSubClass = device_desc->bDeviceSubClass;
deviceProtocol = device_desc->bDeviceProtocol;
deviceInfoReceived = true; // 标记已接收到设备信息
ESP_LOGI("EspUsbHostPrinter", "Device descriptor - Class: 0x%02x, SubClass: 0x%02x, Protocol: 0x%02x, Vendor: 0x%04x, Product: 0x%04x",
device_desc->bDeviceClass, device_desc->bDeviceSubClass, device_desc->bDeviceProtocol,
device_desc->idVendor, device_desc->idProduct);
break;
}
case USB_B_DESCRIPTOR_TYPE_CONFIGURATION: {
if (p == nullptr) {
ESP_LOGW("EspUsbHostPrinter", "Configuration descriptor pointer is null");
break;
}
const usb_config_desc_t *config_desc = (const usb_config_desc_t *)p;
ESP_LOGI("EspUsbHostPrinter", "Configuration descriptor - Interfaces: %d, ConfigValue: %d",
config_desc->bNumInterfaces, config_desc->bConfigurationValue);
break;
}
case USB_B_DESCRIPTOR_TYPE_INTERFACE: {
if (p == nullptr) {
ESP_LOGW("EspUsbHostPrinter", "Interface descriptor pointer is null");
break;
}
const usb_intf_desc_t *intf = (const usb_intf_desc_t *)p;
ESP_LOGI("EspUsbHostPrinter", "Interface descriptor - Class: 0x%02x, Subclass: 0x%02x, Protocol: 0x%02x, Number: %d",
intf->bInterfaceClass, intf->bInterfaceSubClass, intf->bInterfaceProtocol, intf->bInterfaceNumber);
// 支持多种设备类型,包括所有可能的CDC类设备
bool isCompatible = (intf->bInterfaceClass == USB_CLASS_PRINTER) ||
(intf->bInterfaceClass == 0x0A) || // CDC数据类
(intf->bInterfaceClass == 0x02) || // CDC控制类
(intf->bInterfaceClass == 0xFF) || // Vendor specific
(intf->bInterfaceClass == 0x00); // 设备特定类
if (isCompatible) {
ESP_LOGI("EspUsbHostPrinter", "Compatible interface found (Class: 0x%02x)", intf->bInterfaceClass);
esp_err_t err = usb_host_interface_claim(clientHandle, deviceHandle,
intf->bInterfaceNumber,
intf->bAlternateSetting);
if (err != ESP_OK) {
ESP_LOGW("EspUsbHostPrinter", "Claim interface err=%x", err);
}
} else {
ESP_LOGI("EspUsbHostPrinter", "Non-compatible interface found, class: 0x%02x", intf->bInterfaceClass);
}
break;
}
case USB_B_DESCRIPTOR_TYPE_ENDPOINT: {
if (p == nullptr) {
ESP_LOGW("EspUsbHostPrinter", "Endpoint descriptor pointer is null");
break;
}
const usb_ep_desc_t *endpoint = (const usb_ep_desc_t *)p;
ESP_LOGI("EspUsbHostPrinter", "Endpoint - Addr: 0x%02x, Attr: 0x%02x, MaxPacket: %d, Interval: %d",
endpoint->bEndpointAddress, endpoint->bmAttributes, endpoint->wMaxPacketSize, endpoint->bInterval);
if ((endpoint->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK) == USB_BM_ATTRIBUTES_XFER_BULK) {
ESP_LOGI("EspUsbHostPrinter", "Bulk endpoint detected");
if (!(endpoint->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK)) {
outputEndpointAddress = endpoint->bEndpointAddress;
outputEndpointAvailable = true;
ESP_LOGI("EspUsbHostPrinter", "Bulk OUT endpoint configured: 0x%02x", outputEndpointAddress);
} else {
inputEndpointAddress = endpoint->bEndpointAddress;
inputEndpointAvailable = true;
ESP_LOGI("EspUsbHostPrinter", "Bulk IN endpoint configured: 0x%02x", inputEndpointAddress);
// 为输入端点启动接收传输
startReceiveTransfer();
}
} else if ((endpoint->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK) == USB_BM_ATTRIBUTES_XFER_INT) {
ESP_LOGI("EspUsbHostPrinter", "Interrupt endpoint detected");
if (endpoint->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) {
inputEndpointAddress = endpoint->bEndpointAddress;
inputEndpointAvailable = true;
ESP_LOGI("EspUsbHostPrinter", "Interrupt IN endpoint configured: 0x%02x", inputEndpointAddress);
// 为输入端点启动接收传输
startReceiveTransfer();
}
} else {
uint8_t transferType = endpoint->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK;
switch(transferType) {
case USB_BM_ATTRIBUTES_XFER_CONTROL:
ESP_LOGI("EspUsbHostPrinter", "Control endpoint: 0x%02x", endpoint->bEndpointAddress);
break;
case USB_BM_ATTRIBUTES_XFER_ISOC:
ESP_LOGI("EspUsbHostPrinter", "Isochronous endpoint: 0x%02x", endpoint->bEndpointAddress);
break;
}
}
break;
}
default:
ESP_LOGD("EspUsbHostPrinter", "Unhandled descriptor type: %d", bDescriptorType);
break;
}
}
/**
* @brief 启动接收传输
*/
esp_err_t startReceiveTransfer() {
if (!inputEndpointAvailable) {
ESP_LOGW("EspUsbHostPrinter", "Cannot start receive transfer: input endpoint not available");
return ESP_ERR_NOT_FOUND;
}
usb_transfer_t *transfer = nullptr;
esp_err_t err = usb_host_transfer_alloc(512, 0, &transfer);
if (err != ESP_OK) {
ESP_LOGE("EspUsbHostPrinter", "Failed to allocate receive transfer: %d", err);
return err;
}
transfer->device_handle = deviceHandle;
transfer->bEndpointAddress = inputEndpointAddress;
transfer->num_bytes = 512;
transfer->callback = receiveCallback;
transfer->context = this;
ESP_LOGI("EspUsbHostPrinter", "Starting receive transfer on endpoint 0x%02x", inputEndpointAddress);
err = usb_host_transfer_submit(transfer);
if (err != ESP_OK) {
ESP_LOGE("EspUsbHostPrinter", "Failed to submit receive transfer: %d", err);
usb_host_transfer_free(transfer);
}
return err;
}
/**
* @brief 向USB设备发送数据
*/
esp_err_t sendData(const uint8_t *data, size_t length) {
if (data == nullptr || length == 0) {
ESP_LOGW("EspUsbHostPrinter", "SendData failed: Invalid arguments");
return ESP_ERR_INVALID_ARG;
}
if (!outputEndpointAvailable) {
ESP_LOGW("EspUsbHostPrinter", "SendData failed: Endpoint not available");
return ESP_ERR_NOT_FOUND;
}
// 检查超时,强制清除挂起状态
if (sendTransferPending) {
unsigned long currentTime = millis();
if ((currentTime - sendTransferStartTime) > sendTransferTimeout) {
ESP_LOGW("EspUsbHostPrinter", "Send transfer timeout (%lu ms), forcing clear",
(currentTime - sendTransferStartTime));
sendTransferPending = false;
sendTransferStartTime = 0;
} else {
ESP_LOGW("EspUsbHostPrinter", "SendData failed: Previous transfer still pending (%lu ms)",
(currentTime - sendTransferStartTime));
return ESP_ERR_NOT_FINISHED;
}
}
usb_transfer_t *transfer = nullptr;
esp_err_t err = usb_host_transfer_alloc(length, 0, &transfer);
if (err != ESP_OK) {
ESP_LOGE("EspUsbHostPrinter", "Transfer alloc failed: %d", err);
return err;
}
transfer->device_handle = deviceHandle;
transfer->bEndpointAddress = outputEndpointAddress;
transfer->num_bytes = length;
transfer->callback = transferCallback;
transfer->context = this;
memcpy(transfer->data_buffer, data, length);
ESP_LOGI("EspUsbHostPrinter", "Sending %d bytes to endpoint 0x%02x", length, outputEndpointAddress);
ESP_LOG_BUFFER_HEX("USB_TX", data, length);
sendTransferPending = true;
sendTransferStartTime = millis();
transfersSubmitted++;
err = usb_host_transfer_submit(transfer);
if (err != ESP_OK) {
ESP_LOGE("EspUsbHostPrinter", "Transfer submit failed: %d", err);
sendTransferPending = false;
sendTransferStartTime = 0;
transfersFailed++;
usb_host_transfer_free(transfer);
}
return err;
}
/**
* @brief 执行USB主机任务
*/
void task() { EspUsbHost::task(); }
/**
* @brief 重置端点状态
*/
void resetEndpoint() {
outputEndpointAvailable = false;
outputEndpointAddress = 0;
inputEndpointAvailable = false;
inputEndpointAddress = 0;
dataReceived = false;
receivedLength = 0;
sendTransferPending = false;
sendTransferStartTime = 0;
deviceInfoReceived = false;
enumerationAttempted = false;
}
/**
* @brief 获取端点状态信息
*/
void printEndpointStatus() {
ESP_LOGI("EspUsbHostPrinter", "Endpoints - OUT: %s (0x%02x), IN: %s (0x%02x)",
outputEndpointAvailable ? "Available" : "Not available", outputEndpointAddress,
inputEndpointAvailable ? "Available" : "Not available", inputEndpointAddress);
}
/**
* @brief 获取设备信息
*/
void printDeviceInfo() {
ESP_LOGI("EspUsbHostPrinter", "Device Info - Vendor: 0x%04x, Product: 0x%04x, Class: 0x%02x, SubClass: 0x%02x, Protocol: 0x%02x",
vendorId, productId, deviceClass, deviceSubClass, deviceProtocol);
// 根据设备信息提供可能的建议
if (vendorId == 0x10C4 && productId == 0xEA60) {
ESP_LOGI("EspUsbHostPrinter", "Detected CP210x device - common USB-to-Serial converter");
} else if (vendorId == 0x0403 && productId == 0x6001) {
ESP_LOGI("EspUsbHostPrinter", "Detected FTDI device - common USB-to-Serial converter");
} else if (vendorId == 0x2341 || vendorId == 0x1A86) {
ESP_LOGI("EspUsbHostPrinter", "Detected Arduino/CH340 device");
}
}
/**
* @brief 打印完整的设备描述符信息
*/
void printFullDeviceInfo() {
Serial.println("=== 完整设备信息 ===");
Serial.printf("设备连接时间: %lu ms\n", deviceConnectedTime);
Serial.printf("Vendor ID: 0x%04X\n", vendorId);
Serial.printf("Product ID: 0x%04X\n", productId);
Serial.printf("Device Class: 0x%02X\n", deviceClass);
Serial.printf("Device SubClass: 0x%02X\n", deviceSubClass);
Serial.printf("Device Protocol: 0x%02X\n", deviceProtocol);
Serial.printf("设备信息接收: %s\n", deviceInfoReceived ? "是" : "否");
Serial.printf("枚举尝试: %s\n", enumerationAttempted ? "是" : "否");
Serial.printf("输出端点: %s (地址: 0x%02X)\n",
outputEndpointAvailable ? "可用" : "不可用", outputEndpointAddress);
Serial.printf("输入端点: %s (地址: 0x%02X)\n",
inputEndpointAvailable ? "可用" : "不可用", inputEndpointAddress);
// 根据设备类型提供信息
if (deviceClass == 0x00 && deviceSubClass == 0x00) {
Serial.println("设备类型: 设备特定类设备");
} else if (deviceClass == 0xFF) {
Serial.println("设备类型: 厂商特定设备");
} else if (deviceClass == 0x07) {
Serial.println("设备类型: 打印机类设备");
} else if (deviceClass == 0x02) {
Serial.println("设备类型: 通讯设备类(CDC)");
} else if (deviceClass == 0x0A) {
Serial.println("设备类型: CDC数据类设备");
} else if (deviceClass == 0x03) {
Serial.println("设备类型: HID设备");
} else if (deviceClass == 0x08) {
Serial.println("设备类型: 存储设备");
}
Serial.println("==================");
}
/**
* @brief 详细分析设备类型
*/
void analyzeDeviceType() {
Serial.println("=== 设备类型分析 ===");
if (!deviceInfoReceived) {
Serial.println("警告: 尚未接收到设备信息,可能设备未正确枚举");
unsigned long timeSinceConnect = millis() - deviceConnectedTime;
Serial.printf("自连接以来时间: %lu ms\n", timeSinceConnect);
Serial.println("==================");
return;
}
// 根据Vendor ID和Product ID判断设备类型
if (vendorId == 0x046D) {
Serial.println("可能设备: Logitech设备");
} else if (vendorId == 0x0951) {
Serial.println("可能设备: Kingston存储设备");
} else if (vendorId == 0x0781) {
Serial.println("可能设备: SanDisk存储设备");
} else if (vendorId == 0x1949) {
Serial.println("可能设备: Kindle设备");
} else if (vendorId == 0x05AC) {
Serial.println("可能设备: Apple设备");
} else if (vendorId == 0x04F2) {
Serial.println("可能设备: Webcam设备");
} else if (vendorId == 0x045E) {
Serial.println("可能设备: Microsoft设备");
} else if (vendorId == 0x04A9) {
Serial.println("可能设备: Canon设备");
} else if (vendorId == 0x04B3) {
Serial.println("可能设备: IBM设备");
} else if (vendorId == 0x0000 && productId == 0x0000) {
Serial.println("错误: 无效的设备ID,设备可能未正确枚举");
} else {
Serial.printf("未知设备: Vendor ID 0x%04X, Product ID 0x%04X\n", vendorId, productId);
}
// 根据设备类判断
switch(deviceClass) {
case 0x00:
Serial.println("设备类: 设备特定类");
break;
case 0x01:
Serial.println("设备类: 音频设备");
break;
case 0x02:
Serial.println("设备类: 通讯设备(CDC)");
break;
case 0x03:
Serial.println("设备类: HID设备");
if (deviceSubClass == 0x01 && deviceProtocol == 0x02) {
Serial.println("具体类型: 鼠标");
} else if (deviceSubClass == 0x01 && deviceProtocol == 0x01) {
Serial.println("具体类型: 键盘");
}
break;
case 0x05:
Serial.println("设备类: 物理设备");
break;
case 0x06:
Serial.println("设备类: 图像设备");
break;
case 0x07:
Serial.println("设备类: 打印机设备");
break;
case 0x08:
Serial.println("设备类: 存储设备");
break;
case 0x09:
Serial.println("设备类: 集线器设备");
break;
case 0x0A:
Serial.println("设备类: CDC数据设备");
break;
case 0xFF:
Serial.println("设备类: 厂商特定设备");
break;
default:
Serial.printf("设备类: 未知 (0x%02X)\n", deviceClass);
break;
}
Serial.println("==================");
}
/**
* @brief 检查接收传输状态
*/
void checkReceiveStatus() {
Serial.println("=== 接收状态检查 ===");
Serial.printf("输入端点可用: %s\n", inputEndpointAvailable ? "是" : "否");
Serial.printf("输入端点地址: 0x%02X\n", inputEndpointAddress);
if (inputEndpointAvailable) {
Serial.println("尝试启动接收传输...");
esp_err_t err = startReceiveTransfer();
if (err == ESP_OK) {
Serial.println("接收传输启动成功");
} else {
Serial.printf("接收传输启动失败: %d\n", err);
}
}
Serial.println("==================");
}
/**
* @brief 检查是否有接收到数据
*/
bool hasDataReceived() {
return dataReceived;
}
/**
* @brief 获取接收到的数据
*/
void getReceivedData(uint8_t *data, size_t &length) {
if (dataReceived && data && length >= receivedLength) {
memcpy(data, receivedData, receivedLength);
length = receivedLength;
dataReceived = false;
} else {
length = 0;
}
}
/**
* @brief 清除接收数据标志
*/
void clearReceivedData() {
dataReceived = false;
receivedLength = 0;
}
/**
* @brief 尝试发送不同长度的数据包来测试设备
*/
void testDevice() {
Serial.println("Running device test...");
printTransferStats();
// 测试1: 发送单个字节
Serial.println("Test 1: Sending single byte 0x55");
uint8_t singleByte = 0x55;
esp_err_t res = sendData(&singleByte, 1);
printResult("Single byte test", res);
delayAndCheck(3000);
// 测试2: 发送短数据包
Serial.println("Test 2: Sending short data packet");
const uint8_t shortPacket[] = {0x00, 0x01, 0x02, 0x03};
res = sendData(shortPacket, sizeof(shortPacket));
printResult("Short packet test", res);
delayAndCheck(3000);
// 测试3: 发送较长数据包
Serial.println("Test 3: Sending longer data packet");
const uint8_t longPacket[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
res = sendData(longPacket, sizeof(longPacket));
printResult("Long packet test", res);
delayAndCheck(3000);
// 测试4: 发送AT命令
Serial.println("Test 4: Sending AT command");
const char* atCommand = "AT\r\n";
res = sendData((const uint8_t*)atCommand, strlen(atCommand));
printResult("AT command test", res);
delayAndCheck(3000);
Serial.println("Device test completed.");
printTransferStats();
}
/**
* @brief 尝试发送打印机特定命令
*/
void tryPrinterSpecificCommands() {
Serial.println("尝试打印机特定命令...");
// 尝试标准打印机命令
const uint8_t printerCommands[][10] = {
{0x1B, 0x40}, // ESC @ - 初始化打印机
{0x1B, 0x64, 0x05}, // ESC d 5 - 打印并走纸5行
{0x0C}, // FF - 进纸到页首
{0x1B, 0x76, 0x00}, // ESC v 0 - 打印光栅位图(测试)
};
for (int i = 0; i < sizeof(printerCommands)/sizeof(printerCommands[0]); i++) {
Serial.printf("发送打印机命令 %d\n", i+1);
esp_err_t res = sendData(printerCommands[i], sizeof(printerCommands[i]));
printResult("打印机命令测试", res);
delayAndCheck(3000);
}
}
/**
* @brief 尝试CDC类设备命令
*/
void tryCDCCommands() {
Serial.println("尝试CDC设备命令...");
// 发送一些常见的串口命令
const char* cdcCommands[] = {
"\r\n", // 空行
"+++", // 进入命令模式(某些设备)
"AT\r", // 基本AT命令
"ATI\r", // 设备信息
"ATE1\r", // 开启回显
};
for (int i = 0; i < sizeof(cdcCommands)/sizeof(cdcCommands[0]); i++) {
Serial.printf("发送CDC命令: %s", cdcCommands[i]);
esp_err_t res = sendData((const uint8_t*)cdcCommands[i], strlen(cdcCommands[i]));
printResult("CDC命令测试", res);
delayAndCheck(3000);
}
}
/**
* @brief 尝试HID设备命令
*/
void tryHIDCommands() {
Serial.println("尝试HID设备命令...");
// HID设备标准命令 - 获取报告
const uint8_t getReport[] = {0xA1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
esp_err_t res = sendData(getReport, sizeof(getReport));
printResult("HID Get Report", res);
delayAndCheck(3000);
}
/**
* @brief 尝试存储设备命令
*/
void tryStorageCommands() {
Serial.println("尝试存储设备命令...");
// SCSI测试单元就绪命令
const uint8_t testUnitReady[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
esp_err_t res = sendData(testUnitReady, sizeof(testUnitReady));
printResult("SCSI Test Unit Ready", res);
delayAndCheck(3000);
}
/**
* @brief 发送厂商特定命令
*/
void tryVendorSpecificCommands() {
Serial.println("尝试厂商特定命令...");
// 发送一些常见的厂商命令模式
const uint8_t vendorCommands[][8] = {
{0x00}, // 空命令
{0xFF, 0xFF, 0xFF}, // 广播命令
{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 标准请求
};
for (int i = 0; i < sizeof(vendorCommands)/sizeof(vendorCommands[0]); i++) {
Serial.printf("发送厂商命令 %d\n", i+1);
esp_err_t res = sendData(vendorCommands[i], sizeof(vendorCommands[i]));
printResult("厂商命令测试", res);
delayAndCheck(3000);
}
}
/**
* @brief 打印测试结果
*/
void printResult(const char* testName, esp_err_t result) {
switch(result) {
case ESP_OK:
Serial.printf("%s: SUCCESS\n", testName);
break;
case ESP_ERR_TIMEOUT:
Serial.printf("%s: TIMEOUT - Device not responding\n", testName);
break;
case ESP_ERR_INVALID_ARG:
Serial.printf("%s: INVALID ARGUMENTS\n", testName);
break;
case ESP_ERR_NOT_FINISHED:
Serial.printf("%s: PREVIOUS TRANSFER PENDING\n", testName);
break;
case ESP_ERR_NOT_FOUND:
Serial.printf("%s: ENDPOINT NOT AVAILABLE\n", testName);
break;
default:
Serial.printf("%s: ERROR 0x%x\n", testName, result);
break;
}
}
/**
* @brief 延迟并检查传输状态
*/
void delayAndCheck(unsigned long ms) {
unsigned long start = millis();
while (millis() - start < ms) {
task(); // 继续处理USB任务
delay(10);
}
}
/**
* @brief 强制清除传输状态
*/
void forceClearTransferStatus() {
if (sendTransferPending) {
sendTransferPending = false;
sendTransferStartTime = 0;
transfersFailed++;
ESP_LOGW("EspUsbHostPrinter", "Force cleared transfer status");
}
}
/**
* @brief 打印传输统计信息
*/
void printTransferStats() {
Serial.printf("Transfer Stats - Submitted: %lu, Completed: %lu, Failed: %lu, Pending: %s\n",
transfersSubmitted, transfersCompleted, transfersFailed,
sendTransferPending ? "YES" : "NO");
ESP_LOGI("EspUsbHostPrinter", "Transfer Stats - Submitted: %lu, Completed: %lu, Failed: %lu, Pending: %s",
transfersSubmitted, transfersCompleted, transfersFailed,
sendTransferPending ? "YES" : "NO");
}
/**
* @brief 重置传输统计
*/
void resetTransferStats() {
transfersSubmitted = 0;
transfersCompleted = 0;
transfersFailed = 0;
}
/**
* @brief 检查设备是否已完全枚举
*/
bool isDeviceFullyEnumerated() {
return deviceInfoReceived && (inputEndpointAvailable || outputEndpointAvailable);
}
/**
* @brief 尝试重新枚举设备
*/
void tryReenumerate() {
if (!enumerationAttempted && deviceConnectedTime > 0) {
unsigned long timeSinceConnect = millis() - deviceConnectedTime;
if (timeSinceConnect > 5000) { // 连接5秒后仍未枚举
Serial.println("尝试重新枚举设备...");
enumerationAttempted = true;
// 这里可以添加重新枚举的逻辑,但在当前API下比较困难
}
}
}
};
EspUsbHostPrinter usbHost;
void setup() {
Serial.begin(115200);
Serial.println("USB Host Printer Test");
// 初始化 USB 主机
usbHost.begin();
}
void loop() {
usbHost.task();
if (!usbHost.isDeviceConnected()) {
static bool wasConnected = true;
if (wasConnected) {
Serial.println("USB设备断开连接");
usbHost.resetEndpoint();
usbHost.resetTransferStats();
wasConnected = false;
}
return;
} else {
static bool wasConnected = false;
if (!wasConnected) {
Serial.println("USB设备已连接");
wasConnected = true;
delay(1000);
usbHost.printFullDeviceInfo();
usbHost.analyzeDeviceType();
usbHost.checkReceiveStatus();
}
}
// 检查是否有接收到的数据并通过串口发送至电脑
if (usbHost.hasDataReceived()) {
uint8_t buffer[512];
size_t len = sizeof(buffer);
usbHost.getReceivedData(buffer, len);
if (len > 0) {
Serial.printf("[USB接收到数据] %d 字节:\n", len);
// 显示十六进制和ASCII格式
for (size_t i = 0; i < len; i++) {
if (i % 16 == 0) {
Serial.printf("\n%04X: ", (uint16_t)i);
}
Serial.printf("%02X ", buffer[i]);
}
Serial.println();
// 显示ASCII可打印字符
Serial.print("ASCII: ");
for (size_t i = 0; i < len; i++) {
if (buffer[i] >= 32 && buffer[i] <= 126) {
Serial.printf("%c", buffer[i]);
} else {
Serial.print(".");
}
}
Serial.println();
Serial.println("--- End of USB data ---");
}
} else {
// 定期检查接收状态
static unsigned long lastCheck = 0;
if (millis() - lastCheck > 10000) { // 每10秒检查一次
lastCheck = millis();
Serial.println("检查接收状态...");
usbHost.checkReceiveStatus();
}
// 检查是否需要重新枚举
usbHost.tryReenumerate();
}
static unsigned long lastSend = 0;
unsigned long currentMillis = millis();
if (currentMillis - lastSend > 30000) { // 增加到30秒间隔
lastSend = currentMillis;
if (!usbHost.outputEndpointAvailable) {
Serial.println("端点不可用 - 等待设备枚举");
usbHost.printFullDeviceInfo();
return;
}
Serial.println("=== 发送测试数据 ===");
// 检查设备是否完全枚举
if (!usbHost.isDeviceFullyEnumerated()) {
Serial.println("警告: 设备可能未完全枚举,跳过测试");
usbHost.printFullDeviceInfo();
usbHost.analyzeDeviceType();
} else {
// 根据设备类型运行不同的测试
if (usbHost.deviceClass == 0x07) {
// 打印机类设备
usbHost.tryPrinterSpecificCommands();
} else if (usbHost.deviceClass == 0x02 || usbHost.deviceClass == 0x0A) {
// CDC类设备
usbHost.tryCDCCommands();
} else if (usbHost.deviceClass == 0x03) {
// HID设备
usbHost.tryHIDCommands();
} else if (usbHost.deviceClass == 0x08) {
// 存储设备
usbHost.tryStorageCommands();
} else if (usbHost.deviceClass == 0xFF) {
// 厂商特定设备
usbHost.tryVendorSpecificCommands();
} else {
// 默认测试
usbHost.testDevice();
}
}
// 分析设备类型
usbHost.analyzeDeviceType();
// 每次测试后强制清除传输状态,防止挂起
usbHost.forceClearTransferStatus();
Serial.println("==================");
}
}这个程序能发送但不能接收USB数据
最新发布