Open tankyx opened 3 months ago
I tried your exact code, with the exception that I do not have PAW3370
, so instead my main sketch looks like:
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
hid.begin();
USB.begin();
pinMode(0, INPUT_PULLUP);
}
void loop() {
static bool btn = digitalRead(0);
bool btn_now = digitalRead(0);
if(btn != btn_now){
btn = btn_now;
if(!btn_now){
Mouse16.click(1);
}
}
delay(10);
}
Mouse works fine on my computer and I can see both devices in the USB tool I have. Main difference is that I am on a Mac and have no idea what things look like on Windows. Code looks fine and works fine, except you should not call customHID.receiveReport
yourself. That will be called once the host sends data to the device.
Indeed, I tried on both MBP M1 and MBP M3 and it was working without any issues, with both devices showing up. Probably some windows shenanigans happening. Could you please investigate ?
I can't. I do not have a windows machine and the colleague that does just went out on a month long leave... One suggestion for you is to set the USB mode in the board menu to TinyUSB (I saw in the logs it was the default USB/JTAG selected)
Yeah I have done that :
USB Mode to USB-OTG (TinyUSB) Upload mode UART0/Hardware CDC
I dont really understand why Windows is not allowing the Arduino to work as intended
Maybe it does not like something in the vendor descriptor? Can you try with a standard TinyUSB one? https://github.com/espressif/arduino-esp32/blob/master/libraries/USB/examples/HIDVendor/HIDVendor.ino
On Windows I have the following output :
[ 890][E][USBHID.cpp:347] SendReport(): not ready
[ 894][E][USBHID.cpp:347] SendReport(): not ready
[ 899][E][USBHID.cpp:347] SendReport(): not ready
[ 904][E][USBHID.cpp:347] SendReport(): not ready
[ 908][E][USBHID.cpp:347] SendReport(): not ready
[ 913][E][USBHID.cpp:347] SendReport(): not ready
[ 918][E][USBHID.cpp:347] SendReport(): not ready
[ 922][E][USBHID.cpp:347] SendReport(): not ready
[ 927][E][USBHID.cpp:347] SendReport(): not ready
[ 931][E][USBHID.cpp:347] SendReport(): not ready
[ 936][E][USBHID.cpp:347] SendReport(): not ready
[ 941][E][USBHID.cpp:347] SendReport(): not ready
[ 945][E][USBHID.cpp:347] SendReport(): not ready
[ 950][E][USBHID.cpp:347] SendReport(): not ready
[ 955][E][USBHID.cpp:347] SendReport(): not ready
[ 959][E][USBHID.cpp:347] SendReport(): not ready
[ 964][E][USBHID.cpp:347] SendReport(): not ready
[ 969][E][USBHID.cpp:347] SendReport(): not ready
[ 973][E][USBHID.cpp:347] SendReport(): not ready
[ 978][V][USBHID.cpp:240] tud_hid_set_idle_cb(): instance: 0, idle_rate:0
[ 987][V][USBHID.cpp:219] tud_hid_descriptor_report_cb(): instance: 0
[ 993][D][USBHID.cpp:176] tinyusb_load_enabled_hid_devices(): Loaded HID Descriptor with the following reports:
[ 1004][D][USBHID.cpp:179] tinyusb_load_enabled_hid_devices(): ID: 6, Type: INPUT, Size: 63, Usage: VENDOR
[ 1014][D][USBHID.cpp:179] tinyusb_load_enabled_hid_devices(): ID: 6, Type: OUTPUT, Size: 63, Usage: VENDOR
[ 1024][D][USBHID.cpp:179] tinyusb_load_enabled_hid_devices(): ID: 6, Type: FEATURE, Size: 63, Usage: VENDOR
And I can see it being plugged in as a USB Input Device with device type HID (Human Interface Device). Should I use that standard HIDVendor in my code ?
I added the standard HIDVendor device to my code, I still get the issue on Windows. Not on MacOS though
#include "Mouse16.h"
#include "CustomHIDDevice.h"
#include "PAW3370.h"
#include "USBHIDVendor.h"
USBHIDRelativeMouse16 Mouse16;
//USBHIDCustomDevice customHID;
USBHIDVendor Vendor;
PAW3370 sensor;
static void vendorEventCallback(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
if (event_base == ARDUINO_USB_HID_VENDOR_EVENTS) {
arduino_usb_hid_vendor_event_data_t *data = (arduino_usb_hid_vendor_event_data_t *)event_data;
switch (event_id) {
case ARDUINO_USB_HID_VENDOR_GET_FEATURE_EVENT: Serial.printf("HID VENDOR GET FEATURE: len:%u\n", data->len); break;
case ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT:
Serial.printf("HID VENDOR SET FEATURE: len:%u\n", data->len);
for (uint16_t i = 0; i < data->len; i++) {
Serial.printf("0x%02X ", *(data->buffer));
}
Serial.println();
break;
case ARDUINO_USB_HID_VENDOR_OUTPUT_EVENT:
Serial.printf("HID VENDOR OUTPUT: len:%u\n", data->len);
for (uint16_t i = 0; i < data->len; i++) {
Serial.printf("0x%02X ", *(data->buffer));
}
break;
default: break;
}
}
}
void setup() {
Serial.begin(115200);
SPI.begin(PIN_CLK, PIN_MISO, PIN_MOSI, PIN_CS);
if (!sensor.init()) {
Serial.println("Failed to initialize PAW3370");
while (1);
}
Vendor.onEvent(vendorEventCallback);
Mouse16.begin();
Vendor.begin();
USB.begin();
}
void loop() {
int16_t delta_x, delta_y;
if (!sensor.read_motion(&delta_x, &delta_y)) {
Serial.println("Failed to read motion data");
}
if (delta_x != 0 || delta_y != 0) {
Mouse16.move(delta_x, delta_y, 0, 0);
}
if (Vendor.available()) {
Vendor.read();
}
}
@me-no-dev Couple of updates on the matter :
That means that Windows does not like something in your vendor descriptor. I wonder what... what is different from the default one?
I don't really know to be fair. Now I have the custom device showing up, but I can't communicate with it.
#pragma once
#include <USB.h>
#include <USBHID.h>
#include "Mouse16.h"
#define HID_VENDOR_REPORT_SIZE 64
static const uint8_t report_descriptor[] = {
0x06, 0x00, 0xff, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x01, // Usage (Vendor Usage 0x01)
0xa1, 0x01, // Collection (Application)
0x85, 0x06, // Report ID (6)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xff, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8 bits)
0x95, 0x01, // Report Count (1)
0x09, 0x01, // Usage (Vendor Usage 0x01)
0x81, 0x02, // Input (Data, Var, Abs)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xff, 0x7f, // Logical Maximum (32767)
0x75, 0x10, // Report Size (16 bits)
0x95, 0x02, // Report Count (2)
0x09, 0x02, // Usage (Vendor Usage 0x02)
0x09, 0x03, // Usage (Vendor Usage 0x03)
0x81, 0x02, // Input (Data, Var, Abs)
0x75, 0x08, // Report Size (8 bits)
0x95, 0x39, // Report Count (57)
0x09, 0x04, // Usage (Vendor Usage 0x04)
0x81, 0x02, // Input (Data, Var, Abs)
0xc0 // End Collection
};
struct HIDReport {
uint8_t reportId;
int16_t dx;
int16_t dy;
uint8_t padding[57];
};
class USBHIDCustomDevice : public USBHIDDevice {
private:
USBHID _hid;
USBHIDRelativeMouse16 _mouse;
public:
USBHIDCustomDevice(USBHIDRelativeMouse16& mouse) : _hid() {
static bool initialized = false;
if (!initialized) {
initialized = true;
_hid.addDevice(this, sizeof(report_descriptor));
}
_mouse = mouse;
}
void begin() {
_hid.begin();
}
uint16_t _onGetDescriptor(uint8_t *dst) {
memcpy(dst, report_descriptor, sizeof(report_descriptor));
return sizeof(report_descriptor);
}
void receiveReport(const uint8_t* data, size_t length) {
int16_t dx = (int16_t)(data[1] | (data[2] << 8));
int16_t dy = (int16_t)(data[3] | (data[4] << 8));
_mouse.move(dx, dy, 0, 0);
}
void _onSetFeature(uint8_t report_id, const uint8_t *buffer, uint16_t len) {
receiveReport(buffer, len);
}
void _onOutput(uint8_t *report, size_t len) {
receiveReport(report, len);
}
};
#pragma once
#include <USB.h>
#include <USBHID.h>
#define TUD_HID_REPORT_DESC_MOUSE16(...) \
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
/* Report ID if any */\
__VA_ARGS__ \
HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
HID_USAGE_MIN ( 1 ) ,\
HID_USAGE_MAX ( 5 ) ,\
HID_LOGICAL_MIN ( 0 ) ,\
HID_LOGICAL_MAX ( 1 ) ,\
/* Left, Right, Middle, Backward, Forward buttons */ \
HID_REPORT_COUNT( 5 ) ,\
HID_REPORT_SIZE ( 1 ) ,\
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
/* 3 bit padding */ \
HID_REPORT_COUNT( 1 ) ,\
HID_REPORT_SIZE ( 3 ) ,\
HID_INPUT ( HID_CONSTANT ) ,\
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
/* X, Y position [-32767, 32767] */ \
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
HID_LOGICAL_MIN_N ( 0x8001, 2 ) ,\
HID_LOGICAL_MAX_N ( 0x7fff, 2 ) ,\
HID_REPORT_COUNT( 2 ) ,\
HID_REPORT_SIZE ( 16 ) ,\
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
/* Verital wheel scroll [-127, 127] */ \
HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\
HID_LOGICAL_MIN ( 0x81 ) ,\
HID_LOGICAL_MAX ( 0x7f ) ,\
HID_REPORT_COUNT( 1 ) ,\
HID_REPORT_SIZE ( 8 ) ,\
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \
/* Horizontal wheel scroll [-127, 127] */ \
HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \
HID_LOGICAL_MIN ( 0x81 ), \
HID_LOGICAL_MAX ( 0x7f ), \
HID_REPORT_COUNT( 1 ), \
HID_REPORT_SIZE ( 8 ), \
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \
HID_COLLECTION_END , \
HID_COLLECTION_END
static const uint8_t rel16_mouse_report_descriptor[] = {
TUD_HID_REPORT_DESC_MOUSE16(HID_REPORT_ID(HID_REPORT_ID_MOUSE))
};
enum MousePositioning_t {
HID_MOUSE_RELATIVE,
HID_MOUSE_ABSOLUTE
};
typedef struct TU_ATTR_PACKED
{
uint8_t buttons;
int16_t x;
int16_t y;
int8_t wheel;
int8_t pan;
} hid_mouse_report_16_t;
struct HIDMouseType_t {
MousePositioning_t positioning;
const uint8_t *report_descriptor;
size_t descriptor_size;
size_t report_size;
};
HIDMouseType_t HIDMouseRel16 = { HID_MOUSE_RELATIVE, rel16_mouse_report_descriptor, sizeof(rel16_mouse_report_descriptor), sizeof(hid_mouse_report_16_t) };
class USBHIDRelativeMouse16 : public USBHIDDevice {
private:
USBHID _hid;
uint8_t _buttons;
public:
USBHIDRelativeMouse16() : _hid() {
static bool initialized = false;
if (!initialized) {
initialized = true;
_hid.addDevice(this, HIDMouseRel16.descriptor_size);
}
}
void begin() {
_hid.begin();
}
uint16_t _onGetDescriptor(uint8_t *dst) {
memcpy(dst, HIDMouseRel16.report_descriptor, HIDMouseRel16.descriptor_size);
return HIDMouseRel16.descriptor_size;
}
void move(int16_t x, int16_t y, int8_t wheel = 0, int8_t pan = 0) {
hid_mouse_report_16_t report = {
.buttons = _buttons,
.x = x,
.y = y,
.wheel = wheel,
.pan = pan
};
Serial.printf("Sending x = %d | y = %d\n", x, y);
_hid.SendReport(HID_REPORT_ID_MOUSE, &report, sizeof(hid_mouse_report_16_t));
}
void click(uint8_t b) {
_buttons = b;
move(0,0);
_buttons = 0;
move(0,0);
}
void buttons(uint8_t b) {
if (b != _buttons) {
_buttons = b;
move(0,0);
}
}
};
This is the definition of my two devices.
Following is my host code :
void MouseController::sendHIDReport(int16_t dx, int16_t dy) {
HIDReport report;
std::cout << "Sending HID report: " << dx << " " << dy << std::endl;
report.reportId = 0x06; // Use HID_REPORT_ID_VENDOR = 0x06
report.dx = dx;
report.dy = dy;
memset(report.padding, 0, sizeof(report.padding));
DWORD bytesWritten;
std::cout << "Size of report: " << sizeof(report) << std::endl;
//BOOL res = WriteFile(hidDevice, &report, sizeof(report), &bytesWritten, NULL);
BOOL res = HidD_SetOutputReport(hidDevice, &report, sizeof(report));
if (!res) {
int err = GetLastError();
std::cerr << "Failed to send HID report: " << err << std::endl;
if (err == 995 || err == 1167) {
std::cerr << "Device disconnected" << std::endl;
CloseHandle(hidDevice);
hidDevice = nullptr;
Sleep(2000); // Wait for device to reconnect
ConnectToDevice();
} else {
exit(1);
}
} else {
std::cout << "HID report sent successfully: " << dx << " " << dy << std::endl;
}
}
It seems also that my device reboots when it receives too much data for too long
Not sure if this is related, but I do have trouble using CDC and HID simultaneously. After some time, one or the other seems to stall, see https://github.com/espressif/arduino-esp32/issues/9582#issuecomment-2096691001.
BR
Board
ESP32S3
Device Description
DevkitM1, plain board, both USB ports connected to host
Hardware Configuration
Optical sensor connected to GPIO21, GPIO38, GPIO47, GPIO48, GND and 3v3
Version
latest master (checkout manually)
IDE Name
Arduino IDE 2.3.2
Operating System
Windows 10
Flash frequency
80MHz
PSRAM enabled
no
Upload speed
921600
Description
I am implementing an optical sensor using the USBHID.h library. It works well and I am able to send movements to the host. As soon as I instantiate a Custom HID device, the host won't receive the movements (I don't know if it is the board not sending or the host not receiving).
Sketch
Debug Message
Other Steps to Reproduce
I can see the following error in USBLogView Device Description
Unknown USB Device (Device Descriptor Request Failed)
I have checked existing issues, online documentation and the Troubleshooting Guide