RZ/A Flexible Software Package Documentation  Release v3.0.0

 
USBX Porting Layer (rm_usbx_port)

Functions

Refer to USB (r_usb_basic) for the common API (r_usb_basic) to be called from the application.

Overview

This USB driver works by combining USBX and r_usb_basic module.

How to Configuration

Note

  1. Please specify a multiple of MaxPacketSize to the 3rd argument(requested_length). since If the value of the 3rd argument is not multiple of MaxPacketSize, all data sent by USB Host or USB Peripheral may not be received correctly.
  2. Please specify start address of thr area allocated a size larger than 3rd argument(requested_length) to the 2nd argument(data_pointer or buffer).

Limitations

1.Please call the initialization function in the application program. Please be sure to call R_USB_Open function after calling the following functions.

2.Set the value for 1000 Ticks per second in the "Timer Ticks Per Second" item.

timer_ticks.png
Specify value of Timer Ticks Per Second

3.Set the Thread priority to a value of 21.

thread_priority.png
Specify value of Thread priority

4.When using the following functions, call the following functions in the following order after calling the R_USB_Close function. NOTE : Do not call R_USB_Close function in Peripheral Audio Class.

5.The USBX HID class does not support OUT transfer.

6.When using USBX HHID, please use Wired device.

Descriptor

Templates for USBX descriptors can be found in rza/fsp/src/rm_usbx_port folder. Also, please be sure to use your vendor ID.
Change the descriptor.c.template file for each class as follows if High-speed mode is used.

Examples

USBX PCDC Example

PCDC loopback example is as follows.

/******************************************************************************
* Macro definitions
******************************************************************************/
/* USBx device configuration settings */
#define DEVICE_FRAME_LENGTH_HIGH_SPEED (103U)
#define DEVICE_FRAME_LENGTH_FULL_SPEED (93U)
#define STRING_FRAMEWORK_LENGTH (105U)
#define LANGUAGE_ID_FRAME_WORK_LENGTH (2U)
#define CONFIG_NUMB (1U)
#define INTERFACE_NUMB0 (0x00)
#define VALUE_50 (50)
/******************************************************************************
* Exported global variables and functions (to be accessed by other files)
******************************************************************************/
extern uint8_t g_device_framework_full_speed[];
extern uint8_t g_device_framework_hi_speed[];
extern uint8_t g_language_id_framework[];
extern uint8_t g_string_framework[];
/******************************************************************************
* Global functions and variables
******************************************************************************/
UINT usbx_status_callback(ULONG status);
/******************************************************************************
* Private global variables and functions
******************************************************************************/
usb_instance_ctrl_t g_basic0_ctrl;
extern const usb_cfg_t g_basic0_cfg;
static void ux_cdc_device0_instance_activate(void * cdc_instance);
static void ux_cdc_device0_instance_deactivate(void * cdc_instance);
void usbx_pcdc_sample(void);
/******************************************************************************
* Exported global functions (to be accessed by other files)
******************************************************************************/
/* Define local constants. */
#define UX_DEMO_BUFFER_SIZE 2048
#define RESET_VALUE (0x00)
#define MEMPOOL_SIZE (64 * 1024)
#define BYTE_SIZE sizeof(uint32_t)
/* Define global variables. */
UX_SLAVE_CLASS_CDC_ACM * g_cdc = UX_NULL;
UCHAR buffer[UX_DEMO_BUFFER_SIZE];
/* Define local variables. */
static uint32_t g_ux_pool_memory[MEMPOOL_SIZE / BYTE_SIZE];
static UX_SLAVE_CLASS_CDC_ACM_PARAMETER g_ux_device_class_cdc_acm0_parameter;
static ULONG g_actual_length;
/******************************************************************************
* Function Name : usbx_pcdc_sample
* Description : Application task (loopback processing)
* Arguments : none
* Return value : none
******************************************************************************/
void usbx_pcdc_sample (void)
{
UINT status;
ULONG actual_length;
ULONG requested_length;
tx_thread_sleep(10);
/* ux_system_initialization */
status = ux_system_initialize(g_ux_pool_memory, MEMPOOL_SIZE, UX_NULL, RESET_VALUE);
if (UX_SUCCESS != status)
{
printf("Initialization failed.\r\n");
return;
}
/* ux_device stack initialization */
status = ux_device_stack_initialize(g_device_framework_hi_speed,
DEVICE_FRAME_LENGTH_HIGH_SPEED,
g_device_framework_full_speed,
DEVICE_FRAME_LENGTH_FULL_SPEED,
g_string_framework,
STRING_FRAMEWORK_LENGTH,
g_language_id_framework,
LANGUAGE_ID_FRAME_WORK_LENGTH,
&usbx_status_callback);
/* Error Handle */
if (UX_SUCCESS != status)
{
printf("Initialization failed.\r\n");
return;
}
/* The activate command is used when the host has sent a SET_CONFIGURATION command
* and this interface has to be mounted. Both Bulk endpoints have to be mounted
* and the cdc_acm thread needs to be activated. */
g_ux_device_class_cdc_acm0_parameter.ux_slave_class_cdc_acm_instance_activate = ux_cdc_device0_instance_activate;
/* The deactivate command is used when the device has been extracted.
* The device endpoints have to be dismounted and the cdc_acm thread canceled. */
g_ux_device_class_cdc_acm0_parameter.ux_slave_class_cdc_acm_instance_deactivate =
ux_cdc_device0_instance_deactivate;
/* ux_device stack class registration */
status = ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name,
_ux_device_class_cdc_acm_entry,
CONFIG_NUMB,
INTERFACE_NUMB0,
(void *) &g_ux_device_class_cdc_acm0_parameter);
/* Error Handle */
if (UX_SUCCESS != status)
{
printf("Initialization failed.\r\n");
return;
}
/* Open usb driver */
if (g_usb_on_usb.open(&g_basic0_ctrl, &g_basic0_cfg) != FSP_SUCCESS)
{
printf("Failed to open USB.\r\n");
return;
}
printf("initialization process succeeded.\r\n");
while (1)
{
/* Ensure the CDC class is mounted. */
if (g_cdc != UX_NULL)
{
/* Read from the CDC class. */
status = ux_device_class_cdc_acm_read(g_cdc, buffer, UX_DEMO_BUFFER_SIZE, &actual_length);
if (status == UX_SUCCESS)
{
/* The actual length becomes the requested length. */
requested_length = actual_length;
/* Check the status. If OK, we will write to the CDC instance. */
ux_device_class_cdc_acm_write(g_cdc, buffer, requested_length, &g_actual_length);
/* Clear buffer to 0. */
ux_utility_memory_set(buffer, 0, sizeof(buffer));
}
else
{
/* If reading from host fails, wait 50tick. */
tx_thread_sleep(VALUE_50);
}
}
else
{
/* If the CDC class fails to mount, 50tick wait. */
tx_thread_sleep(VALUE_50);
}
}
}
/* Activate Function */
static void ux_cdc_device0_instance_activate (void * cdc_instance)
{
/* Save the CDC instance. */
g_cdc = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance;
}
/* Deactivate Function */
static void ux_cdc_device0_instance_deactivate (void * cdc_instance)
{
FSP_PARAMETER_NOT_USED(cdc_instance);
g_cdc = UX_NULL;
}
/* Callback Function */
UINT usbx_status_callback (ULONG status)
{
switch (status)
{
case UX_DEVICE_ATTACHED:
break;
case UX_DEVICE_REMOVED:
break;
default:
{
/* do nothing */
break;
}
}
return 0;
}

USBX HCDC Example

The main functions of the HCDC loopback example are as follows:

  1. Virtual UART control settings are configured by transmitting the class request SET_LINE_CODING to the CDC device.
  2. Sends receive (Bulk In transfer) requests to a CDC peripheral device and receives data.
  3. Loops received data back to the peripheral by means of Bulk Out transfers.

The main loop performs loopback processing in which data received from a CDC peripheral device is transmitted unaltered back to the peripheral.

#define VALUE_100 (100)
UINT ux_host_usr_event_notification (ULONG event, UX_HOST_CLASS * host_class, VOID * instance)
{
if (_ux_utility_memory_compare(_ux_system_host_class_cdc_acm_name, host_class,
_ux_utility_string_length_get(_ux_system_host_class_cdc_acm_name)) ==
UX_SUCCESS)
{
if (event == UX_FSP_DEVICE_INSERTION) /* Check if there is a device insertion. */
{
p_cdc_acm = (UX_HOST_CLASS_CDC_ACM *) instance;
if (p_cdc_acm->ux_host_class_cdc_acm_interface->ux_interface_descriptor.bInterfaceClass !=
UX_HOST_CLASS_CDC_DATA_CLASS)
{
/* It seems the DATA class is on the second interface. Or we hope ! */
p_cdc_acm = p_cdc_acm->ux_host_class_cdc_acm_next_instance;
/* Check again this interface, if this is not the data interface, we give up. */
if (p_cdc_acm->ux_host_class_cdc_acm_interface->ux_interface_descriptor.bInterfaceClass !=
UX_HOST_CLASS_CDC_DATA_CLASS)
{
/* We did not find a proper data interface. */
p_cdc_acm = UX_NULL;
}
}
if (p_cdc_acm != UX_NULL)
{
tx_event_flags_set(&g_cdcacm_activate_event_flags0, CDCACM_FLAG, TX_OR);
}
}
else if (event == UX_FSP_DEVICE_REMOVAL) /* Check if there is a device removal. */
{
tx_event_flags_set(&g_cdcacm_activate_event_flags0, ~CDCACM_FLAG, TX_AND);
p_cdc_acm = UX_NULL;
}
else
{
}
}
return UX_SUCCESS;
}
void buffer_clear (uint8_t * p)
{
uint16_t counter;
for (counter = 0; counter < DATA_LEN; counter++)
{
*p = 0U;
}
}
/******************************************************************************
* Function Name : usbx_hcdc_sample
* Description : Application task (loopback processing)
* Arguments : none
* Return value : none
******************************************************************************/
/* CDCACM Host Thread entry function */
void usbx_hcdc_sample (void)
{
uint32_t status;
ULONG actual_flags;
uint16_t counter = 0;
for (counter = 0; counter < DATA_LEN; counter++)
{
g_write_buf[counter] = (uint8_t) counter;
}
ux_system_initialize((CHAR *) g_ux_pool_memory, MEMPOOL_SIZE, UX_NULL, 0);
ux_host_stack_initialize(ux_host_usr_event_notification);
g_usb_on_usb.open(&g_basic0_ctrl, &g_basic0_cfg);
while (1)
{
tx_event_flags_get(&g_cdcacm_activate_event_flags0, CDCACM_FLAG, TX_OR, &actual_flags, TX_WAIT_FOREVER);
if (p_cdc_acm != UX_NULL)
{
if (0 == g_is_communicate)
{
tx_thread_sleep(VALUE_100);
g_is_communicate = 1;
}
status = ux_host_class_cdc_acm_write(p_cdc_acm, g_write_buf, DATA_LEN, &g_write_actual_length);
if ((UX_SUCCESS == status) && (DATA_LEN == g_write_actual_length))
{
g_read_actual_length = 0;
buffer_clear(g_read_buf);
status = ux_host_class_cdc_acm_read(p_cdc_acm, g_read_buf, DATA_LEN, &g_read_actual_length);
if ((UX_SUCCESS == status) && (DATA_LEN == g_read_actual_length))
{
for (counter = 0; counter < DATA_LEN; counter++)
{
if ((uint8_t) counter != g_read_buf[counter])
{
while (1)
{
;
}
}
}
}
}
}
}
}

USBX HMSC Example

HMSC storage example is as follows. See usbx_hmsc_sample for the basic operation of HMSC. Also, please refer to usbx_hmsc_sample_format for the format of the USB memory.

#define UX_STORAGE_BUFFER_SIZE (64 * 1024)
#define EVENT_USB_PLUG_IN (1UL << 0)
#define EVENT_USB_PLUG_OUT (1UL << 1)
#define MEMPOOL_SIZE (63488)
#define DATA_LEN (2048)
#define VALUE_32 (32)
#define VALUE_100 (100)
#define VALUE_200 (200)
#define VALUE_256 (256)
#define VALUE_1024 (1024)
#define DEVICE_INSERTION (0x01U)
#define DEVICE_REMOVAL (0x02U)
static uint16_t g_read_buf[UX_STORAGE_BUFFER_SIZE];
static uint16_t g_write_buf[UX_STORAGE_BUFFER_SIZE];
static FX_FILE g_file;
static UCHAR g_fx_media0_media_memory[UX_STORAGE_BUFFER_SIZE];
static uint8_t g_ux_pool_memory[MEMPOOL_SIZE];
static FX_MEDIA * g_p_media = UX_NULL;
TX_EVENT_FLAGS_GROUP g_usb_plug_events;
UINT usb_host_plug_event_notification(ULONG usb_event, UX_HOST_CLASS * host_class, VOID * instance);
UINT ux_system_host_storage_fx_media_get(UX_HOST_CLASS_STORAGE * instance,
UX_HOST_CLASS_STORAGE_MEDIA ** p_storage_media,
FX_MEDIA ** p_fx_media);
static UINT apl_change_function (ULONG event, UX_HOST_CLASS * host_class, VOID * instance)
{
UINT status = UX_SUCCESS;
UX_HOST_CLASS * class;
UX_HOST_CLASS_STORAGE * storage;
UX_HOST_CLASS_STORAGE_MEDIA * storage_media;
(void) instance;
/* Check the class container if it is for a USBX Host Mass Storage class. */
if (UX_SUCCESS ==
_ux_utility_memory_compare(_ux_system_host_class_storage_name, host_class,
_ux_utility_string_length_get(_ux_system_host_class_storage_name)))
{
/* Check if there is a device insertion. */
if (DEVICE_INSERTION == event)
{
status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &class);
if (UX_SUCCESS != status)
{
return status;
}
status = ux_host_stack_class_instance_get(class, 0, (void **) &storage);
if (UX_SUCCESS != status)
{
return status;
}
if (UX_HOST_CLASS_INSTANCE_LIVE != storage->ux_host_class_storage_state)
{
return UX_ERROR;
}
storage_media = class->ux_host_class_media;
g_p_media = &storage_media->ux_host_class_storage_media;
tx_event_flags_set(&g_usb_plug_events, EVENT_USB_PLUG_IN, TX_OR);
}
else if (DEVICE_REMOVAL == event) /* Check if there is a device removal. */
{
g_p_media = UX_NULL;
tx_event_flags_set(&g_usb_plug_events, EVENT_USB_PLUG_OUT, TX_OR);
}
else
{
}
}
return status;
}
/******************************************************************************
* Function Name : usbx_hmsc_sample
* Description : Application task (loopback processing)
* Arguments : none
* Return value : none
******************************************************************************/
void usbx_hmsc_sample (void)
{
ULONG actual_length = 0;
ULONG actual_flags;
UINT tx_return;
UINT fx_return;
uint16_t data_count = 0;
FX_MEDIA * p_media = UX_NULL;
CHAR volume[VALUE_32];
fx_system_initialize();
ux_system_initialize((CHAR *) g_ux_pool_memory, MEMPOOL_SIZE, UX_NULL, 0);
ux_host_stack_initialize(apl_change_function);
tx_event_flags_create(&g_usb_plug_events, (CHAR *) "USB Plug Event Flags");
g_usb_on_usb.open(&g_basic0_ctrl, &g_basic0_cfg);
while (1)
{
// Wait until device inserted.
tx_return = tx_event_flags_get(&g_usb_plug_events,
EVENT_USB_PLUG_IN,
TX_OR_CLEAR,
&actual_flags,
TX_WAIT_FOREVER);
if (TX_SUCCESS != tx_return)
{
tx_thread_sleep(TX_WAIT_FOREVER);
}
// Get the pointer to FileX Media Control Block for a USB flash device
p_media = g_p_media;
// Retrieve the volume name of the opened media from the Data sector
fx_return = fx_media_volume_get(p_media, volume, FX_DIRECTORY_SECTOR);
if (FX_SUCCESS == fx_return)
{
// Set the default directory in the opened media, arbitrary name called "firstdir"
fx_directory_default_set(p_media, "firstdir");
// Suspend this thread for 200 time-ticks
tx_thread_sleep(VALUE_100);
// Try to open the file, 'counter.txt'.
fx_return = fx_file_open(p_media, &g_file, "counter.txt", (FX_OPEN_FOR_READ | FX_OPEN_FOR_WRITE));
if (FX_SUCCESS != fx_return)
{
// The 'counter.txt' file is not found, so create a new file
fx_return = fx_file_create(p_media, "counter.txt");
if (FX_SUCCESS != fx_return)
{
break;
}
// Open that file
fx_return = fx_file_open(p_media, &g_file, "counter.txt", (FX_OPEN_FOR_READ | FX_OPEN_FOR_WRITE));
if (FX_SUCCESS != fx_return)
{
break;
}
}
// Already open a file, then read the file in blocks
// Set a specified byte offset for reading
fx_return = fx_file_seek(&g_file, 0);
if (FX_SUCCESS == fx_return)
{
fx_return = fx_file_read(&g_file, g_read_buf, DATA_LEN, &actual_length);
if ((FX_SUCCESS == fx_return) || (FX_END_OF_FILE == fx_return))
{
if (data_count == VALUE_1024)
{
// empty file
data_count = 0;
}
for (uint16_t data_max_count = data_count; data_count < (data_max_count + VALUE_256); data_count++)
{
g_write_buf[data_count] = data_count;
}
// Set the specified byte offset for writing
fx_return = fx_file_seek(&g_file, 0);
if (FX_SUCCESS == fx_return)
{
// Write the file in blocks
fx_return = fx_file_write(&g_file, g_write_buf, DATA_LEN);
if (FX_SUCCESS == fx_return)
{
}
else
{
tx_thread_sleep(TX_WAIT_FOREVER);
}
}
}
}
else
{
tx_thread_sleep(TX_WAIT_FOREVER);
}
// Close already opened file
fx_return = fx_file_close(&g_file);
if (FX_SUCCESS != fx_return)
{
tx_thread_sleep(TX_WAIT_FOREVER);
}
tx_thread_sleep(VALUE_200);
}
else
{
tx_thread_sleep(TX_WAIT_FOREVER);
}
/* flush the media */
fx_return = fx_media_flush(p_media);
if (FX_SUCCESS != fx_return)
{
tx_thread_sleep(TX_WAIT_FOREVER);
}
/* close the media */
fx_return = fx_media_close(p_media);
if (FX_SUCCESS != fx_return)
{
tx_thread_sleep(TX_WAIT_FOREVER);
}
// Wait for unplugging the USB
tx_event_flags_get(&g_usb_plug_events, EVENT_USB_PLUG_OUT, TX_OR_CLEAR, &actual_flags, TX_WAIT_FOREVER);
} // while(1)
}
void usbx_hmsc_sample_format (void)
{
ULONG actual_flags;
UINT tx_return;
UINT status = UX_SUCCESS;
FX_MEDIA * p_media = UX_NULL;
fx_system_initialize();
ux_system_initialize((CHAR *) g_ux_pool_memory, MEMPOOL_SIZE, UX_NULL, 0);
ux_host_stack_initialize(apl_change_function);
tx_event_flags_create(&g_usb_plug_events, (CHAR *) "USB Plug Event Flags");
g_usb_on_usb.open(&g_basic0_ctrl, &g_basic0_cfg);
// Wait until device inserted.
tx_return = tx_event_flags_get(&g_usb_plug_events, EVENT_USB_PLUG_IN, TX_OR_CLEAR, &actual_flags, TX_WAIT_FOREVER);
if (TX_SUCCESS != tx_return)
{
tx_thread_sleep(TX_WAIT_FOREVER);
}
// Get the pointer to FileX Media Control Block for a USB flash device
p_media = g_p_media;
memset(g_fx_media0_media_memory, 0x00, sizeof(g_fx_media0_media_memory));
status = fx_media_format(p_media, // Pointer to FileX media control block.
p_media->fx_media_driver_entry, // Driver entry
p_media->fx_media_driver_info, // Pointer to Block Media Driver
g_fx_media0_media_memory, // Media buffer pointer
p_media->fx_media_memory_size, // Media buffer size
"sample", // Volume Name
p_media->fx_media_number_of_FATs, // Number of FATs
p_media->fx_media_root_directory_entries, // Directory Entries
p_media->fx_media_hidden_sectors, // Hidden sectors
(ULONG) p_media->fx_media_total_sectors, // Total sectors
p_media->fx_media_bytes_per_sector, // Sector size
p_media->fx_media_sectors_per_cluster, // Sectors per cluster
p_media->fx_media_heads, // Heads (disk media)
p_media->fx_media_sectors_per_track);
if ((uint8_t) FX_SUCCESS != status)
{
__BKPT(0);
}
}

USBX HUVC Example

HUVC example is as follows.

/***********************************************************************************************************************
* Macro definitions
***********************************************************************************************************************/
#define LINK_ENABLE_WAIT_TIME (1000U)
#define OHCI_ADDRESS (R_USB00_BASE + 0x000)
#define EHCI_ADDRESS (R_USB00_BASE + 0x100)
#define EVENT_USB_PLUG_IN (1UL << 0)
#define EVENT_USB_PLUG_OUT (1UL << 1)
#define UX_FSP_DEVICE_INSERTION (0x01U)
#define UX_FSP_DEVICE_REMOVAL (0x02U)
/* First select camera spec */
#define FIRST_SELECT_WIDTH 640
#define FIRST_SELECT_HEIGHT 480
#define FIRST_SELECT_INTERVAL 333333
/* Definition of the process of adding a video buffer. */
/* Please enable either HIGH_BANDWIDTH_EHCI or NORMAL_BANDWIDTH_OHCI. */
#define HIGH_BANDWIDTH_EHCI 1
// #define NORMAL_BANDWIDTH_OHCI 1
#define VIDEO_BUFFER_SIZE (4 * 1024)
#define IMAGE_WIDTH 640
#define IMAGE_HEIGHT 480
#define MAX_STREAM_BUFFER 2
#define MAX_STREAM_SIZE (IMAGE_WIDTH * IMAGE_HEIGHT * 2)
#define STREAM_STATUS_FIND 0
#define STREAM_STATUS_DATA_ACTIVE 0x01
#define STREAM_STATUS_DATA_EOF 0x02
#define MUTEX_WAIT_TIME 10
#define REC_LOG_NUM 128
#define MAX_NUM_BUFFERS (UX_HOST_CLASS_VIDEO_TRANSFER_REQUEST_COUNT - 1)
#define HTTP_THREAD_STACK 2048
#define IMAGE_RECEIVE_THREAD_STACK (8 * 1024)
#define THREAD_SLEEP_TIME 100
#define OFFSET_MIN_FRAME_INTERVAL 26
#define OFFSET_MAX_FRAME_INTERVAL 30
#define OFFSET_FRAME_INTERVAL_STEP 34
#define NUMBER_OF_CAMERA_SPEC 200
#define CHANNEL_BANDWIDTH_SELECTION 1024
#define UVC_STREAM_HEADER_HEADERINFO_EOH (1U << 7)
#define UVC_STREAM_HEADER_HEADERINFO_ERR (1U << 6)
#define UVC_STREAM_HEADER_HEADERINFO_STI (1U << 5)
#define UVC_STREAM_HEADER_HEADERINFO_RES (1U << 4)
#define UVC_STREAM_HEADER_HEADERINFO_SCR (1U << 3)
#define UVC_STREAM_HEADER_HEADERINFO_PTS (1U << 2)
#define UVC_STREAM_HEADER_HEADERINFO_EOF (1U << 1)
#define UVC_STREAM_HEADER_HEADERINFO_FID (1U << 0)
typedef struct
{
UINT start_tick;
UINT end_tick;
UINT rec_count;
UINT length;
} REC_LOG;
typedef struct
{
#if 1
ULONG p_frame;
#else
UCHAR * p_frame;
#endif
ULONG length;
} FRAME_DATA;
/* Structure that stores 1 frame of Image data */
typedef struct
{
ULONG length;
UCHAR image[MAX_STREAM_SIZE];
} STREAM_BUFFER;
typedef struct spec_of_camera
{
int width;
int height;
int interval;
} SPEC_OF_CAMERA;
typedef struct uvc_stream_header_struct
{
UCHAR bHeaderLength;
UCHAR bmHeaderInfo;
UCHAR dwPresentationTime[4];
UCHAR scrSourceClock_SourceTimeClock[4];
UCHAR scrSourceClock_SOFCounter[2];
} uvc_stream_header_t;
/***********************************************************************************************************************
* Private function prototypes
***********************************************************************************************************************/
VOID uvc_transfer_request_done_callback(UX_TRANSFER * transfer_request);
VOID uvc_parameter_interval_list(UX_HOST_CLASS_VIDEO * video, int width, int height);
UINT uvc_parameter_frame_list(UX_HOST_CLASS_VIDEO * video);
VOID uvc_parameter_list(UX_HOST_CLASS_VIDEO * video, int format);
VOID uvc_process_function(UX_HOST_CLASS_VIDEO * video);
UINT ux_host_usr_event_notification(ULONG event, UX_HOST_CLASS * host_class, VOID * instance);
extern void http_thread_entry(ULONG thread_input);
extern void image_receive_thread_entry(ULONG thread_input);
/***********************************************************************************************************************
* Private global variables
***********************************************************************************************************************/
extern TX_EVENT_FLAGS_GROUP g_usb_plug_events;
/* device insert flag */
TX_EVENT_FLAGS_GROUP g_device_insert_eventflag;
/* data received semaphore */
TX_SEMAPHORE g_data_received_semaphore;
/* video class instance */
UX_HOST_CLASS_VIDEO * volatile video_host_class;
UCHAR video_buffer[MAX_NUM_BUFFERS][VIDEO_BUFFER_SIZE] USB_BUFFER_PLACE_IN_SECTION;
FRAME_DATA frame_data[MAX_NUM_BUFFERS];
int frame_index = 0;
/* Camera spec data */
SPEC_OF_CAMERA camera_spec[NUMBER_OF_CAMERA_SPEC];
int camera_spec_count = 0;
int camera_spec_select = 0;
TX_THREAD http_thread;
CHAR http_thread_stack[HTTP_THREAD_STACK];
TX_THREAD image_receive_thread;
CHAR image_receive_thread_stack[IMAGE_RECEIVE_THREAD_STACK];
ULONG actual_flags = 0;
ULONG error_counter = 0;
UINT image_get_log[REC_LOG_NUM];
UINT image_get_idx = 0;
/* Image data for MAX_STREAM_BUFFER frames */
STREAM_BUFFER stream_buffer[MAX_STREAM_BUFFER];
/* index of stream_buffer */
static int current_stream_index = 0;
/* Image data for display */
STREAM_BUFFER * current_display_image = NULL;
/* Image data for update */
STREAM_BUFFER * current_stream_image = &stream_buffer[0];
/* mutex for stream_buffer */
static TX_MUTEX image_mutex;
/* Value for searching for frame switching */
static int fid = -1;
/* prototypes */
void display_image_update(void);
int check_stream(FRAME_DATA * p_frame_data);
UCHAR _ux_system_host_class_video_name[] = "ux_host_class_video";
REC_LOG rec_log[REC_LOG_NUM];
UINT rec_log_idx = 0;
ULONG receive_count = 0;
/* index of frame_data */
static int frame_check_index = 0;
/* Check status of stream data */
static int stream_status;
usb_instance_ctrl_t g_basic0_ctrl;
/* Change API. */
static UINT apl_change_function (ULONG event, UX_HOST_CLASS * host_class, VOID * instance)
{
UINT status = UX_SUCCESS;
if (UX_SUCCESS ==
_ux_utility_memory_compare(_ux_system_host_class_video_name, host_class,
_ux_utility_string_length_get(_ux_system_host_class_video_name)))
{
if (UX_DEVICE_INSERTION == event) /* Check if there is a device insertion. */
{
video_host_class = instance;
/* Set the event flag to let application know the device insertion. */
tx_event_flags_set(&g_usb_plug_events, EVENT_USB_PLUG_IN, TX_OR);
}
else if (UX_DEVICE_REMOVAL == event)
{
/* Clear the event flag in case the camera was removed before the application could clear it. */
tx_event_flags_set(&g_usb_plug_events, EVENT_USB_PLUG_OUT, TX_OR);
video_host_class = NULL;
}
else
{
/* Do nothing */
}
}
return status;
}
/* USB HOST initialization. */
static UINT usb_host_initialization (void)
{
UINT status;
UINT size = sizeof(UX_DEVICE);
/* ux host stack initialization */
status = ux_host_stack_initialize(apl_change_function);
if (status != UX_SUCCESS)
{
printf("UX_HOST_STACK_INITIALIZE API FAILED..\r\n");
return UX_ERROR;
}
/* Register all the USB host controllers available in this system */
status = ux_host_stack_hcd_register(_ux_system_host_hcd_ohci_name, ux_hcd_ohci_initialize, OHCI_ADDRESS, 0x0);
if (status != UX_SUCCESS)
{
printf("OHCI regist FAILED..\r\n");
return UX_ERROR;
}
status = ux_host_stack_hcd_register(_ux_system_host_hcd_ehci_name, ux_hcd_ehci_initialize, EHCI_ADDRESS, 0x0);
if (status != UX_SUCCESS)
{
printf("EHCI regist FAILED..\r\n");
return UX_ERROR;
}
return UX_SUCCESS;
}
/* Video data received callback function. */
VOID uvc_transfer_request_done_callback (UX_TRANSFER * transfer_request)
{
/* This is the callback function invoked by UVC class after a packet of
* data is received. */
/* The actual number of bytes being received into the data buffer is
* recorded in transfer_request -> ux_transfer_request_actual_length. */
/* Since this callback function executes in the USB host controller
* thread, a semaphore is released so the application can pick up the
* video data in application thread. */
frame_data[frame_index].length = transfer_request->ux_transfer_request_actual_length;
frame_index++;
if (MAX_NUM_BUFFERS <= frame_index)
{
frame_index = 0;
}
tx_semaphore_put(&g_data_received_semaphore);
}
/* Show the interval types */
VOID uvc_parameter_interval_list (UX_HOST_CLASS_VIDEO * video, int width, int height)
{
UX_HOST_CLASS_VIDEO_FRAME_DESCRIPTOR frame_descriptor;
ULONG min_frame_interval;
int i;
/* Make the descriptor machine independent. */
_ux_utility_descriptor_parse(video->ux_host_class_video_current_frame_address,
_ux_system_class_video_frame_descriptor_structure,
UX_HOST_CLASS_VIDEO_FRAME_DESCRIPTOR_ENTRIES,
(UCHAR *) &frame_descriptor);
/* Check the frame interval type. */
if (frame_descriptor.bFrameIntervalType == 0)
{
if (camera_spec_count < (int) (sizeof(camera_spec) / sizeof(camera_spec[0])))
{
/* Frame interval type is continuous. */
min_frame_interval = _ux_utility_long_get(
video->ux_host_class_video_current_frame_address + OFFSET_MIN_FRAME_INTERVAL);
_ux_utility_long_get(video->ux_host_class_video_current_frame_address + OFFSET_MAX_FRAME_INTERVAL);
_ux_utility_long_get(video->ux_host_class_video_current_frame_address + OFFSET_FRAME_INTERVAL_STEP);
camera_spec[camera_spec_count].width = width;
camera_spec[camera_spec_count].height = height;
camera_spec[camera_spec_count].interval = (int) min_frame_interval;
if (0 < camera_spec_count)
{
/* select high-level spec */
if (width > camera_spec[camera_spec_select].width)
{
camera_spec_select = camera_spec_count;
}
}
camera_spec_count++;
}
}
else
{
/* Frame interval type is discrete. */
for (i = 0; i < (int) frame_descriptor.bFrameIntervalType; i++)
{
if (camera_spec_count < (int) (sizeof(camera_spec) / sizeof(camera_spec[0])))
{
camera_spec[camera_spec_count].width = width;
camera_spec[camera_spec_count].height = height;
camera_spec[camera_spec_count].interval = (int) _ux_utility_long_get(video->ux_host_class_video_current_frame_address +
26 + (unsigned int) i *
sizeof(ULONG));
if (0 < camera_spec_count)
{
/* select high-level spec */
if (width > camera_spec[camera_spec_select].width)
{
camera_spec_select = camera_spec_count;
}
}
camera_spec_count++;
}
else
{
break;
}
}
}
}
/* Show the frame resolutions */
UINT uvc_parameter_frame_list (UX_HOST_CLASS_VIDEO * video)
{
ULONG frames_index;
UX_HOST_CLASS_VIDEO_PARAMETER_FRAME_DATA frame_parameter;
UINT status = UX_SUCCESS;
/* frame resolutions */
for (frames_index = 1; frames_index <= video->ux_host_class_video_number_frames; frames_index++)
{
/* Get frame data for current frame index. */
frame_parameter.ux_host_class_video_parameter_frame_requested = frames_index;
status = _ux_host_class_video_frame_data_get(video, &frame_parameter);
if (status != UX_SUCCESS)
{
return status;
}
/* Save the current frame index. */
video->ux_host_class_video_current_frame = frames_index;
uvc_parameter_interval_list(video,
(int) frame_parameter.ux_host_class_video_parameter_frame_width,
(int) frame_parameter.ux_host_class_video_parameter_frame_height);
}
return status;
}
/* Show the device parameters */
VOID uvc_parameter_list (UX_HOST_CLASS_VIDEO * video, int format)
{
ULONG format_index;
UX_HOST_CLASS_VIDEO_PARAMETER_FORMAT_DATA format_parameter;
UINT status = UX_SUCCESS;
/* format types */
for (format_index = 1; format_index <= video->ux_host_class_video_number_formats; format_index++)
{
/* Get format data for current format index. */
format_parameter.ux_host_class_video_parameter_format_requested = format_index;
status = _ux_host_class_video_format_data_get(video, &format_parameter);
if (status == UX_SUCCESS)
{
if ((int) format_parameter.ux_host_class_video_parameter_format_subtype == format)
{
/* Save number of frames in the video instance. */
video->ux_host_class_video_number_frames =
format_parameter.ux_host_class_video_parameter_number_frame_descriptors;
uvc_parameter_frame_list(video);
break;
}
}
}
}
/* End of Frame. */
VOID uvc_frame_finish (UCHAR * p_frame)
{
UINT old_threshold;
tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
if (video_host_class)
{
/* Add the buffer back for video transfer. */
ux_host_class_video_transfer_buffer_add(video_host_class, p_frame);
}
tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
}
/* Get the camera spec. */
int uvc_camera_spec_get (SPEC_OF_CAMERA ** p_camera_spec, int * p_select)
{
if (p_camera_spec != NULL)
{
*p_camera_spec = camera_spec;
}
if (p_select != NULL)
{
*p_select = camera_spec_select;
}
return camera_spec_count;
}
/* Set the camera spec. */
void uvc_camera_spec_set (int select)
{
if (select < camera_spec_count)
{
camera_spec_select = select;
}
}
/* Stop camera. */
void uvc_camera_stop (void)
{
if (video_host_class != NULL)
{
/* Stop video transfer. */
ux_host_class_video_stop(video_host_class);
}
}
/* Start camera. */
void uvc_camera_start (void)
{
UINT status;
UX_HOST_CLASS_VIDEO_PARAMETER_CHANNEL channel;
/* Index variable keeping track of the current buffer being used by the video device. */
ULONG buffer_index;
if (video_host_class != NULL)
{
/* Set video parameters. This setting value is a dummy.
* Depending on the application, set the necessary parameters. */
if (camera_spec_select < camera_spec_count)
{
ux_host_class_video_frame_parameters_set(video_host_class, UX_HOST_CLASS_VIDEO_VS_FORMAT_UNCOMPRESSED,
(ULONG) camera_spec[camera_spec_select].width,
camera_spec[camera_spec_select].height,
(ULONG) camera_spec[camera_spec_select].interval);
}
else
{
ux_host_class_video_frame_parameters_set(video_host_class,
UX_HOST_CLASS_VIDEO_VS_FORMAT_UNCOMPRESSED,
FIRST_SELECT_WIDTH,
FIRST_SELECT_HEIGHT,
FIRST_SELECT_INTERVAL);
}
/* Set the user callback function of video class. */
ux_host_class_video_transfer_callback_set(video_host_class, uvc_transfer_request_done_callback);
/* Find out the maximum memory buffer size for the video configuration
* set above. */
ux_host_class_video_max_payload_get(video_host_class);
/* Clear semaphore to zero */
while (1)
{
if (tx_semaphore_get(&g_data_received_semaphore, 0) == TX_NO_INSTANCE)
{
break;
}
}
/* Start video transfer. */
status = ux_host_class_video_start(video_host_class);
if (status != UX_SUCCESS)
{
/* Setting these to zero is a hack since we're mixing old and new APIs (new API does this and is required for reads). */
video_host_class->ux_host_class_video_transfer_request_start_index = 0;
video_host_class->ux_host_class_video_transfer_request_end_index = 0;
channel.ux_host_class_video_parameter_format_requested =
video_host_class->ux_host_class_video_current_format;
channel.ux_host_class_video_parameter_frame_requested =
video_host_class->ux_host_class_video_current_frame;
channel.ux_host_class_video_parameter_frame_interval_requested =
video_host_class->ux_host_class_video_current_frame_interval;
channel.ux_host_class_video_parameter_channel_bandwidth_selection = CHANNEL_BANDWIDTH_SELECTION;
ux_host_class_video_ioctl(video_host_class, UX_HOST_CLASS_VIDEO_IOCTL_CHANNEL_START, &channel);
}
#if HIGH_BANDWIDTH_EHCI /* Driver HCD must support adding requests list. */
{
UCHAR * video_buffers[MAX_NUM_BUFFERS];
for (buffer_index = 0; buffer_index < MAX_NUM_BUFFERS; buffer_index++)
{
frame_data[buffer_index].p_frame = (ULONG) video_buffer[buffer_index];
video_buffers[buffer_index] = (UCHAR *) frame_data[buffer_index].p_frame;
}
/* Issue transfer request list to start streaming. */
ux_host_class_video_transfer_buffers_add(video_host_class, video_buffers, MAX_NUM_BUFFERS);
}
#elif NORMAL_BANDWIDTH_OHCI /* Driver adds request one by one. */
/* Allocate space for video buffer. */
for (buffer_index = 0; buffer_index < MAX_NUM_BUFFERS; buffer_index++)
{
frame_data[buffer_index].p_frame = (ULONG) video_buffer[buffer_index];
/* Add buffer to the video device for video streaming data. */
ux_host_class_video_transfer_buffer_add(video_host_class, frame_data[buffer_index].p_frame);
}
#endif
}
frame_index = 0;
}
/* USB Thread entry function */
void camera_thread_entry (void)
{
UINT status;
int loop_count;
/* Create the flags and the semaphore for video control. */
status = tx_event_flags_create(&g_device_insert_eventflag, (CHAR *) "Device Insert Event Flags");
if (status != TX_SUCCESS)
{
printf("UVC event flags create FAILED..\r\n");
return;
}
status = tx_semaphore_create(&g_data_received_semaphore, (CHAR *) "Data Receive Semaphore", 0);
if (status != TX_SUCCESS)
{
printf("UVC semaphore create FAILED..\r\n");
return;
}
status = ux_host_startup(&g_basic0_ctrl, &g_basic0_cfg, usb_host_initialization);
if (status != UX_SUCCESS)
{
printf("ux_host_startup API FAILED..\r\n");
return;
}
printf("Init completed!\r\n\r\n");
printf("Please insert USB camera for work.\r\n");
/* Wait until device inserted.*/
tx_event_flags_get(&g_usb_plug_events, EVENT_USB_PLUG_IN, TX_AND_CLEAR, &actual_flags, TX_WAIT_FOREVER);
if (EVENT_USB_PLUG_IN == actual_flags)
{
printf("USB camera is inserted\r\n");
}
/* Reset the event flag */
actual_flags = 0;
loop_count = 0;
/* List parameters */
camera_spec_count = 0;
camera_spec_select = 0;
/* Create the image receive thread. */
status = tx_thread_create(&image_receive_thread,
(CHAR *) "Image Receive Thread",
image_receive_thread_entry,
(ULONG) NULL,
&image_receive_thread_stack,
sizeof(image_receive_thread_stack),
12,
12,
0,
TX_AUTO_START);
if (status != TX_SUCCESS)
{
printf("Image Receive thread failed.\r\n");
}
/* This delay is required for now to get valid ISO IN UX_ENDPOINT instance. */
tx_thread_sleep(THREAD_SLEEP_TIME);
while (true)
{
loop_count++;
/* Check if USB is plugged out.*/
tx_event_flags_get(&g_usb_plug_events, EVENT_USB_PLUG_OUT, TX_AND_CLEAR, &actual_flags, TX_NO_WAIT);
if (EVENT_USB_PLUG_OUT == actual_flags)
{
printf("\r\nPlease insert USB camera for work.\r\n\r\n");
actual_flags = 0;
/* Wait until device inserted.*/
while (EVENT_USB_PLUG_IN != actual_flags)
{
tx_event_flags_get(&g_usb_plug_events, EVENT_USB_PLUG_IN, TX_AND_CLEAR, &actual_flags, TX_WAIT_FOREVER);
if (EVENT_USB_PLUG_IN == actual_flags)
{
printf("USB camera is inserted\r\n");
loop_count = 0;
/* This delay is required for now to get valid ISO IN UX_ENDPOINT instance. */
tx_thread_sleep(THREAD_SLEEP_TIME);
/* List parameters */
camera_spec_count = 0;
camera_spec_select = 0;
}
}
}
else
{
tx_thread_sleep(THREAD_SLEEP_TIME);
}
}
}
/* update image data from mjpeg thread */
void display_image_update (void)
{
if (tx_mutex_get(&image_mutex, TX_WAIT_FOREVER) == TX_SUCCESS)
{
/* Change current_display_image */
current_display_image = current_stream_image;
/* Change current_stream_image */
current_stream_index++;
if (MAX_STREAM_BUFFER <= current_stream_index)
{
current_stream_index = 0;
}
current_stream_image = &stream_buffer[current_stream_index];
tx_mutex_put(&image_mutex);
// Notify GUIX of REDRAW events.
// event.gx_event_type = GX_EVENT_REDRAW;
// gx_system_event_send(&event);
}
/* If the mutex cannot be obtained, it will update the current image. */
}
/* get image data from display thread */
ULONG display_image_get (UCHAR ** image)
{
ULONG rtn = 0;
if (tx_mutex_get(&image_mutex, TX_WAIT_FOREVER) == TX_SUCCESS)
{
/* Returns the current image data. */
if (current_display_image != NULL)
{
rtn = current_display_image->length;
if (image != NULL)
{
*image = current_display_image->image;
}
}
if (rtn == 0)
{
tx_mutex_put(&image_mutex);
}
else
{
image_get_log[image_get_idx] = tx_time_get();
image_get_idx++;
if (image_get_idx >= REC_LOG_NUM)
{
image_get_idx = 0;
}
}
}
return rtn;
}
/* release image data from display thread */
void display_image_release (void)
{
current_display_image = NULL;
tx_mutex_put(&image_mutex);
}
/* check image data and update */
int check_stream (FRAME_DATA * p_frame_data)
{
ULONG time_tick;
ULONG time_tick2;
uvc_stream_header_t * uvc_stream_header;
char * image_stream_data;
int image_stream_length;
if (0 < p_frame_data->length)
{
/* Get UVC stream header */
uvc_stream_header = (uvc_stream_header_t *) p_frame_data->p_frame;
image_stream_data = &((char *) p_frame_data->p_frame)[sizeof(uvc_stream_header_t)];
image_stream_length = (int) (p_frame_data->length - sizeof(uvc_stream_header_t));
if (0 < image_stream_length)
{
if (stream_status == STREAM_STATUS_FIND)
{
if (2 <= image_stream_length)
{
/* check SOF */
if ((fid != (int) (uvc_stream_header->bmHeaderInfo & UVC_STREAM_HEADER_HEADERINFO_FID)))
{
// Records the tick at the start of image reception.
time_tick = tx_time_get();
receive_count = 0;
rec_log[rec_log_idx].start_tick = time_tick;
/* stream data active */
stream_status = STREAM_STATUS_DATA_ACTIVE;
current_stream_image->length = 0;
fid = (int) (uvc_stream_header->bmHeaderInfo & UVC_STREAM_HEADER_HEADERINFO_FID);
}
}
}
if ((stream_status != STREAM_STATUS_FIND) &&
(fid != (int) (uvc_stream_header->bmHeaderInfo & UVC_STREAM_HEADER_HEADERINFO_FID)))
{
/* The frame data has been lost. Start over from the frame start search. */
stream_status = STREAM_STATUS_FIND;
current_stream_image->length = 0;
fid = -1;
return 0;
}
if (stream_status != STREAM_STATUS_FIND)
{
if (MAX_STREAM_SIZE < (current_stream_image->length + (ULONG) image_stream_length))
{
/* The storage area has been exceeded. Start over from the frame start search. */
stream_status = STREAM_STATUS_FIND;
current_stream_image->length = 0;
return 0;
}
receive_count++;
/* copy to stream buffer */
memcpy(&current_stream_image->image[current_stream_image->length],
image_stream_data,
(size_t) image_stream_length);
current_stream_image->length += (ULONG) image_stream_length;
}
if ((uvc_stream_header->bmHeaderInfo & UVC_STREAM_HEADER_HEADERINFO_EOF) != 0)
{
// Records the tick at the end of image reception.
time_tick = tx_time_get();
rec_log[rec_log_idx].end_tick = time_tick;
rec_log[rec_log_idx].rec_count = receive_count;
rec_log[rec_log_idx].length = current_stream_image->length;
rec_log_idx++;
if (rec_log_idx >= REC_LOG_NUM)
{
rec_log_idx = 0;
}
display_image_update();
stream_status = STREAM_STATUS_FIND;
current_stream_image->length = 0;
fid = -1;
}
}
}
return 0;
}
/* Define the image receive thread. */
void image_receive_thread_entry (ULONG thread_input)
{
tx_mutex_create(&image_mutex, "image mutex", TX_NO_INHERIT);
// event.gx_event_target = 0;
// event.gx_event_sender = GX_ID_NONE;
do
{
uvc_camera_stop();
stream_status = STREAM_STATUS_FIND; /* find top stream data */
frame_check_index = 0;
current_stream_image = &stream_buffer[0];
current_stream_image->length = 0;
uvc_camera_start();
while (tx_semaphore_get(&g_data_received_semaphore, THREAD_SLEEP_TIME * 2) == TX_SUCCESS)
{
/* UVC data is received, the data is analyzed. */
if (check_stream(&frame_data[frame_check_index]) == 0)
{
/* Release the UVC data. */
uvc_frame_finish((UCHAR *) frame_data[frame_check_index].p_frame);
frame_check_index++;
if (MAX_NUM_BUFFERS <= frame_check_index)
{
frame_check_index = 0;
}
}
}
} while (1);
tx_mutex_delete(&image_mutex);
}

USBX HHID Example

HHID user interface example is as follows.

void keyboard_update_task (ULONG thread_input)
{
ULONG usbx_return_value;
/* keyboard button masks, set by ux_host_class_hid_keyboard_buttons_get call */
ULONG keyboard_key = 0;
/* keyboard state masks, set by ux_host_class_hid_keyboard_buttons_get call */
ULONG keyboard_state = 0;
FSP_PARAMETER_NOT_USED(thread_input);
while (1)
{
usbx_return_value = ux_host_class_hid_keyboard_key_get(
(UX_HOST_CLASS_HID_KEYBOARD *) hid_keyboard_client->ux_host_class_hid_client_local_instance,
&keyboard_key,
&keyboard_state);
if ((usbx_return_value == UX_SUCCESS) || (usbx_return_value == UX_NO_KEY_PRESS))
{
hid_devices_info.device_connected = KEYBOARD_DEVICE;
hid_devices_info.key = keyboard_key;
hid_devices_info.keyboard_status = keyboard_state;
/* Clear the states for next read */
keyboard_key = 0;
keyboard_state = 0;
/* copy the keyboard states to queue */
tx_queue_send(&device_parameters, &hid_devices_info, TX_NO_WAIT);
}
tx_thread_sleep(10);
}
}
void mouse_update_task (ULONG thread_input)
{
/* mouse button masks, set by ux_host_class_hid_mouse_buttons_get call */
ULONG mouse_buttons;
/* X co-ordinate displacement of mouse */
SLONG mouse_x_position = 0;
/* Y co-ordinate displacement of mouse */
SLONG mouse_y_position = 0;
/* variable to hold USBX return values */
ULONG usbx_return_value;
FSP_PARAMETER_NOT_USED(thread_input);
while (1)
{
usbx_return_value = ux_host_class_hid_mouse_buttons_get(
(UX_HOST_CLASS_HID_MOUSE *) hid_mouse_client->ux_host_class_hid_client_local_instance,
&mouse_buttons);
if (usbx_return_value == UX_SUCCESS)
{
usbx_return_value = ux_host_class_hid_mouse_position_get(
(UX_HOST_CLASS_HID_MOUSE *) hid_mouse_client->ux_host_class_hid_client_local_instance,
&mouse_x_position,
&mouse_y_position);
}
if (usbx_return_value == UX_SUCCESS)
{
hid_devices_info.device_connected = MOUSE_DEVICE;
hid_devices_info.key = mouse_buttons;
hid_devices_info.mouse_direction_X = mouse_x_position;
hid_devices_info.mouse_direction_Y = mouse_y_position;
tx_queue_send(&device_parameters, &hid_devices_info, TX_NO_WAIT);
}
tx_thread_sleep(10);
}
}
void usbx_hhid_sample (void)
{
uint8_t i;
ux_system_initialize((CHAR *) g_ux_pool_memory, MEMPOOL_SIZE, UX_NULL, 0);
ux_host_stack_initialize(ux_system_host_hid_change_function);
g_usb_on_usb.open(&g_basic0_ctrl, &g_basic0_cfg);
tx_thread_create(&keyboard_update,
(CHAR *) "keyboard_update_task",
keyboard_update_task,
(ULONG) NULL,
&keyboard_update_stack,
2048,
22,
2,
1,
TX_AUTO_START);
tx_thread_create(&mouse_update,
(CHAR *) "mouse_update_task",
mouse_update_task,
(ULONG) NULL,
&mouse_update_stack,
1024,
22,
2,
1,
TX_AUTO_START);
while (1)
{
for (i = 0; i < UX_HOST_CLASS_HID_MAX_CLIENTS; i++)
{
/* Check whether the instance registered? through USB HID device insertion callback? */
if (NULL != hid_class_keyboard_instance[i])
{
UX_HOST_CLASS_HID_CLIENT * hid_client = hid_class_keyboard_instance[i]->ux_host_class_hid_client;
hid_keyboard_client = hid_client;
tx_thread_sleep(10);
}
/* Check whether the instance registered? through USB HID device insertion callback? */
if (NULL != hid_class_mouse_instance[i])
{
UX_HOST_CLASS_HID_CLIENT * hid_client = hid_class_mouse_instance[i]->ux_host_class_hid_client;
hid_mouse_client = hid_client;
tx_thread_sleep(10);
}
/* If multiple similar type devices are connected, allow them one by one share data with application */
tx_thread_sleep(10);
}
}
}