Skip to main content
Visitor II
June 14, 2025
Question

USB HID Get Report Callback data is different from Bus Hound sniff data

  • June 14, 2025
  • 5 replies
  • 1322 views

Hi,

I would like to consult the USB HID GetReport feature.
The issue is that the printout data from MCU log is different from bus hound displayed result.

Bus hound is trial version, the data length indeed is 16.

CYH_0-1749920225104.png

This is the log I set to printout from USBD_HID_Keyboard_SetReport

CYH_2-1749920268498.png

#define UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH 32
static uint8_t g_last_input_report[17]; // adjust size to match your report
static UINT g_last_input_report_len = 0;

/**
 * @brief USBD_HID_Keyboard_GetReport
 * This function is invoked when host is requesting event through
 * control GET_REPORT request.
 * hid_instance: Pointer to the hid class instance.
 * hid_event: Pointer to structure of the hid event.
 * @retval status
 */
UINT USBD_HID_Keyboard_GetReport(UX_SLAVE_CLASS_HID *hid_instance,
		UX_SLAVE_CLASS_HID_EVENT *hid_event) {
	printf(">>> USBD_HID_Keyboard_GetReport invoked\r\n");

	static uint32_t get_report_counter = 0;
	printf("=== GET_REPORT #%lu at %lu ms ===\r\n", ++get_report_counter, HAL_GetTick());

	if (hid_event == UX_NULL || g_last_input_report_len == 0)
		return UX_ERROR;

	//Type1:Input ;; Type3:Feature
	printf(">>> GetReport Request: type=%lu, id=0x%02lX\r\n, Buffer len: %lu\r\n",
			hid_event->ux_device_class_hid_event_report_type,
			hid_event->ux_device_class_hid_event_report_id,
			g_last_input_report_len);

	if (hid_event->ux_device_class_hid_event_report_id== 0x01&&
	 hid_event->ux_device_class_hid_event_report_type == UX_DEVICE_CLASS_HID_REPORT_TYPE_INPUT)
	{
		if (g_last_input_report_len <= UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH) {
			memcpy(hid_event->ux_device_class_hid_event_buffer,
					g_last_input_report, g_last_input_report_len);
			hid_event->ux_device_class_hid_event_length =
					g_last_input_report_len;

			printf("GetReport:");
			for (UINT i = 0; i < g_last_input_report_len; i++) {
				printf("%02X,", g_last_input_report[i]);
			}
			printf("\r\n");
			return UX_SUCCESS;
		}
	}
	printf("ERROR: Conditions not met, returning UX_ERROR\r\n");
	return UX_ERROR;
}

Also add the log in _ux_device_class_hid_report_get

CYH_3-1749920634381.png

However, in here is still show the different data from bus hound capture though it is still aligned the data in GetReport Callback.

 

The HID descriptor is set as below

__ALIGN_BEGIN uint8_t USBD_HID_KEYBOARD_ReportDesc[]
__ALIGN_END =
{
 /* USER CODE BEGIN USBD_HID_KEYBOARD_ReportDesc */
 //Wedy Change for customized report
 0x06, 0x00, 0xFF, // USAGE PAGE (Vendor Defined)
 0x09, 0xFF, // USAGE (Vendor Usage)
 0xA1, 0x01, // COLLECTION (Application)

 // Feature Report - Report ID 1
 0x85, 0x01, // REPORT_ID (1)
 0x15, 0x00, // LOGICAL_MINIMUM (0)
 0x25, 0xFF, // LOGICAL_MAXIMUM (255)
 0x75, 0x08, // REPORT_SIZE (8)
 0x95, 0x10, // REPORT_COUNT (16)
 0x09, 0x01, // USAGE (Vendor Specific)
 0x81, 0x02, // INPUT (Data,Var,Abs)

 // Feature Report - Report ID 1 (16 bytes)
 0x85, 0x01, // REPORT_ID (1)
 0x95, 0x10, // REPORT_COUNT (16)
 0x09, 0x02, // USAGE (Vendor Specific)
 0xB1, 0x02, // FEATURE (Data,Var,Abs)

 // Output Report - Report ID 2
 0x85, 0x02, // REPORT_ID (2)
 0x95, 0x11, // REPORT_COUNT (17)
 0x09, 0x01, // USAGE (Vendor Specific)
 0x91, 0x02, // OUTPUT (Data,Var,Abs)
 /* USER CODE END USBD_HID_KEYBOARD_ReportDesc */
 0xc0 /* End Collection */
};

 

    This topic has been closed for replies.

    5 replies

    Technical Moderator
    June 16, 2025

    Hi @CYH 

    Which STM32U0 are you using? Would you attach minimum firmware to replicate the issue on a reference board?

    CYHAuthor
    Visitor II
    June 16, 2025

    Hi @FBL ,

    Thank you for your reply.
    I am using STM32U083C-DK as test platform but with STM32U083HCY6 pin configuration.

    The minimum firmware you are saying is the source code, right?
    Please kindly check the attach files as your reference.

    int main(void)
    {
    
     /* USER CODE BEGIN 1 */
    
     /* USER CODE END 1 */
    
     /* MCU Configuration--------------------------------------------------------*/
    
     /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
     HAL_Init();
    
     /* USER CODE BEGIN Init */
    
     /* USER CODE END Init */
    
     /* Configure the system clock */
     SystemClock_Config();
    
     /* USER CODE BEGIN SysInit */
    
     /* USER CODE END SysInit */
    
     /* Initialize all configured peripherals */
     MX_GPIO_Init();
     MX_USBX_Device_Init();
     MX_USART2_UART_Init();
     /* USER CODE BEGIN 2 */
    
     /* USER CODE END 2 */
    
     /* Infinite loop */
     /* USER CODE BEGIN WHILE */
     while (1)
     {
     /* USER CODE END WHILE */
    
     /* USER CODE BEGIN 3 */
    	 //Set up the device descriptor
    	 USBX_Device_Process(NULL);
     }
     /* USER CODE END 3 */
    }

     

    Technical Moderator
    June 16, 2025

    Hi @CYH 

    Here are some suggestions :

    First, ensure buffer alignment in USBD_HID_Keyboard_SendReport to prevent unaligned memory access

    uint8_t full_report[1 + 15] __attribute__((aligned(8)));

    Second, before copying g_last_input_report into the hid_event buffer, ensure the buffer size does not exceed the allowed limit in USBD_HID_Keyboard_GetReport

    if (g_last_input_report_len > UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH) {
     printf("Error: Buffer overflow detected\r\n");
     return UX_ERROR;
    }

    In USBD_HID_Keyboard_SetReport, verify the size of the data being copied into g_output_report_buffer to ensure it does not exceed the maximum allowed size:

    if (data_len > MAX_HID_OUTPUT_REPORT_SIZE) {
     printf("Error: Output report too large\r\n");
     return UX_ERROR;
    }

     

    CYHAuthor
    Visitor II
    June 17, 2025

    Hi @FBL ,

    Thank you for your suggestion.

    However, after modification the result still failed.

    CYH_0-1750124466000.png

    As the image show above, I found that even I didn't set g_last_input_report for GetReport, there still have data be reported whenever host try to get report from ID 1, and the value seems could be changed randomly.
    Besides that, I found that after I set the g_last_input_report which expected to be 01 D4........, though the reported data is not expected, but the value seems keep the same each time.

    Not sure whether it is any hint for you to help with the analysis.

    Technical Moderator
    June 18, 2025

    Hi @CYH  

    Here some suggestions:

    • Implement software debouncing (e.g., require stable button state for 20-50 ms).
    • Send a zeroed report immediately after key press to simulate key release to avoid data reported continuously.

     

     

    VOID USBX_DEVICE_HID_CUSTOMER_Task(VOID) {
     static ULONG last_tick = 0;
     ULONG current_tick;
     UX_SLAVE_DEVICE *device;
     UX_SLAVE_CLASS_HID_EVENT hid_event;
    
     device = &_ux_system_slave->ux_system_slave_device;
     ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT));
    
     current_tick = HAL_GetTick();
    
     if ((device->ux_slave_device_state == UX_DEVICE_CONFIGURED) && (hid_keyboard != UX_NULL))
     {
     if (ux_utility_time_elapsed(last_tick, current_tick) < BUTTON_DETECT_WAIT)
     {
     return; // Wait for debounce period
     }
    
     last_tick = current_tick;
    
     if (User_Button_State) // Button pressed (edge detection recommended)
     {
     GetKeyData(&hid_event); // Fill HID report for key press
    
     if (ux_device_class_hid_event_set(hid_keyboard, &hid_event) == UX_SUCCESS)
     {
     // Prepare key release report (all zeros)
     memset(hid_event.ux_device_class_hid_event_buffer, 0, hid_event.ux_device_class_hid_event_length);
     ux_device_class_hid_event_set(hid_keyboard, &hid_event);
    
     User_Button_State = 0U; // Reset button state after event sent
     }
     else
     {
     // Handle error (optional)
     }
     }
     }
    }

     

    CYHAuthor
    Visitor II
    July 2, 2025

    Hi @FBL ,

    Not sure whether you have ont other suggestion?

    #define MAX_HID_OUTPUT_REPORT_SIZE 17
    #define HID_REPORT_TOTAL_SIZE 17 // 1 ID + 16 payload
    static uint8_t g_output_report_buffer[MAX_HID_OUTPUT_REPORT_SIZE];
    static UINT g_output_report_length = 0;
    static uint8_t g_output_report_ready = 0;
    static uint8_t g_last_input_report[17]__attribute__((aligned(8)));;
    static UINT g_last_input_report_len = 0;
    
    __ALIGN_BEGIN uint8_t USBD_HID_KEYBOARD_ReportDesc[]
    __ALIGN_END =
    {
     /* USER CODE BEGIN USBD_HID_KEYBOARD_ReportDesc */
     //CY Change for customized report
     0x06, 0x00, 0xFF, // USAGE PAGE (Vendor Defined)
     0x09, 0xFF, // USAGE (Vendor Usage)
     0xA1, 0x01, // COLLECTION (Application)
    
     // Feature Report - Report ID 1
     0x85, 0x01, // REPORT_ID (1)
     0x15, 0x00, // LOGICAL_MINIMUM (0)
     0x25, 0xFF, // LOGICAL_MAXIMUM (255)
     0x75, 0x08, // REPORT_SIZE (8)
     0x95, 0x10, // REPORT_COUNT (16)
     0x09, 0x01, // USAGE (Vendor Specific)
     0x81, 0x02, // INPUT (Data,Var,Abs)
    
     // Feature Report - Report ID 1 (16 bytes)
     0x85, 0x01, // REPORT_ID (1)
     0x95, 0x10, // REPORT_COUNT (16)
     0x09, 0x02, // USAGE (Vendor Specific)
     0xB1, 0x02, // FEATURE (Data,Var,Abs)
    
     // Output Report - Report ID 2
     0x85, 0x02, // REPORT_ID (2)
     0x95, 0x11, // REPORT_COUNT (17)
     0x09, 0x01, // USAGE (Vendor Specific)
     0x91, 0x02, // OUTPUT (Data,Var,Abs)
     /* USER CODE END USBD_HID_KEYBOARD_ReportDesc */
     0xc0 /* End Collection */
    };
    
    UINT USBD_HID_Keyboard_GetReport(UX_SLAVE_CLASS_HID *hid_instance,
    		UX_SLAVE_CLASS_HID_EVENT *hid_event) {
    
    	/* USER CODE BEGIN USBD_HID_Keyboard_GetReport */
     static uint32_t get_report_counter = 0;
     static uint32_t last_logged_report_counter = 0;
    
     uint32_t current_counter = ++get_report_counter;
     printf("\r\n=== [GET_REPORT #%lu] === @ %lu ms ===\r\n", current_counter, HAL_GetTick());
    
     if (hid_event == UX_NULL || g_last_input_report_len == 0) {
     if (hid_event != UX_NULL) {
     memset(hid_event->ux_device_class_hid_event_buffer, 0, HID_REPORT_TOTAL_SIZE);
     hid_event->ux_device_class_hid_event_length = HID_REPORT_TOTAL_SIZE;
     }
     printf("GetReport ERROR: No data available\r\n");
     return UX_SUCCESS;
     }
    
     printf("Report Type: %lu, Report ID: 0x%02lX, Length: %lu\r\n",
     hid_event->ux_device_class_hid_event_report_type,
     hid_event->ux_device_class_hid_event_report_id,
     g_last_input_report_len);
    
     if (hid_event->ux_device_class_hid_event_report_id == 0x01 &&
     hid_event->ux_device_class_hid_event_report_type == UX_DEVICE_CLASS_HID_REPORT_TYPE_INPUT) {
    
     memcpy(hid_event->ux_device_class_hid_event_buffer,
     g_last_input_report, g_last_input_report_len);
     hid_event->ux_device_class_hid_event_length = g_last_input_report_len;
    
     printf("Final length set = %lu\r\n", hid_event->ux_device_class_hid_event_length);
    
     printf("Report Data: ");
     for (UINT i = 0; i < g_last_input_report_len; i++) {
     printf("%02X ", g_last_input_report[i]);
     }
     printf("\r\n");
    
     // Only log "USBX sending to host" once per report sequence
     if (current_counter != last_logged_report_counter) {
     last_logged_report_counter = current_counter;
     printf("USBX sending to host: ");
     for (UINT i = 0; i < hid_event->ux_device_class_hid_event_length; i++) {
     printf("%02X ", hid_event->ux_device_class_hid_event_buffer[i]);
     }
     printf("\r\n");
     }
    
     return UX_SUCCESS;
     }
    
     printf("ERROR: Report type/id mismatch or unsupported\r\n");
     return UX_ERROR;
     /* USER CODE END USBD_HID_Keyboard_GetReport */
    }

    I have modified and add more log info inside the GetReport.

    However, the data stil show different from bushound.

    CYH_0-1751444109583.png

    CYH_2-1751444140863.png

     

    Technical Moderator
    July 2, 2025

    Hi @CYH 

    If you are using legacy keyboard, check the report descriptor from this article. Otherwise, for custom keyboard use case, make sure to use the right report descriptor.

    CYHAuthor
    Visitor II
    July 2, 2025

    Hi @FBL ,

    I am using STM32U083 for develpment and the library seems a little bit different from the one you shared.
    My file structure is shown as below, I am not sure whether I am using legacy or custom keyborad.

    I only enable the HID Core and HID Keyboard in .ioc, and modify the keyboard descriptor to the one I provided in previous message.

    CYH_0-1751448702590.png

     

    CYHAuthor
    Visitor II
    July 3, 2025

    Hi @FBL ,
    I found that if I don't proceed _ux_device_class_hid_event_set() inside Keyboard_SendReport as below makred, then I could get the matched data from GetReport.

    UINT USBD_HID_Keyboard_GetReport(UX_SLAVE_CLASS_HID *hid_instance,
    		UX_SLAVE_CLASS_HID_EVENT *hid_event) {
    
    	/* USER CODE BEGIN USBD_HID_Keyboard_GetReport */
     printf("\r\n=== [GET_REPORT] ===\r\n");
    
     if (hid_event == UX_NULL || g_last_input_report_len == 0) {
     if (hid_event != UX_NULL) {
     memset(hid_event->ux_device_class_hid_event_buffer, 0, HID_REPORT_TOTAL_SIZE);
     hid_event->ux_device_class_hid_event_length = HID_REPORT_TOTAL_SIZE;
     }
     printf("GetReport ERROR: No data available\r\n");
     return UX_SUCCESS;
     }
    
     if (hid_event->ux_device_class_hid_event_report_id == 0x01 &&
     hid_event->ux_device_class_hid_event_report_type == UX_DEVICE_CLASS_HID_REPORT_TYPE_INPUT) {
    
     memcpy(hid_event->ux_device_class_hid_event_buffer,
     g_last_input_report, HID_REPORT_TOTAL_SIZE);
     hid_event->ux_device_class_hid_event_length = g_last_input_report_len;
    
     printf("Final length set = %lu\r\n", hid_event->ux_device_class_hid_event_length);
    
     printf("USBX sending to host: ");
     for (UINT i = 0; i < hid_event->ux_device_class_hid_event_length; i++) {
     printf("%02X ", hid_event->ux_device_class_hid_event_buffer[i]);
     }
     printf("\r\n");
    
     return UX_SUCCESS;
     }
    
     printf("ERROR: Report type/id mismatch or unsupported\r\n");
     return UX_ERROR;
     /* USER CODE END USBD_HID_Keyboard_GetReport */
    }
    
    /* USER CODE BEGIN 1 */
    ///////////////////HID_INPUT_to_HOST//////////////////////
    UINT USBD_HID_Keyboard_SendReport(UX_SLAVE_CLASS_HID *hid_instance, uint8_t *report, UINT length)
    {
    	if (hid_instance == UX_NULL || report == UX_NULL || length == 0)
    		return UX_ERROR;
    
    	if (length > HID_REPORT_TOTAL_SIZE) {
    	 printf("Error: Output report too large\r\n");
    	 return UX_ERROR;
    	}
    
    	full_report[0] = 0x01; // Report ID
    	memcpy(&full_report[1], report, length);
    
    	// Store for GetReport
    	memcpy(g_last_input_report, full_report, HID_REPORT_TOTAL_SIZE);
    	g_last_input_report_len = HID_REPORT_TOTAL_SIZE;
    
    	printf("GetReport prepared (Report ID 0x01): ");
    	for (UINT i = 0; i < g_last_input_report_len; i++) {
    	 printf("%02X ", g_last_input_report[i]);
    	}
    	printf("\r\n");
    
    	// Do NOT call _ux_device_class_hid_event_set() here if need to support GetReport instead of OutputReport
    	/*UX_SLAVE_CLASS_HID_EVENT hid_event;
    	hid_event.ux_device_class_hid_event_report_id = 0x01;
    	hid_event.ux_device_class_hid_event_report_type =
    			UX_DEVICE_CLASS_HID_REPORT_TYPE_INPUT;
    	hid_event.ux_device_class_hid_event_length = sizeof(full_report)-1;
    	memcpy(hid_event.ux_device_class_hid_event_buffer, full_report,
    			sizeof(full_report)-1);
    
    	printf("Input report to host: ");
    	for (UINT i = 0; i < sizeof(full_report)-1; i++) {
    		printf("%02X ", full_report[i]);
    	}
    	printf("\r\n");
    
    	ux_device_class_hid_event_set(hid_instance, &hid_event);*/
    
    	return UX_SUCCESS;
    }

     Does it sounds reasonable? Is that expected to not have input report while system would like to proceed GetReport?