Skip to main content
August 13, 2020
Solved

[USB Host] Keyboard Output Report - How to control the 3 LEDs? (NumLock, Caps Lock and Scroll Lock status)

  • August 13, 2020
  • 12 replies
  • 6998 views

Could anyone tell how to add this functionality in the USB Host library for STM32CubeIDE?

I found this:

u8 c=3;
 
USBH_StatusTypeDef res = USBH_BUSY;
 
do {
res=USBH_Set_Report(&USB_OTG_Host_Hnd,&USB_Host,0x02,0x00,0x01,&c);
} while(res != USBH_OK);

Source: https://community.st.com/s/question/0D50X00009XkZ11/caps-lock-led-turn-onoff

I didn't find this function (USBH_Set_Report) in the library, I found only USBH_HID_SetReport, but I couldn't implement that.

Is there any ST document that talks about this?

I found a document written by Microchip:

A standard keyboard has three LEDs to display NumLock, Caps Lock and Scroll Lock status. The LEDs are absolute output items; the state of each LED must be included in the output reports (0 = OFF, 1 = ON)

Source: http://ww1.microchip.com/downloads/en/AppNotes/01212a.pdf

This topic has been closed for replies.
Best answer by

Okay, that worked for me, maybe there's a better way to do it, but I have other things going on:

usb_host.c:

uint32_t keyboardMain_debounce = 0;
HID_KEYBD_Info_TypeDef *keybd_info1;
 
uint8_t kbd_LED_status[1] = { 0B001 }; // kbd_num_lock_state = 1
uint8_t kbd_LED_status_old = 0;
 
uint8_t kbd_num_lock_state = 1;
uint8_t caps_lock_state = 0;
uint8_t kbd_scroll_lock_state = 0;
 
void USBH_HID_EventCallback(USBH_HandleTypeDef *phost) {
	HID_HandleTypeDef *HID_Handle =
			(HID_HandleTypeDef*) phost->pActiveClass->pData;
	if (HID_Handle->Init == USBH_HID_KeybdInit) {
		keybd_info1 = USBH_HID_GetKeybdInfo(phost);
 
		USBH_DbgLog("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
				keybd_info1->keys[0], keybd_info1->keys[1],
				keybd_info1->keys[2], keybd_info1->keys[3],
				keybd_info1->keys[4], keybd_info1->keys[5]); // USBH_DbgLog
 
		if (HAL_GetTick() > (keyboardMain_debounce + 100)) {
			keyboardMain_debounce = HAL_GetTick();
 
			uint8_t key = keybd_info1->keys[0];
 
			if (key == KEY_INSERT) {
				keyboard_insert = !keyboard_insert;
			} else if (key == KEY_KEYPAD_NUM_LOCK_AND_CLEAR) {
				if ((kbd_LED_status[0] & 1) == 0) {
					kbd_LED_status[0] |= 0B001;
				} else {
					kbd_LED_status[0] &= 0B110;
				}
			} else if (key == KEY_CAPS_LOCK) {
				if (((kbd_LED_status[0] >> 1) & 1) == 0) {
					kbd_LED_status[0] |= 0B010;
				} else {
					kbd_LED_status[0] &= 0B101;
				}
			} else if (key == KEY_SCROLL_LOCK) {
				if (((kbd_LED_status[0] >> 2) & 1) == 0) {
					kbd_LED_status[0] |= 0B100;
				} else {
					kbd_LED_status[0] &= 0B011;
				}
			}
		}
 
	} else if (HID_Handle->Init == USBH_HID_MouseInit) {
		USBH_HID_GetMouseInfo(phost);
 
		USBH_DbgLog(
				"Mouse action: x= 0x%x, y= 0x%x, button1 = 0x%x, button2 = 0x%x, button3 = 0x%x \n",
				mouse_info.x, mouse_info.y, mouse_info.buttons[0],
				mouse_info.buttons[1], mouse_info.buttons[2]);
	}
}

usb_host.c:

/* USER CODE BEGIN 1 */
USBH_StatusTypeDef USB_Set_Keyboard_LED_Status(uint8_t *LED_status) {
	if (kbd_LED_status_old == kbd_LED_status[0]) {
		return HAL_OK;
	}
 
	kbd_LED_status_old = LED_status[0];
 
	uint8_t kbd_led[2] = { 0x00, 0x00 };
 
	USBH_StatusTypeDef ret = HAL_BUSY;
	USBH_StatusTypeDef ret2 = HAL_OK;
 
	kbd_led[0] = LED_status[0] & 7;
 
	for (uint8_t timeout = 0; timeout < 15; timeout++) {
		ret = USBH_HID_SetReport(&hUsbHostFS, 0x02U, 0U, kbd_led,
				sizeof(kbd_led));
 
		UsrLog("USBH_HID_SetReport return: %d", ret);
		IWDG_delay_ms(1);
 
		if (ret == ret2) {
			break;
		}
	}
 
//	ret = HAL_BUSY;
//	ret2 = HAL_OK;
 
	for (uint8_t timeout = 0; timeout < 15; timeout++) {
		ret = USBH_HID_GetReport(&hUsbHostFS, 0x02U, 0U, kbd_led,
				sizeof(kbd_led));
 
		UsrLog("USBH_HID_GetReport return: %d; kbd_led: %d", ret, kbd_led[0]);
		IWDG_delay_ms(1);
 
		if (ret == ret2) {
			break;
		}
	}
 
	if (kbd_led[0] == (LED_status[0] & 7)) {
		ret = HAL_OK;
	} else {
		ret = HAL_ERROR;
	}
 
	LED_status[0] = kbd_led[0];
 
	if ((kbd_LED_status[0] & 1) == 1) {
		kbd_num_lock_state = 1;
	} else {
		kbd_num_lock_state = 0;
	}
 
	if (((kbd_LED_status[0] >> 1) & 1) == 1) {
		caps_lock_state = 1;
	} else {
		caps_lock_state = 0;
	}
 
	if (((kbd_LED_status[0] >> 2) & 1) == 1) {
		kbd_scroll_lock_state = 1;
	} else {
		kbd_scroll_lock_state = 0;
	}
 
	return ret;
}

usb_host.c:

static void USBH_UserProcess2(USBH_HandleTypeDef *phost, uint8_t id) {
	/* USER CODE BEGIN CALL_BACK_21 */
	switch (id) {
	case HOST_USER_SELECT_CONFIGURATION:
		break;
 
	case HOST_USER_DISCONNECTION:
		Appli_state = APPLICATION_DISCONNECT;
 
		Appli_state_FS = Appli_state;
 
		kbd_LED_status_old = 99; // <--------- to update keyboard if reconnected

 usbh_core.c:

uint32_t keyboard_led_status_tick = 0;
 
/**
 * @brief USBH_Process
 * Background process of the USB Core.
 * @param phost: Host Handle
 * @retval USBH Status
 */
USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost) {
[...]
	case HOST_CLASS:
		/* process class state machine */
		if (phost->pActiveClass != NULL) {
			/* Update keyboard LED status */
			if (HAL_GetTick() > (keyboard_led_status_tick + 10)) {
				keyboard_led_status_tick = HAL_GetTick();
				HID_HandleTypeDef *HID_Handle =
						(HID_HandleTypeDef*) phost->pActiveClass->pData;
				if (HID_Handle->Init == USBH_HID_KeybdInit) {
					USB_Set_Keyboard_LED_Status();
				}
			}
 
			phost->pActiveClass->BgndProcess(phost);
		}
		break;
 
	case HOST_DEV_DISCONNECTED:
[...]

12 replies

Pavel A.
November 20, 2021

IIRC the host class examples in the ST USBH library are limited.

Every class can send few requests to the device at setup time (after enumeration) and then goes to "steady state" that in HID examples only reads input reports.

What you're looking for is how to "inject" a class specific request in the "steady" state of the HID class.

RhSilicon
Lead
December 26, 2022

Related: USB HUB support for HID HOST: https://community.st.com/s/feed/0D53W000021OPdPSAW