This chapter covers all the exposed APIs of the USBX host classes. The following APIs for each class are described in detail.
Register a HID client to the HID class.
UINT ux_host_class_hid_client_register(
UCHAR *hid_client_name,
UINT (*hid_client_handler)
(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *));
This function is used to register a HID client to the HID class and returns immediately. The HID class needs to find a match between a HID device and HID client before requesting data from this device.
Note: The C string of hid_client_name must be NULL-terminated and the length of it (without the NULL-terminator itself) must be no larger than UX_HOST_CLASS_HID_MAX_CLIENT_NAME_LENGTH.
UINT status;
/* The following example illustrates how to register a HID client, in
this case a USB mouse, to the HID class. */
status = ux_host_class_hid_client_register("ux_host_class_hid_client_mouse",
ux_host_class_hid_mouse_entry);
/* If status equals UX_SUCCESS, the operation was successful. */
Register a callback from the HID class.
UINT ux_host_class_hid_report_callback_register(
UX_HOST_CLASS_HID *hid,
UX_HOST_CLASS_HID_REPORT_CALLBACK *call_back);
This function is used to register a callback from the HID class to the HID client when a report is received and returns immediately.
UINT status;
/* This example illustrates how to register a HID client, in this case a USB mouse, to the HID class. In this case, the HID client is asking the HID class to call the client for each usage received in the HID report. */
call_back.ux_host_class_hid_report_callback_id = 0;
call_back.ux_host_class_hid_report_callback_function = ux_host_class_hid_mouse_callback;
call_back.ux_host_class_hid_report_callback_buffer = UX_NULL;
call_back.ux_host_class_hid_report_callback_flags = UX_HOST_CLASS_HID_REPORT_INDIVIDUAL_USAGE;
call_back.ux_host_class_hid_report_callback_length = 0;
status = ux_host_class_hid_report_callback_register(hid, &call_back);
/* If status equals UX_SUCCESS, the operation was successful. */
Start the periodic endpoint for a HID class instance.
UINT ux_host_class_hid_periodic_report_start(UX_HOST_CLASS_HID *hid);
This function is used to start the periodic (interrupt) endpoint for the instance of the HID class that is bound to this HID client. The HID class cannot start the periodic endpoint until the HID client is activated and therefore it is left to the HID client to start this endpoint to receive reports.
To protect states for reentry, it waits the semaphore of HID instance before modifying periodic report polling state.
UINT status;
/* The following example illustrates how to start the periodic
endpoint. */
status = ux_host_class_hid_periodic_report_start(hid);
/* If status equals UX_SUCCESS, the operation was successful. */
Stop the periodic endpoint for a HID class instance.
UINT ux_host_class_hid_periodic_report_stop(UX_HOST_CLASS_HID *hid);
This function is used to stop the periodic (interrupt) endpoint for the instance of the HID class that is bound to this HID client. The HID class cannot stop the periodic endpoint until the HID client is deactivated, all its resources freed and therefore it is left to the HID client to stop this endpoint.
To protect states for reentry, it waits the semaphore of HID instance before modifying periodic report polling state.
UINT status;
/* The following example illustrates how to stop the periodic endpoint. */
status = ux_host_class_hid_periodic_report_stop(hid);
/* If status equals UX_SUCCESS, the operation was successful. */
Get a report idle rate from a HID class instance
UINT ux_host_class_hid_idle_get(UX_HOST_CLASS_HID *hid,
USHORT *idle_time, USHORT report_id)
This function is used to get idle rate time period used by device to keep sending reports when there is no data.
To protect states for reentry, it waits the semaphore of HID instance and the semaphore of device default control endpoint before issuing the transfer request.
USHORT idle_time;
UINT status;
/* The following example illustrates how to get idle rate. */
status = ux_host_class_hid_idle_get(hid, &idle_time, 0);
/* If status equals UX_SUCCESS, the operation was successful. */
Send idle rate
UINT ux_host_class_hid_idle_set(UX_HOST_CLASS_HID *hid,
USHORT idle_time, USHORT report_id)
This function is used to set idle rate time period to the device.
To protect states for reentry, it waits the semaphore of HID instance and the semaphore of device default control endpoint before issuing the transfer request.
/* The following example illustrates how to set idle rate. */
status = ux_host_class_hid_idle_set(hid, 50, 0);
/* If status equals UX_SUCCESS, the operation was successful. */
Get a report from a HID class instance.
UINT ux_host_class_hid_report_get(
UX_HOST_CLASS_HID *hid,
UX_HOST_CLASS_HID_CLIENT_REPORT *client_report);
This function is used to receive a report directly from the device without relying on the periodic endpoint. This report is coming from the control endpoint but its treatment is the same as though it were coming on the periodic endpoint.
To protect states for reentry, it waits the semaphore of HID instance and the semaphore of device default control endpoint before issuing the transfer request.
UX_HOST_CLASS_HID_CLIENT_REPORT input_report;
UINT status;
/* The following example illustrates how to get a report. */
input_report.ux_host_class_hid_client_report = hid_report;
input_report.ux_host_class_hid_client_report_buffer = buffer;
input_report.ux_host_class_hid_client_report_length = length;
input_report.ux_host_class_hid_client_flags = UX_HOST_CLASS_HID_REPORT_INDIVIDUAL_USAGE;
status = ux_host_class_hid_report_get(hid, &input_report);
/* If status equals UX_SUCCESS, the operation was successful. */
Send a report
UINT ux_host_class_hid_report_set(
UX_HOST_CLASS_HID *hid,
UX_HOST_CLASS_HID_CLIENT_REPORT *client_report);
This function is used to send a report directly to the device.
To protect states for reentry, it waits the semaphore of HID instance and the semaphore of device default control endpoint before issuing the transfer request.
/* The following example illustrates how to send a report. */
UX_HOST_CLASS_HID_CLIENT_REPORT input_report;
input_report.ux_host_class_hid_client_report = hid_report;
input_report.ux_host_class_hid_client_report_buffer = buffer;
input_report.ux_host_class_hid_client_report_length = length;
input_report.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_INDIVIDUAL_USAGE;
status = ux_host_class_hid_report_set(hid, &input_report);
/* If status equals UX_SUCCESS, the operation was successful. */
Get mouse buttons.
UINT ux_host_class_hid_mouse_buttons_get(
UX_HOST_CLASS_HID_MOUSE *mouse_instance,
ULONG *mouse_buttons);
This function is used to get the mouse buttons.
Note the polling of button states are in background. The last updated buttons states are returned immediately.
/* The following example illustrates how to obtain mouse buttons. */
UX_HOST_CLASS_HID_MOUSE *mouse_instance;
ULONG mouse_buttons;
status = ux_host_class_hid_mouse_button_get(mouse_instance, &mouse_buttons);
/* If status equals UX_SUCCESS, the operation was successful. */
Get mouse position.
UINT ux_host_class_hid_mouse_position_get(
UX_HOST_CLASS_HID_MOUSE *mouse_instance,
SLONG *mouse_x_position,
SLONG *mouse_y_position);
This function is used to get the mouse position in x & y coordinates.
Note the polling of position states are in background. The last updated position states are returned immediately.
/* The following example illustrates how to obtain mouse coordinates. */
UX_HOST_CLASS_HID_MOUSE *mouse_instance;
SLONG mouse_x_position;
SLONG mouse_y_position;
status = ux_host_class_hid_mouse_position_get(mouse_instance,
&mouse_x_position, &mouse_y_position);
/* If status equals UX_SUCCESS, the operation was successful. */
Get keyboard key and state.
UINT ux_host_class_hid_keyboard_key_get(
UX_HOST_CLASS_HID_KEYBOARD *keyboard_instance,
ULONG *keyboard_key,
ULONG *keyboard_state);
This function is used to get the keyboard key and state.
Note the polling of key states are in background. The last updated keys states are returned immediately.
The keyboard state can have the following values.
while (1)
{
/* Get a key/state from the keyboard. */
status = ux_host_class_hid_keyboard_key_get(keyboard,
&keyboard_char, &keyboard_state);
/* Check if there is something. */
if (status == UX_SUCCESS)
{
#ifdef UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE
if (keyboard_state & UX_HID_KEYBOARD_STATE_KEY_UP)
{
/* The key was released. */
} else
{
/* The key was pressed. */
}
#endif
/* We have a character in the queue. */
keyboard_queue[keyboard_queue_index] = (UCHAR) keyboard_char;
/* Can we accept more ? */
if(keyboard_queue_index < 1024)
keyboard_queue_index++;
}
tx_thread_sleep(10);
}
Perform an IOCTL function to the HID keyboard.
UINT ux_host_class_hid_keyboard_ioctl(
UX_HOST_CLASS_HID_KEYBOARD *keyboard_instance,
ULONG ioctl_function, VOID *parameter);
This function performs a specific ioctl function to the HID keyboard. The call is blocking and only returns when there is either an error or when the command is completed.
UINT status;
/* This example shows usage of the SET_LAYOUT IOCTL function.
USBX receives raw key values from the device (these raw values
are defined in the HID usage table specification) and optionally
decodes them for application usage. The decoding is performed
based on a set of arrays that act as maps – which array is used
depends on the raw key value (i.e. keypad and non-keypad) and
the current state of the keyboard (i.e. shift, caps lock, etc.). */
/* When the shift condition is not present and the raw key value
is not within the keypad value range, this array will be used to decode the raw key value. */
static UCHAR keyboard_layout_raw_to_unshifted_map[] =
{
0,0,0,0,
'a','b','c','d','e','f','g',
'h','i','j','k','l','m','n',
'o','p','q','r','s','t',
'u','v','w','x','y','z',
'1','2','3','4','5','6','7','8','9','0',
0x0d,0x1b,0x08,0x07,0x20,'-','=','[',']',
'\\','#',';',0x27,'`',',','.','/',0xf0,
0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,
0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcd,0xd0,0xc8,0xf2,
'/','*','-','+',
0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=',
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
/* When the shift condition is present and the raw key value
is not within the keypad value range, this array will be used to decode the raw key value. */
static UCHAR keyboard_layout_raw_to_shifted_map[] =
{
0,0,0,0,
'A','B','C','D','E','F','G',
'H','I','J','K','L','M','N',
'O','P','Q','R','S','T',
'U','V','W','X','Y','Z',
'!','@','#','$','%','^','&','*','(',')',
0x0d,0x1b,0x08,0x07,0x20,'_','+','{','}',
'|','~',':','"','~','<','>','?',0xf0,
0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,
0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcd,0xd0,0xc8,0xf2,
'/','*','-','+',
0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=',
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
/* When numlock is on and the raw key value is within the keypad
value range, this array will be used to decode the raw key value. */
static UCHAR keyboard_layout_raw_to_numlock_on_map[] =
{
'/','*','-','+',
0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=',
};
/* When numlock is off and the raw key value is within the keypad value
range, this array will be used to decode the raw key value. */
static UCHAR keyboard_layout_raw_to_numlock_off_map[] =
{
'/','*','-','+',
0x0d,0xcf,0xd0,0xd1,0xcb,'5',0xcd,0xc7,0xc8,0xc9,0xd2,0xd3,'\\',0x00,0x
00,'=',
};
/* Specify the keyboard layout for USBX usage. */
static UX_HOST_CLASS_HID_KEYBOARD_LAYOUT keyboard_layout =
{
keyboard_layout_raw_to_shifted_map,
keyboard_layout_raw_to_unshifted_map,
keyboard_layout_raw_to_numlock_on_map,
keyboard_layout_raw_to_numlock_off_map,
/* The maximum raw key value. Values larger than this are discarded. */
UX_HID_KEYBOARD_KEYS_UPPER_RANGE,
/* The raw key value for the letter 'a'. */
UX_HID_KEYBOARD_KEY_LETTER_A,
/* The raw key value for the letter 'z'. */
UX_HID_KEYBOARD_KEY_LETTER_Z,
/* The lower range raw key value for keypad keys - inclusive. */
UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE,
/* The upper range raw key value for keypad keys. */
UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE
};
/* Call the IOCTL function to change the keyboard layout. */
status = ux_host_class_hid_keyboard_ioctl(keyboard,
UX_HID_KEYBOARD_IOCTL_SET_LAYOUT, (VOID *)&keyboard_layout);
/* If status equals UX_SUCCESS, the operation was successful. */
UINT status;
/* The following example illustrates IOCTL function of Disable key decode from keyboard layout. */
status = ux_host_class_hid_keyboard_ioctl(keyboard,
UX_HID_KEYBOARD_IOCTL_DISABLE_KEYS_DECODE, UX_NULL);
/* If status equals UX_SUCCESS, the operation was successful. */
Get remote control usage
UINT ux_host_class_hid_remote_control_usage_get(
UX_HOST_CLASS_HID_REMOTE_CONTROL *remote_control_instance,
LONG *usage,
ULONG *value);
This function is used to get the remote control usages.
Note the polling of remote control usages are in background and the usages are put in a circular queue, the function just returns the very first usage received and saved in the queue, immediately. When there is nothing in the queue status error is returned.
The list of all possible usages is too long to fit in this user guide. For a full description, the ux_host_class_hid.h has the entire set of possible values.
/* Read usages and values as the user changes the vol/bass/treble buttons on the speaker */
while (remote_control != UX_NULL)
{
status = ux_host_class_hid_remote_control_usage_get(remote_control, &usage, &value);
if (status == UX_SUCCESS)
{
/* We have something coming from the HID remote control,
we filter the usage here and only allow the
volume usage which can be VOLUME, VOLUME_INCREMENT or VOLUME_DECREMENT */
switch(usage)
{
case UX_HOST_CLASS_HID_CONSUMER_VOLUME :
case UX_HOST_CLASS_HID_CONSUMER_VOLUME_INCREMENT :
case UX_HOST_CLASS_HID_CONSUMER_VOLUME_DECREMENT :
if (value<0x80)
{
if (current_volume + audio_control.ux_host_class_audio_control_res < 0xffff)
current_volume = current_volume + audio_control.ux_host_class_audio_control_res;
} else {
if (current_volume > audio_control.ux_host_class_audio_control_res)
current_volume = current_volumeaudio_control.ux_host_class_audio_control_res;
}
audio_control.ux_host_class_audio_control_channel = 1;
audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL;
audio_control.ux_host_class_audio_control_cur = current_volume;
status = ux_host_class_audio_control_value_set(audio, &audio_control);
audio_control.ux_host_class_audio_control_channel = 2;
audio_control.ux_host_class_audio_control = UX_HOST_CLASS_AUDIO_VOLUME_CONTROL;
audio_control.ux_host_class_audio_control_cur = current_volume;
status = ux_host_class_audio_control_value_set(audio, &audio_control);
break;
}
}
tx_thread_sleep(10);
}
Read from the cdc_acm interface.
UINT ux_host_class_cdc_acm_read(
UX_HOST_CLASS_CDC_ACM *cdc_acm,
UCHAR *data_pointer,
ULONG requested_length,
ULONG *actual_length);
This function reads from the cdc_acm interface. The call is blocking and only returns when there is either an error or when the transfer is complete.
Note: This functions reads raw bulk data from device, so it keeps pending until buffer is full or device terminates the transfer by a short packet (including Zero Length Packet). For more details, please refer to General Considerations for Bulk Transfer. The function reads bytes from the device packet by packet. If the prepared buffer size is smaller than a packet and the device sends more data than expected (in other words, the prepared buffer size is not a multiple of the USB endpoint’s max packet size), then buffer overflow will occur. To avoid this issue, the recommended way to read is to allocate a buffer exactly one packet size (USB endpoint max packet size). This way if there is more data, the next read can get it and no buffer overflow will occur. If there is less data, the current read can get a short packet instead of generating an error.
UINT status;
/* The following example illustrates this service. */
status = ux_host_class_cdc_acm_read(cdc_acm, data_pointer,
requested_length, &actual_length);
/* If status equals UX_SUCCESS, the operation was successful. */
Write to the cdc_acm interface
UINT ux_host_class_cdc_acm_write(
UX_HOST_CLASS_CDC_ACM *cdc_acm,
UCHAR *data_pointer,
ULONG requested_length,
ULONG *actual_length);
This function writes to the cdc_acm interface. The call is blocking and only returns when there is either an error or when the transfer is complete.
UINT status;
/* The following example illustrates this service. */
status = ux_host_class_cdc_acm_write(cdc_acm, data_pointer,
requested_length, &actual_length);
/* If status equals UX_SUCCESS, the operation was successful. */
Perform an IOCTL function to the cdc_acm interface.
UINT ux_host_class_cdc_acm_ioctl(
UX_HOST_CLASS_CDC_ACM *cdc_acm,
ULONG ioctl_function,
VOID *parameter);
This function performs a specific ioctl function to the cdc_acm interface. The call is blocking and only returns when there is either an error or when the command is completed.
UINT status;
/* The following example illustrates this service. */
status = ux_host_class_cdc_acm_ioctl(cdc_acm,
UX_HOST_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING, (VOID *)&line_coding);
/* If status equals UX_SUCCESS, the operation was successful. */
Begins background reception of data from the device.
UINT ux_host_class_cdc_acm_reception_start(
UX_HOST_CLASS_CDC_ACM *cdc_acm,
UX_HOST_CLASS_CDC_ACM_RECEPTION *cdc_acm_reception);
This function causes USBX to continuously read data from the device in the background. Upon completion of each transaction, the callback specified in cdc_acm_reception is invoked so the application may perform further processing of the transaction’s data.
Note: ux_host_class_cdc_acm_read must not be used while background reception is in use.
Note: cdc_acm_reception must have its callback function assigned, where ux_host_class_cdc_acm_reception_data_tail must be moved after data processed. The example of this callback implement follows:
void demo_host_cdc_acm_reception_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm, UINT status, UCHAR *reception_buffer, ULONG reception_size) { UX_HOST_CLASS_CDC_ACM_RECEPTION *reception = cdc_acm -> ux_host_class_cdc_acm_reception; /* Perform processing of the transaction's data at reception_buffer. */ /* Move reception data tail to next buffer. */ if (reception -> ux_host_class_cdc_acm_reception_data_tail + reception -> ux_host_class_cdc_acm_reception_block_size >= reception -> ux_host_class_cdc_acm_reception_data_buffer + reception -> ux_host_class_cdc_acm_reception_data_buffer_size) /* We are at the end of the buffer. Move back to the beginning. */ reception -> ux_host_class_cdc_acm_reception_data_tail = reception -> ux_host_class_cdc_acm_reception_data_buffer; else /* Program the tail to be after the current buffer. */ reception -> ux_host_class_cdc_acm_reception_data_tail += reception -> ux_host_class_cdc_acm_reception_block_size; }
typedef struct UX_HOST_CLASS_CDC_ACM_RECEPTION_STRUCT
{
ULONG ux_host_class_cdc_acm_reception_state;
ULONG ux_host_class_cdc_acm_reception_block_size;
UCHAR *ux_host_class_cdc_acm_reception_data_buffer;
ULONG ux_host_class_cdc_acm_reception_data_buffer_size;
UCHAR *ux_host_class_cdc_acm_reception_data_head;
UCHAR *ux_host_class_cdc_acm_reception_data_tail;
VOID (*ux_host_class_cdc_acm_reception_callback)(struct UX_HOST_CLASS_CDC_ACM_STRUCT *cdc_acm,
UINT status, UCHAR *reception_buffer, ULONG reception_size);
} UX_HOST_CLASS_CDC_ACM_RECEPTION;
UINT status;
UX_HOST_CLASS_CDC_ACM_RECEPTION cdc_acm_reception;
/* Setup the background reception parameter. */
/* Set the desired max read size for each transaction.
For example, if this value is 64, then the maximum amount of
data received from the device in a single transaction is 64.
If the amount of data received from the device is less than this value,
the callback will still be invoked with the actual amount of data received. */
cdc_acm_reception.ux_host_class_cdc_acm_reception_block_size = block_size;
/* Set the buffer where the data from the device is read to. */
cdc_acm_reception.ux_host_class_cdc_acm_reception_data_buffer = cdc_acm_reception_buffer;
/* Set the size of the data reception buffer.
Note that this should be at least as large as ux_host_class_cdc_acm_reception_block_size. */
cdc_acm_reception.ux_host_class_cdc_acm_reception_data_buffer_size = cdc_acm_reception_buffer_size;
/* Set the callback that is to be invoked upon each reception transfer completion. */
cdc_acm_reception.ux_host_class_cdc_acm_reception_callback = reception_callback;
/* Start background reception using the values we defined in the reception parameter. */
status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_reception);
/* If status equals UX_SUCCESS, background reception has successfully started. */
Stops background reception of packets.
UINT ux_host_class_cdc_acm_reception_stop(
UX_HOST_CLASS_CDC_ACM *cdc_acm,
UX_HOST_CLASS_CDC_ACM_RECEPTION *cdc_acm_reception);
This function causes USBX to stop background reception previously started by ux_host_class_cdc_acm_reception_start.
typedef struct UX_HOST_CLASS_CDC_ACM_RECEPTION_STRUCT
{
ULONG ux_host_class_cdc_acm_reception_state;
ULONG ux_host_class_cdc_acm_reception_block_size;
UCHAR *ux_host_class_cdc_acm_reception_data_buffer;
ULONG ux_host_class_cdc_acm_reception_data_buffer_size;
UCHAR *ux_host_class_cdc_acm_reception_data_head;
UCHAR *ux_host_class_cdc_acm_reception_data_tail;
VOID (*ux_host_class_cdc_acm_reception_callback)(
struct UX_HOST_CLASS_CDC_ACM_STRUCT *cdc_acm, UINT status,
UCHAR *reception_buffer, ULONG reception_size);
} UX_HOST_CLASS_CDC_ACM_RECEPTION;
UINT status;
UX_HOST_CLASS_CDC_ACM_RECEPTION cdc_acm_reception;
/* Stop background reception. The reception parameter should be the same
that was passed to ux_host_class_cdc_acm_reception_start. */
status = ux_host_class_cdc_acm_reception_stop(cdc_acm, &cdc_acm_reception);
/* If status equals UX_SUCCESS, background reception has successfully stopped. */