Middleware for the Azure RTOS USBX Porting Layer on RZ MPUs.
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
Using a class other than HMSC. The following describes how to configure USBX using HCDC as an example.
1.Select [New Stack]->[Azure RTOS]->[USBX]->[HCDC]
Select USB Device Class
2.The following is displayed when selecting USBX HCDC.
USBX HCDC Stack
3.Select the USB pipe to use.
Select using USB Pipe
Using HMSC. Since HMSC is used in a different way from other USBX modules, the usage is described below.
1.Select [New Stack]->[Azure RTOS]->[FileX]->[FileX on USBX]
Select USB Device Class
2.The following is displayed when selecting Filex on USBX.
FileX on USBX Stack
Note
- The following are notes on using the ux_host_class_cdc_acm_read function or the ux_device_class_cdc_acm_read function.
- 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.
- 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.
- Peripheral
- PCDC
- ux_system_initialize
- ux_device_stack_initialize
- ux_device_stack_class_register
- Host
- HCDC / HHID / HUVC
- ux_system_initialize
- ux_host_stack_initialize
- HMSC
- ux_system_initialize
- ux_host_stack_initialize
- fx_system_initialize
2.Set the value for 1000 Ticks per second in the "Timer Ticks Per Second" item.
Specify value of Timer Ticks Per Second
3.Set the Thread priority to a value of 21.
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.
- Peripheral
- PCDC
- _ux_device_stack_class_unregister
- _ux_device_stack_uninitialize
- Host
- _ux_host_stack_uninitialize
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.
- rm_usbx_pcdc_descriptor.c.template
- Comment on lines 108 and 243.
- Delete the "//" on lines 109 and 242.
Examples
USBX PCDC Example
PCDC loopback example is as follows.
#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)
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[];
UINT usbx_status_callback(ULONG status);
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);
#define UX_DEMO_BUFFER_SIZE 2048
#define RESET_VALUE (0x00)
#define MEMPOOL_SIZE (64 * 1024)
#define BYTE_SIZE sizeof(uint32_t)
UX_SLAVE_CLASS_CDC_ACM * g_cdc = UX_NULL;
UCHAR buffer[UX_DEMO_BUFFER_SIZE];
static uint32_t g_ux_pool_memory[MEMPOOL_SIZE / BYTE_SIZE] USB_BUFFER_PLACE_IN_SECTION;
static UX_SLAVE_CLASS_CDC_ACM_PARAMETER g_ux_device_class_cdc_acm0_parameter;
static ULONG g_actual_length;
void usbx_pcdc_sample (void)
{
UINT status;
ULONG actual_length;
ULONG requested_length;
tx_thread_sleep(10);
status = ux_system_initialize(g_ux_pool_memory, MEMPOOL_SIZE, UX_NULL, RESET_VALUE);
if (UX_SUCCESS != status)
{
printf("Initialization failed.\r\n");
return;
}
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);
if (UX_SUCCESS != status)
{
printf("Initialization failed.\r\n");
return;
}
g_ux_device_class_cdc_acm0_parameter.ux_slave_class_cdc_acm_instance_activate = ux_cdc_device0_instance_activate;
g_ux_device_class_cdc_acm0_parameter.ux_slave_class_cdc_acm_instance_deactivate =
ux_cdc_device0_instance_deactivate;
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);
if (UX_SUCCESS != status)
{
printf("Initialization failed.\r\n");
return;
}
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)
{
if (g_cdc != UX_NULL)
{
status = ux_device_class_cdc_acm_read(g_cdc, buffer, UX_DEMO_BUFFER_SIZE, &actual_length);
if (status == UX_SUCCESS)
{
requested_length = actual_length;
ux_device_class_cdc_acm_write(g_cdc, buffer, requested_length, &g_actual_length);
ux_utility_memory_set(buffer, 0, sizeof(buffer));
}
else
{
tx_thread_sleep(VALUE_50);
}
}
else
{
tx_thread_sleep(VALUE_50);
}
}
}
static void ux_cdc_device0_instance_activate (void * cdc_instance)
{
g_cdc = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance;
}
static void ux_cdc_device0_instance_deactivate (void * cdc_instance)
{
g_cdc = UX_NULL;
}
UINT usbx_status_callback (ULONG status)
{
switch (status)
{
case UX_DEVICE_ATTACHED:
break;
case UX_DEVICE_REMOVED:
break;
default:
{
break;
}
}
return 0;
}
USBX HCDC Example
The main functions of the HCDC loopback example are as follows:
- Virtual UART control settings are configured by transmitting the class request SET_LINE_CODING to the CDC device.
- Sends receive (Bulk In transfer) requests to a CDC peripheral device and receives data.
- 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)
{
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)
{
p_cdc_acm = p_cdc_acm->ux_host_class_cdc_acm_next_instance;
if (p_cdc_acm->ux_host_class_cdc_acm_interface->ux_interface_descriptor.bInterfaceClass !=
UX_HOST_CLASS_CDC_DATA_CLASS)
{
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)
{
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;
}
}
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;
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)))
{
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)
{
g_p_media = UX_NULL;
tx_event_flags_set(&g_usb_plug_events, EVENT_USB_PLUG_OUT, TX_OR);
}
else
{
}
}
return status;
}
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)
{
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);
}
p_media = g_p_media;
fx_return = fx_media_volume_get(p_media, volume, FX_DIRECTORY_SECTOR);
if (FX_SUCCESS == fx_return)
{
fx_directory_default_set(p_media, "firstdir");
tx_thread_sleep(VALUE_100);
fx_return = fx_file_open(p_media, &g_file, "counter.txt", (FX_OPEN_FOR_READ | FX_OPEN_FOR_WRITE));
if (FX_SUCCESS != fx_return)
{
fx_return = fx_file_create(p_media, "counter.txt");
if (FX_SUCCESS != fx_return)
{
break;
}
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;
}
}
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)
{
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;
}
fx_return = fx_file_seek(&g_file, 0);
if (FX_SUCCESS == fx_return)
{
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);
}
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);
}
fx_return = fx_media_flush(p_media);
if (FX_SUCCESS != fx_return)
{
tx_thread_sleep(TX_WAIT_FOREVER);
}
fx_return = fx_media_close(p_media);
if (FX_SUCCESS != fx_return)
{
tx_thread_sleep(TX_WAIT_FOREVER);
}
tx_event_flags_get(&g_usb_plug_events, EVENT_USB_PLUG_OUT, TX_OR_CLEAR, &actual_flags, TX_WAIT_FOREVER);
}
}
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);
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);
}
p_media = g_p_media;
memset(g_fx_media0_media_memory, 0x00, sizeof(g_fx_media0_media_memory));
status = fx_media_format(p_media,
p_media->fx_media_driver_entry,
p_media->fx_media_driver_info,
g_fx_media0_media_memory,
p_media->fx_media_memory_size,
"sample",
p_media->fx_media_number_of_FATs,
p_media->fx_media_root_directory_entries,
p_media->fx_media_hidden_sectors,
(ULONG) p_media->fx_media_total_sectors,
p_media->fx_media_bytes_per_sector,
p_media->fx_media_sectors_per_cluster,
p_media->fx_media_heads,
p_media->fx_media_sectors_per_track);
if ((uint8_t) FX_SUCCESS != status)
{
__BKPT(0);
}
}
USBX HUVC Example
HUVC example is as follows.
#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)
#define FIRST_SELECT_WIDTH 640
#define FIRST_SELECT_HEIGHT 480
#define FIRST_SELECT_INTERVAL 333333
#define HIGH_BANDWIDTH_EHCI 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;
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;
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);
extern TX_EVENT_FLAGS_GROUP g_usb_plug_events;
TX_EVENT_FLAGS_GROUP g_device_insert_eventflag;
TX_SEMAPHORE g_data_received_semaphore;
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;
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;
STREAM_BUFFER stream_buffer[MAX_STREAM_BUFFER];
static int current_stream_index = 0;
STREAM_BUFFER * current_display_image = NULL;
STREAM_BUFFER * current_stream_image = &stream_buffer[0];
static TX_MUTEX image_mutex;
static int fid = -1;
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;
static int frame_check_index = 0;
static int stream_status;
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)
{
video_host_class = instance;
tx_event_flags_set(&g_usb_plug_events, EVENT_USB_PLUG_IN, TX_OR);
}
else if (UX_DEVICE_REMOVAL == event)
{
tx_event_flags_set(&g_usb_plug_events, EVENT_USB_PLUG_OUT, TX_OR);
video_host_class = NULL;
}
else
{
}
}
return status;
}
static UINT usb_host_initialization (void)
{
UINT status;
UINT size = sizeof(UX_DEVICE);
status = ux_host_stack_initialize(apl_change_function);
if (status != UX_SUCCESS)
{
printf("UX_HOST_STACK_INITIALIZE API FAILED..\r\n");
return UX_ERROR;
}
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;
}
VOID uvc_transfer_request_done_callback (UX_TRANSFER * transfer_request)
{
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);
}
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;
_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);
if (frame_descriptor.bFrameIntervalType == 0)
{
if (camera_spec_count < (int) (sizeof(camera_spec) / sizeof(camera_spec[0])))
{
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)
{
if (width > camera_spec[camera_spec_select].width)
{
camera_spec_select = camera_spec_count;
}
}
camera_spec_count++;
}
}
else
{
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)
{
if (width > camera_spec[camera_spec_select].width)
{
camera_spec_select = camera_spec_count;
}
}
camera_spec_count++;
}
else
{
break;
}
}
}
}
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;
for (frames_index = 1; frames_index <= video->ux_host_class_video_number_frames; frames_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;
}
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;
}
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;
for (format_index = 1; format_index <= video->ux_host_class_video_number_formats; 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)
{
video->ux_host_class_video_number_frames =
format_parameter.ux_host_class_video_parameter_number_frame_descriptors;
uvc_parameter_frame_list(video);
break;
}
}
}
}
VOID uvc_frame_finish (UCHAR * p_frame)
{
UINT old_threshold;
tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold);
if (video_host_class)
{
ux_host_class_video_transfer_buffer_add(video_host_class, p_frame);
}
tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold);
}
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;
}
void uvc_camera_spec_set (int select)
{
if (select < camera_spec_count)
{
camera_spec_select = select;
}
}
void uvc_camera_stop (void)
{
if (video_host_class != NULL)
{
ux_host_class_video_stop(video_host_class);
}
}
void uvc_camera_start (void)
{
UINT status;
UX_HOST_CLASS_VIDEO_PARAMETER_CHANNEL channel;
ULONG buffer_index;
if (video_host_class != NULL)
{
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);
}
ux_host_class_video_transfer_callback_set(video_host_class, uvc_transfer_request_done_callback);
ux_host_class_video_max_payload_get(video_host_class);
while (1)
{
if (tx_semaphore_get(&g_data_received_semaphore, 0) == TX_NO_INSTANCE)
{
break;
}
}
status = ux_host_class_video_start(video_host_class);
if (status != UX_SUCCESS)
{
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
{
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;
}
ux_host_class_video_transfer_buffers_add(video_host_class, video_buffers, MAX_NUM_BUFFERS);
}
#elif NORMAL_BANDWIDTH_OHCI
for (buffer_index = 0; buffer_index < MAX_NUM_BUFFERS; buffer_index++)
{
frame_data[buffer_index].p_frame = (ULONG) video_buffer[buffer_index];
ux_host_class_video_transfer_buffer_add(video_host_class, frame_data[buffer_index].p_frame);
}
#endif
}
frame_index = 0;
}
void camera_thread_entry (void)
{
UINT status;
int loop_count;
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");
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");
}
actual_flags = 0;
loop_count = 0;
camera_spec_count = 0;
camera_spec_select = 0;
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");
}
tx_thread_sleep(THREAD_SLEEP_TIME);
while (true)
{
loop_count++;
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;
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;
tx_thread_sleep(THREAD_SLEEP_TIME);
camera_spec_count = 0;
camera_spec_select = 0;
}
}
}
else
{
tx_thread_sleep(THREAD_SLEEP_TIME);
}
}
}
void display_image_update (void)
{
if (tx_mutex_get(&image_mutex, TX_WAIT_FOREVER) == TX_SUCCESS)
{
current_display_image = 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);
}
}
ULONG display_image_get (UCHAR ** image)
{
ULONG rtn = 0;
if (tx_mutex_get(&image_mutex, TX_WAIT_FOREVER) == TX_SUCCESS)
{
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;
}
void display_image_release (void)
{
current_display_image = NULL;
tx_mutex_put(&image_mutex);
}
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)
{
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)
{
if ((fid != (int) (uvc_stream_header->bmHeaderInfo & UVC_STREAM_HEADER_HEADERINFO_FID)))
{
time_tick = tx_time_get();
receive_count = 0;
rec_log[rec_log_idx].start_tick = time_tick;
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)))
{
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))
{
stream_status = STREAM_STATUS_FIND;
current_stream_image->length = 0;
return 0;
}
receive_count++;
memcpy(¤t_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)
{
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;
}
void image_receive_thread_entry (ULONG thread_input)
{
tx_mutex_create(&image_mutex, "image mutex", TX_NO_INHERIT);
do
{
uvc_camera_stop();
stream_status = STREAM_STATUS_FIND;
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)
{
if (check_stream(&frame_data[frame_check_index]) == 0)
{
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;
ULONG keyboard_key = 0;
ULONG keyboard_state = 0;
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;
keyboard_key = 0;
keyboard_state = 0;
tx_queue_send(&device_parameters, &hid_devices_info, TX_NO_WAIT);
}
tx_thread_sleep(10);
}
}
void mouse_update_task (ULONG thread_input)
{
ULONG mouse_buttons;
SLONG mouse_x_position = 0;
SLONG mouse_y_position = 0;
ULONG usbx_return_value;
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++)
{
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);
}
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);
}
tx_thread_sleep(10);
}
}
}