mirror of
https://github.com/azure-rtos/usbx.git
synced 2025-01-28 07:03:07 +08:00
6ed7092b77
Add regression tests (auto triggered on PR, manually triggered in forked branch).
1839 lines
58 KiB
C
1839 lines
58 KiB
C
#include "ux_test.h"
|
|
#include "ux_test_hcd_sim_host.h"
|
|
#include "ux_test_dcd_sim_slave.h"
|
|
|
|
#ifndef _ux_utility_time_elapsed
|
|
#define _ux_utility_time_elapsed(t0,t1) ((t1)>=(t0) ? ((t1)-(t0)) : (0xFFFFFFFF - (t0) + (t1)))
|
|
#endif
|
|
|
|
#define UX_TEST_TIMEOUT_MS 3000
|
|
|
|
static UX_TEST_ACTION ux_test_action_handler_check(UX_TEST_ACTION *action, UX_TEST_FUNCTION usbx_function, void *params, UCHAR advance);
|
|
|
|
UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter);
|
|
UINT _ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter);
|
|
void test_control_return(UINT);
|
|
extern ULONG ux_test_port_status;
|
|
|
|
static UX_TEST_ACTION *ux_test_hook_action_list; /* Link list, with .next NULL as end. */
|
|
static UX_TEST_ACTION *ux_test_main_action_list; /* Link list, with .next NULL as end. */
|
|
static UX_TEST_ACTION *ux_test_user_list_actions;/* Link list, with .created_list_next NULL as end. */
|
|
static UCHAR ux_test_expedient = 1;
|
|
static UCHAR ignore_all_errors = 0;
|
|
static UCHAR exit_on_errors = 0;
|
|
static ULONG ux_test_memory_test_no_device_memory_free_amount;
|
|
|
|
static UCHAR ux_test_assert_hit_hint_off = 0;
|
|
static UCHAR ux_test_assert_hit_exit_off = 0;
|
|
static ULONG ux_test_assert_hit_count = 0;
|
|
static UINT ux_test_assert_hit_exit_code = 1;
|
|
|
|
VOID _ux_test_main_action_list_thread_update(TX_THREAD *old, TX_THREAD *new)
|
|
{
|
|
UX_TEST_ACTION *list = ux_test_main_action_list;
|
|
if (old != new)
|
|
{
|
|
while(list)
|
|
{
|
|
if (list->thread_ptr == old)
|
|
list->thread_ptr == new;
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID _ux_test_main_action_list_semaphore_update(TX_SEMAPHORE *old, TX_SEMAPHORE *new)
|
|
{
|
|
UX_TEST_ACTION *list = ux_test_main_action_list;
|
|
if (old != new)
|
|
{
|
|
while(list)
|
|
{
|
|
if (list->semaphore_ptr == old)
|
|
list->semaphore_ptr == new;
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID _ux_test_main_action_list_mutex_update(TX_MUTEX *old, TX_MUTEX *new)
|
|
{
|
|
UX_TEST_ACTION *list = ux_test_main_action_list;
|
|
if (old != new)
|
|
{
|
|
while(list)
|
|
{
|
|
if (list->mutex_ptr == old)
|
|
list->mutex_ptr == new;
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
UCHAR _ux_test_check_action_function(UX_TEST_ACTION *new_actions)
|
|
{
|
|
|
|
UCHAR result;
|
|
|
|
|
|
#ifndef UX_TEST_RACE_CONDITION_TESTS_ON
|
|
result = (new_actions->usbx_function > 0 && new_actions->usbx_function < (ULONG)UX_TEST_OVERRIDE_RACE_CONDITION_OVERRIDES);
|
|
#else
|
|
result = (new_actions->_usbx_function > 0 && new_actions->_usbx_function < (ULONG)UX_TEST_NUMBER_OVERRIDES);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
VOID _ux_test_append_action(UX_TEST_ACTION *list, UX_TEST_ACTION *new_action)
|
|
{
|
|
|
|
UX_TEST_ACTION *tail;
|
|
|
|
|
|
tail = list;
|
|
while (tail->next != UX_NULL)
|
|
tail = tail->next;
|
|
tail->next = new_action;
|
|
}
|
|
|
|
UINT ux_test_list_action_compare(UX_TEST_ACTION *list_item, UX_TEST_ACTION *action)
|
|
{
|
|
UX_TEST_ACTION temp;
|
|
UINT status;
|
|
|
|
/* It's created one, check its contents. */
|
|
if (list_item->created_list_next == list_item)
|
|
{
|
|
/* Copy action contents to test. */
|
|
temp = *action;
|
|
|
|
/* Set action next, created to match. */
|
|
temp.next = list_item->next;
|
|
temp.created_list_next = list_item->created_list_next;
|
|
|
|
/* Compare. */
|
|
status = ux_utility_memory_compare(list_item, &temp, sizeof(temp));
|
|
|
|
/* Return success if equal. */
|
|
if (status == UX_SUCCESS)
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
|
|
/* It's static one, check address. */
|
|
if (list_item == action)
|
|
return UX_SUCCESS;
|
|
}
|
|
|
|
/* No, they do not match. */
|
|
return UX_NO_CLASS_MATCH;
|
|
}
|
|
|
|
VOID ux_test_remove_hook(UX_TEST_ACTION *action)
|
|
{
|
|
UX_TEST_ACTION *item;
|
|
UX_TEST_ACTION *previous;
|
|
|
|
item = ux_test_hook_action_list;
|
|
while(item)
|
|
{
|
|
if (ux_test_list_action_compare(item, action) != UX_SUCCESS)
|
|
{
|
|
previous = item;
|
|
item = item->next;
|
|
continue;
|
|
}
|
|
|
|
/* Remove action from head. */
|
|
if (item == ux_test_hook_action_list)
|
|
{
|
|
ux_test_hook_action_list = item->next;
|
|
}
|
|
|
|
/* Remove action from list. */
|
|
else
|
|
{
|
|
previous->next = action->next;
|
|
}
|
|
|
|
/* Free if it's created. */
|
|
if (action->created_list_next == action)
|
|
free(action);
|
|
|
|
/* Remove is done. */
|
|
return;
|
|
}
|
|
}
|
|
|
|
UINT ux_test_link_hook(UX_TEST_ACTION *action)
|
|
{
|
|
UX_TEST_ACTION *tail;
|
|
|
|
if (ux_test_hook_action_list == UX_NULL)
|
|
{
|
|
ux_test_hook_action_list = action;
|
|
}
|
|
else
|
|
{
|
|
tail = ux_test_hook_action_list;
|
|
while(tail)
|
|
{
|
|
/* Check existing. */
|
|
if (ux_test_list_action_compare(tail, action) == UX_SUCCESS)
|
|
return UX_ERROR;
|
|
|
|
/* Check next. */
|
|
if (tail->next == UX_NULL)
|
|
break;
|
|
|
|
tail = tail->next;
|
|
}
|
|
tail->next = action;
|
|
}
|
|
return UX_SUCCESS;
|
|
}
|
|
|
|
UINT ux_test_add_hook(UX_TEST_ACTION action)
|
|
{
|
|
UX_TEST_ACTION *created_action;
|
|
UINT status;
|
|
|
|
created_action = (UX_TEST_ACTION *)malloc(sizeof(UX_TEST_ACTION));
|
|
UX_TEST_ASSERT(created_action);
|
|
|
|
*created_action = action;
|
|
|
|
created_action->next = UX_NULL;
|
|
|
|
/* We use the memory pointer to indicate it's added by memory allocation.
|
|
* On clean up or free we should free allocated memory.
|
|
*/
|
|
created_action->created_list_next = created_action;
|
|
|
|
status = ux_test_link_hook(created_action);
|
|
if (status != UX_SUCCESS)
|
|
{
|
|
free(created_action);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
VOID ux_test_remove_hooks_from_array(UX_TEST_ACTION *actions)
|
|
{
|
|
UX_TEST_ACTION *action;
|
|
|
|
action = actions;
|
|
while(action->usbx_function)
|
|
{
|
|
//printf("rm %p\n", action);
|
|
UX_TEST_ASSERT(_ux_test_check_action_function(action));
|
|
ux_test_remove_hook(action);
|
|
action ++;
|
|
}
|
|
}
|
|
|
|
VOID ux_test_remove_hooks_from_list(UX_TEST_ACTION *actions)
|
|
{
|
|
UX_TEST_ACTION *action;
|
|
UX_TEST_ACTION *next;
|
|
|
|
action = actions;
|
|
while(action)
|
|
{
|
|
UX_TEST_ASSERT(_ux_test_check_action_function(action));
|
|
next = action->next;
|
|
ux_test_remove_hook(action);
|
|
action = next;
|
|
}
|
|
}
|
|
|
|
VOID ux_test_link_hooks_from_array(UX_TEST_ACTION *actions)
|
|
{
|
|
UX_TEST_ACTION *action;
|
|
|
|
action = actions;
|
|
while(action->usbx_function)
|
|
{
|
|
UX_TEST_ASSERT(_ux_test_check_action_function(action));
|
|
ux_test_link_hook(action);
|
|
action ++;
|
|
}
|
|
}
|
|
|
|
VOID ux_test_link_hooks_from_list(UX_TEST_ACTION *actions)
|
|
{
|
|
UX_TEST_ACTION *action;
|
|
|
|
action = actions;
|
|
while(action)
|
|
{
|
|
UX_TEST_ASSERT(_ux_test_check_action_function(action));
|
|
ux_test_link_hook(action);
|
|
action = action->next;
|
|
}
|
|
}
|
|
|
|
VOID ux_test_add_hooks_from_array(UX_TEST_ACTION *actions)
|
|
{
|
|
UX_TEST_ACTION *action;
|
|
|
|
action = actions;
|
|
while(action->usbx_function)
|
|
{
|
|
UX_TEST_ASSERT(_ux_test_check_action_function(action));
|
|
ux_test_add_hook(*action);
|
|
action ++;
|
|
}
|
|
}
|
|
|
|
VOID ux_test_add_hooks_from_list(UX_TEST_ACTION *actions)
|
|
{
|
|
UX_TEST_ACTION *action;
|
|
|
|
action = actions;
|
|
while(action)
|
|
{
|
|
UX_TEST_ASSERT(_ux_test_check_action_function(action));
|
|
ux_test_add_hook(*action);
|
|
action = action->next;
|
|
}
|
|
}
|
|
|
|
ULONG ux_test_do_hooks_before(UX_TEST_FUNCTION usbx_function, VOID *params)
|
|
{
|
|
UX_TEST_ACTION *list;
|
|
UX_TEST_ACTION action;
|
|
ULONG action_count = 0;
|
|
ULONG action_return = 0;
|
|
|
|
list = ux_test_hook_action_list;
|
|
while(list)
|
|
{
|
|
action = ux_test_action_handler_check(list, usbx_function, params, UX_FALSE);
|
|
if (action.matched && !action.do_after)
|
|
{
|
|
action_count ++;
|
|
if (!action.no_return)
|
|
action_return = 0x80000000u;
|
|
}
|
|
ux_test_do_action_before(&action, params);
|
|
list = list->next;
|
|
}
|
|
return (action_count | action_return);
|
|
}
|
|
|
|
VOID ux_test_do_hooks_after(UX_TEST_FUNCTION usbx_function, VOID *params)
|
|
{
|
|
UX_TEST_ACTION *list;
|
|
UX_TEST_ACTION action;
|
|
ULONG action_count = 0;
|
|
|
|
list = ux_test_hook_action_list;
|
|
while(list)
|
|
{
|
|
action = ux_test_action_handler_check(list, usbx_function, params, UX_FALSE);
|
|
if (action.matched)
|
|
action_count ++;
|
|
ux_test_do_action_after(&action, params);
|
|
list = list->next;
|
|
}
|
|
}
|
|
|
|
VOID ux_test_free_hook_actions()
|
|
{
|
|
UX_TEST_ACTION *action;
|
|
|
|
while(ux_test_hook_action_list)
|
|
{
|
|
action = ux_test_hook_action_list;
|
|
ux_test_hook_action_list = ux_test_hook_action_list->next;
|
|
|
|
/* If this action is added/created, free allocated memory. */
|
|
if (action->created_list_next == action)
|
|
{
|
|
free(action);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID _ux_test_add_action_to_list(UX_TEST_ACTION *list, UX_TEST_ACTION action)
|
|
{
|
|
|
|
UX_TEST_ACTION *new_action = UX_NULL;
|
|
UX_TEST_ACTION *tail;
|
|
|
|
|
|
/* Do some idiot-proof checks. */
|
|
{
|
|
/* Check the function. */
|
|
#ifndef UX_TEST_RACE_CONDITION_TESTS_ON
|
|
UX_TEST_ASSERT((action.usbx_function > 0 && action.usbx_function < (ULONG)UX_TEST_OVERRIDE_RACE_CONDITION_OVERRIDES));
|
|
#else
|
|
UX_TEST_ASSERT((action._usbx_function > 0 && action._usbx_function < (ULONG)UX_TEST_NUMBER_OVERRIDES));
|
|
#endif
|
|
|
|
/* Make sure expedient is on when it should be. */
|
|
if (action.no_return == 0 &&
|
|
/* For user callbacks, it's okay. */
|
|
action.usbx_function < UX_TEST_OVERRIDE_USER_CALLBACKS)
|
|
{
|
|
/* Allowed if flow stopped to avoid low level operations. */
|
|
#if 0
|
|
UX_TEST_ASSERT(ux_test_is_expedient_on());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (/* Is this the main list? */
|
|
list == ux_test_main_action_list ||
|
|
/* Is the head of user-list already an action? */
|
|
list->usbx_function)
|
|
{
|
|
new_action = (UX_TEST_ACTION *)malloc(sizeof(UX_TEST_ACTION));
|
|
*new_action = action;
|
|
new_action->next = UX_NULL;
|
|
}
|
|
|
|
if (list == ux_test_main_action_list)
|
|
{
|
|
|
|
if (!ux_test_main_action_list)
|
|
ux_test_main_action_list = new_action;
|
|
else
|
|
_ux_test_append_action(list, new_action);
|
|
}
|
|
else
|
|
{
|
|
|
|
if (!list->usbx_function)
|
|
*list = action;
|
|
else
|
|
{
|
|
|
|
/* Append to user created list. */
|
|
if (!ux_test_user_list_actions)
|
|
ux_test_user_list_actions = new_action;
|
|
else
|
|
{
|
|
|
|
tail = ux_test_user_list_actions;
|
|
while (tail->created_list_next)
|
|
tail = tail->created_list_next;
|
|
tail->created_list_next = new_action;
|
|
}
|
|
|
|
_ux_test_append_action(list, new_action);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID ux_test_add_action_to_main_list(UX_TEST_ACTION new_action)
|
|
{
|
|
|
|
_ux_test_add_action_to_list(ux_test_main_action_list, new_action);
|
|
}
|
|
|
|
VOID ux_test_add_action_to_main_list_multiple(UX_TEST_ACTION new_action, UINT num)
|
|
{
|
|
|
|
while (num--)
|
|
_ux_test_add_action_to_list(ux_test_main_action_list, new_action);
|
|
}
|
|
|
|
VOID ux_test_add_action_to_user_list(UX_TEST_ACTION *list, UX_TEST_ACTION new_action)
|
|
{
|
|
|
|
_ux_test_add_action_to_list(list, new_action);
|
|
}
|
|
|
|
VOID ux_test_set_main_action_list_from_list(UX_TEST_ACTION *new_actions)
|
|
{
|
|
|
|
UX_TEST_ASSERT(!ux_test_main_action_list);
|
|
while (new_actions)
|
|
{
|
|
|
|
ux_test_add_action_to_main_list(*new_actions);
|
|
new_actions = new_actions->next;
|
|
}
|
|
}
|
|
|
|
VOID ux_test_set_main_action_list_from_array(UX_TEST_ACTION *new_actions)
|
|
{
|
|
|
|
UX_TEST_ASSERT(!ux_test_main_action_list);
|
|
while (new_actions->usbx_function)
|
|
{
|
|
|
|
ux_test_add_action_to_main_list(*new_actions);
|
|
new_actions++;
|
|
}
|
|
}
|
|
|
|
VOID ux_test_free_user_list_actions()
|
|
{
|
|
|
|
UX_TEST_ACTION *action;
|
|
|
|
|
|
while (ux_test_user_list_actions)
|
|
{
|
|
|
|
action = ux_test_user_list_actions;
|
|
ux_test_user_list_actions = ux_test_user_list_actions->created_list_next;
|
|
free(action);
|
|
}
|
|
}
|
|
|
|
static VOID _ux_test_advance_actions()
|
|
{
|
|
|
|
UX_TEST_ACTION *action;
|
|
|
|
|
|
UX_TEST_ASSERT(ux_test_main_action_list != UX_NULL);
|
|
action = ux_test_main_action_list;
|
|
ux_test_main_action_list = ux_test_main_action_list->next;
|
|
free(action);
|
|
}
|
|
|
|
VOID ux_test_clear_main_list_actions()
|
|
{
|
|
|
|
while (ux_test_main_action_list)
|
|
_ux_test_advance_actions();
|
|
}
|
|
|
|
VOID _ux_test_set_actions_and_set_function(UX_TEST_ACTION *new_actions, UX_TEST_FUNCTION function)
|
|
{
|
|
|
|
UX_TEST_ASSERT(new_actions != UX_NULL);
|
|
|
|
while (new_actions->function || new_actions->usbx_function)
|
|
{
|
|
|
|
if (new_actions->function && !new_actions->usbx_function)
|
|
new_actions->usbx_function = function;
|
|
ux_test_add_action_to_main_list(*new_actions);
|
|
new_actions++;
|
|
}
|
|
}
|
|
|
|
VOID ux_test_hcd_sim_host_set_actions(UX_TEST_ACTION *new_actions)
|
|
{
|
|
|
|
ux_test_clear_main_list_actions();
|
|
|
|
if (new_actions != UX_NULL)
|
|
_ux_test_set_actions_and_set_function(new_actions, UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY);
|
|
}
|
|
|
|
VOID ux_test_dcd_sim_slave_set_actions(UX_TEST_ACTION *new_actions)
|
|
{
|
|
|
|
ux_test_clear_main_list_actions();
|
|
|
|
if (new_actions != UX_NULL)
|
|
_ux_test_set_actions_and_set_function(new_actions, UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION);
|
|
}
|
|
|
|
/* Returns whether there are any actions in the list. */
|
|
UCHAR ux_test_check_actions_empty()
|
|
{
|
|
return(ux_test_main_action_list == UX_NULL ? UX_TRUE : UX_FALSE);
|
|
}
|
|
|
|
UINT ux_test_wait_for_empty_actions()
|
|
{
|
|
return ux_test_wait_for_null((VOID **)&ux_test_main_action_list);
|
|
}
|
|
|
|
UINT ux_test_wait_for_empty_actions_wait_time(UINT wait_time_ms)
|
|
{
|
|
return ux_test_wait_for_null_wait_time((VOID **)&ux_test_main_action_list, wait_time_ms);
|
|
}
|
|
|
|
UINT ux_test_get_num_actions_left()
|
|
{
|
|
|
|
UINT num_actions_remaining = 0;
|
|
UX_TEST_ACTION *action = ux_test_main_action_list;
|
|
|
|
|
|
while (action)
|
|
{
|
|
num_actions_remaining++;
|
|
action = action->next;
|
|
}
|
|
|
|
return(num_actions_remaining);
|
|
}
|
|
|
|
VOID _ux_host_class_storage_driver_read_write_notify(VOID *func);
|
|
|
|
VOID ux_test_cleanup_everything(VOID)
|
|
{
|
|
|
|
/* Free main list actions. */
|
|
ux_test_clear_main_list_actions();
|
|
|
|
/* Free allocated user list actions. */
|
|
ux_test_free_user_list_actions();
|
|
|
|
/* Free added hook actions. */
|
|
ux_test_free_hook_actions();
|
|
|
|
/* Reset expedient value. */
|
|
ux_test_expedient = UX_TRUE;
|
|
|
|
/* Reset free memory test amount. */
|
|
ux_test_memory_test_no_device_memory_free_amount = 0;
|
|
|
|
/* Assert related. */
|
|
ux_test_assert_hit_count = 0;
|
|
ux_test_assert_hit_hint_off = 0;
|
|
ux_test_assert_hit_exit_off = 0;
|
|
ux_test_assert_hit_exit_code = 1;
|
|
|
|
#if defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
|
|
_ux_host_class_storage_driver_read_write_notify(UX_NULL);
|
|
#endif
|
|
}
|
|
|
|
VOID ux_test_do_action_before(UX_TEST_ACTION *action, VOID *params)
|
|
{
|
|
|
|
if (action->matched && !action->do_after)
|
|
{
|
|
if (action->action_func)
|
|
{
|
|
action->action_func(action, params);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID ux_test_do_action_after(UX_TEST_ACTION *action, VOID *params)
|
|
{
|
|
|
|
if (action->matched && action->do_after)
|
|
{
|
|
if (action->action_func)
|
|
{
|
|
action->action_func(action, params);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID ux_test_turn_on_expedient(UCHAR *original_expedient)
|
|
{
|
|
|
|
if (original_expedient)
|
|
{
|
|
*original_expedient = ux_test_expedient;
|
|
}
|
|
ux_test_expedient = 1;
|
|
}
|
|
|
|
VOID ux_test_turn_off_expedient(UCHAR *original_expedient)
|
|
{
|
|
|
|
if (original_expedient)
|
|
{
|
|
*original_expedient = ux_test_expedient;
|
|
}
|
|
ux_test_expedient = 0;
|
|
}
|
|
|
|
VOID ux_test_set_expedient(UCHAR value)
|
|
{
|
|
|
|
ux_test_expedient = value;
|
|
}
|
|
|
|
UCHAR ux_test_is_expedient_on()
|
|
{
|
|
|
|
return(ux_test_expedient);
|
|
}
|
|
|
|
UX_TEST_ACTION ux_test_action_handler(UX_TEST_FUNCTION usbx_function, void *params)
|
|
{
|
|
return ux_test_action_handler_check(ux_test_main_action_list, usbx_function, params, UX_TRUE);
|
|
}
|
|
|
|
static UX_TEST_ACTION ux_test_action_handler_check(UX_TEST_ACTION *list, UX_TEST_FUNCTION usbx_function, void *params, UCHAR advance)
|
|
{
|
|
|
|
UINT i;
|
|
UINT min;
|
|
UX_TEST_ACTION *this = list;
|
|
UX_TEST_ACTION result = { 0 };
|
|
UCHAR act = 0;
|
|
UX_TRANSFER *host_req;
|
|
UX_SLAVE_TRANSFER *slave_req;
|
|
ULONG *slave_req_code = UX_NULL;
|
|
UINT *req_code = UX_NULL;
|
|
ULONG *req_actual_len = UX_NULL;
|
|
UX_ENDPOINT *ep;
|
|
TX_THREAD *this_thread;
|
|
UX_TEST_SETUP req_setup;
|
|
UX_TEST_SIM_ENTRY_ACTION generic_transfer_parameter = { 0 };
|
|
UX_TEST_GENERIC_CD *generic_cd_params;
|
|
UX_TEST_GENERIC_CD _generic_cd_params;
|
|
UINT str_len0;
|
|
UINT str_len1;
|
|
UCHAR ignore_param_checks = 0;
|
|
UX_TEST_OVERRIDE_TX_SEMAPHORE_GET_PARAMS *semaphore_get_params;
|
|
UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE_PARAMS *semaphore_create_params;
|
|
UX_TEST_OVERRIDE_TX_THREAD_CREATE_PARAMS *thread_create_params;
|
|
UX_TEST_ERROR_CALLBACK_PARAMS *error_callback_params;
|
|
UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS*device_media_read_write_flush_params;
|
|
UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS_PARAMS *device_media_status_params;
|
|
UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST_PARAMS *host_stack_transfer_request_params;
|
|
UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE_PARAMS *thread_preemption_change_params;
|
|
UX_TEST_OVERRIDE_UX_HOST_STACK_INTERFACE_SET_PARAMS *host_stack_interface_set_params;
|
|
UX_TEST_OVERRIDE_TX_MUTEX_GET_PARAMS *mutex_get_params;
|
|
UX_TEST_OVERRIDE_TX_MUTEX_PUT_PARAMS *mutex_put_params;
|
|
UX_TEST_OVERRIDE_TX_MUTEX_CREATE_PARAMS *mutex_create_params;
|
|
UX_TEST_OVERRIDE_NX_PACKET_POOL_CREATE_PARAMS *packet_pool_create_params;
|
|
UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE_PARAMS *packet_allocate_params;
|
|
|
|
|
|
if (this)
|
|
{
|
|
|
|
if (this->usbx_function == usbx_function)
|
|
{
|
|
|
|
/* If appropriate, setup generic controller driver (CD) parameter. */
|
|
if (this->usbx_function == UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY ||
|
|
this->usbx_function == UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION ||
|
|
this->usbx_function == UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST)
|
|
{
|
|
/* Treat a transfer request action like an HCD action. */
|
|
if (usbx_function == UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST)
|
|
{
|
|
host_stack_transfer_request_params = params;
|
|
generic_cd_params = &_generic_cd_params;
|
|
generic_cd_params->parameter = host_stack_transfer_request_params->transfer_request;
|
|
generic_cd_params->function = UX_HCD_TRANSFER_REQUEST;
|
|
}
|
|
else
|
|
{
|
|
generic_cd_params = params;
|
|
}
|
|
}
|
|
|
|
/* Should we ignore the param checking? */
|
|
if (this->ignore_params)
|
|
{
|
|
if (this->usbx_function == UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY ||
|
|
this->usbx_function == UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION)
|
|
{
|
|
/* Check the sub-function. */
|
|
if (this->function == generic_cd_params->function)
|
|
{
|
|
ignore_param_checks = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* There is no sub-function. */
|
|
ignore_param_checks = 1;
|
|
}
|
|
}
|
|
|
|
act = 1;
|
|
if (!ignore_param_checks)
|
|
{
|
|
switch (usbx_function)
|
|
{
|
|
|
|
case UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY:
|
|
case UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION:
|
|
case UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST:
|
|
|
|
act = 0;
|
|
if (this->function == generic_cd_params->function)
|
|
{
|
|
|
|
act = 1;
|
|
switch (generic_cd_params->function)
|
|
{
|
|
|
|
/* We have action on endpoint entries */
|
|
case UX_HCD_CREATE_ENDPOINT:
|
|
//case UX_DCD_CREATE_ENDPOINT:
|
|
case UX_HCD_DESTROY_ENDPOINT:
|
|
//case UX_DCD_DESTROY_ENDPOINT:
|
|
case UX_HCD_RESET_ENDPOINT:
|
|
//case UX_DCD_RESET_ENDPOINT:
|
|
case UX_DCD_ENDPOINT_STATUS:
|
|
case UX_DCD_STALL_ENDPOINT:
|
|
|
|
ep = generic_cd_params->parameter;
|
|
|
|
if ((this->req_action & UX_TEST_MATCH_EP) &&
|
|
this->req_ep_address != ep->ux_endpoint_descriptor.bEndpointAddress)
|
|
act = 0;
|
|
|
|
break;
|
|
|
|
/* We have action on transfer request abort */
|
|
case UX_HCD_TRANSFER_ABORT:
|
|
//case UX_DCD_TRANSFER_ABORT:
|
|
|
|
if (UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION != usbx_function)
|
|
{
|
|
|
|
host_req = (UX_TRANSFER *)generic_cd_params->parameter;
|
|
if ((this->req_action & UX_TEST_MATCH_EP) &&
|
|
this->req_ep_address != host_req->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress)
|
|
act = 0;
|
|
}
|
|
else
|
|
{
|
|
|
|
slave_req = (UX_SLAVE_TRANSFER *)generic_cd_params->parameter;
|
|
if ((this->req_action & UX_TEST_MATCH_EP) &&
|
|
this->req_ep_address != slave_req->ux_slave_transfer_request_endpoint->ux_slave_endpoint_descriptor.bEndpointAddress)
|
|
act = 0;
|
|
}
|
|
break;
|
|
|
|
/* We have action on transfer request */
|
|
case UX_HCD_TRANSFER_REQUEST:
|
|
//case UX_DCD_TRANSFER_REQUEST:
|
|
|
|
generic_transfer_parameter.req_setup = &req_setup;
|
|
|
|
if (usbx_function == UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY ||
|
|
usbx_function == UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST)
|
|
{
|
|
host_req = generic_cd_params->parameter;
|
|
|
|
generic_transfer_parameter.req_actual_len = host_req->ux_transfer_request_actual_length;
|
|
generic_transfer_parameter.req_data = host_req->ux_transfer_request_data_pointer;
|
|
generic_transfer_parameter.req_ep_address = host_req->ux_transfer_request_endpoint->ux_endpoint_descriptor.bEndpointAddress;
|
|
generic_transfer_parameter.req_requested_len = host_req->ux_transfer_request_requested_length;
|
|
generic_transfer_parameter.req_status = host_req->ux_transfer_request_status;
|
|
generic_transfer_parameter.req_setup->ux_test_setup_index = host_req->ux_transfer_request_index;
|
|
generic_transfer_parameter.req_setup->ux_test_setup_request = host_req->ux_transfer_request_function;
|
|
generic_transfer_parameter.req_setup->ux_test_setup_type = host_req->ux_transfer_request_type;
|
|
generic_transfer_parameter.req_setup->ux_test_setup_value = host_req->ux_transfer_request_value;
|
|
|
|
req_actual_len = &host_req->ux_transfer_request_actual_length;
|
|
req_code = &host_req->ux_transfer_request_completion_code;
|
|
}
|
|
else
|
|
{
|
|
slave_req = generic_cd_params->parameter;
|
|
|
|
generic_transfer_parameter.req_actual_len = slave_req->ux_slave_transfer_request_actual_length;
|
|
generic_transfer_parameter.req_data = slave_req->ux_slave_transfer_request_data_pointer;
|
|
generic_transfer_parameter.req_ep_address = slave_req->ux_slave_transfer_request_endpoint->ux_slave_endpoint_descriptor.bEndpointAddress;
|
|
generic_transfer_parameter.req_requested_len = slave_req->ux_slave_transfer_request_requested_length;
|
|
generic_transfer_parameter.req_status = slave_req->ux_slave_transfer_request_status;
|
|
generic_transfer_parameter.req_setup->ux_test_setup_type = (UCHAR)slave_req->ux_slave_transfer_request_type;
|
|
|
|
req_actual_len = &slave_req->ux_slave_transfer_request_actual_length;
|
|
slave_req_code = &slave_req->ux_slave_transfer_request_completion_code;
|
|
}
|
|
|
|
if (this->req_action & UX_TEST_MATCH_EP &&
|
|
this->req_ep_address != generic_transfer_parameter.req_ep_address)
|
|
act = 0;
|
|
|
|
/* We must confirm request setup is matching */
|
|
if (this->req_setup)
|
|
{
|
|
|
|
if ((this->req_action & UX_TEST_SETUP_MATCH_REQUEST) &&
|
|
(generic_transfer_parameter.req_setup->ux_test_setup_type != this->req_setup->ux_test_setup_type))
|
|
act = 0;
|
|
|
|
if ((this->req_action & UX_TEST_SETUP_MATCH_REQUEST) &&
|
|
(generic_transfer_parameter.req_setup->ux_test_setup_request != this->req_setup->ux_test_setup_request))
|
|
act = 0;
|
|
|
|
if ((this->req_action & UX_TEST_SETUP_MATCH_VALUE) &&
|
|
(generic_transfer_parameter.req_setup->ux_test_setup_value != this->req_setup->ux_test_setup_value))
|
|
act = 0;
|
|
|
|
if ((this->req_action & UX_TEST_SETUP_MATCH_INDEX) &&
|
|
(generic_transfer_parameter.req_setup->ux_test_setup_index != this->req_setup->ux_test_setup_index))
|
|
act = 0;
|
|
}
|
|
|
|
/* Compare data. We only do the comparison if this action is not meant for substituting data. */
|
|
if (!(this->req_action & UX_TEST_SIM_REQ_ANSWER) && this->req_data)
|
|
{
|
|
if (generic_transfer_parameter.req_data == UX_NULL ||
|
|
/* Make sure we don't go off the end during the compare. */
|
|
generic_transfer_parameter.req_requested_len < this->req_actual_len)
|
|
act = 0;
|
|
else
|
|
{
|
|
|
|
/* Is there no mask? */
|
|
if (!this->req_data_match_mask)
|
|
{
|
|
if (ux_utility_memory_compare(generic_transfer_parameter.req_data, this->req_data, this->req_actual_len) == UX_ERROR)
|
|
{
|
|
act = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Compare with mask. */
|
|
for (i = 0; i < this->req_actual_len; i++)
|
|
{
|
|
if (this->req_data_match_mask[i] &&
|
|
this->req_data[i] != generic_transfer_parameter.req_data[i])
|
|
{
|
|
act = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Compare requested lengths. */
|
|
if ((this->req_action & UX_TEST_MATCH_REQ_LEN) &&
|
|
(generic_transfer_parameter.req_requested_len != this->req_requested_len))
|
|
act = 0;
|
|
|
|
/* Do additional check. */
|
|
if (this->check_func && !this->check_func())
|
|
act = 0;
|
|
|
|
break;
|
|
|
|
case UX_DCD_CHANGE_STATE:
|
|
case UX_HCD_RESET_PORT:
|
|
case UX_HCD_ENABLE_PORT:
|
|
case UX_HCD_GET_PORT_STATUS:
|
|
|
|
/* AFAIK, there's nothing to check here. */
|
|
|
|
break;
|
|
|
|
/* The other entries are not handled now */
|
|
default:
|
|
UX_TEST_ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
#if 0
|
|
case UX_TEST_OVERRIDE_UX_UTILITY_MEMORY_ALLOCATE:
|
|
|
|
memory_allocate_params = params;
|
|
if (memory_allocate_params->memory_alignment != this->memory_alignment ||
|
|
memory_allocate_params->memory_cache_flag != this->memory_cache_flag ||
|
|
memory_allocate_params->memory_size_requested != this->memory_size_requested)
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case UX_TEST_OVERRIDE_TX_SEMAPHORE_GET:
|
|
|
|
semaphore_get_params = params;
|
|
|
|
if (this->semaphore_ptr != UX_NULL && semaphore_get_params->semaphore_ptr != this->semaphore_ptr ||
|
|
semaphore_get_params->wait_option != this->wait_option)
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_ERROR_CALLBACK:
|
|
|
|
error_callback_params = params;
|
|
if ((this->error_code && error_callback_params->error_code != this->error_code) ||
|
|
(this->system_context && error_callback_params->system_context != this->system_context) ||
|
|
(this->system_level && error_callback_params->system_level != this->system_level))
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ:
|
|
|
|
device_media_read_write_flush_params = params;
|
|
if ((device_media_read_write_flush_params->lba != this->lba ||
|
|
device_media_read_write_flush_params->lun != this->lun ||
|
|
device_media_read_write_flush_params->number_blocks != this->number_blocks))
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_WRITE:
|
|
|
|
device_media_read_write_flush_params = params;
|
|
if ((device_media_read_write_flush_params->lba != this->lba ||
|
|
device_media_read_write_flush_params->lun != this->lun ||
|
|
device_media_read_write_flush_params->number_blocks != this->number_blocks))
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_FLUSH:
|
|
|
|
device_media_read_write_flush_params = params;
|
|
if ((device_media_read_write_flush_params->lba != this->lba ||
|
|
device_media_read_write_flush_params->lun != this->lun ||
|
|
device_media_read_write_flush_params->number_blocks != this->number_blocks))
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS:
|
|
|
|
device_media_status_params = params;
|
|
if ((device_media_status_params->lun != this->lun ||
|
|
device_media_status_params->media_id != this->media_id))
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_NX_PACKET_POOL_CREATE:
|
|
|
|
packet_pool_create_params = params;
|
|
|
|
/* We just compare names. */
|
|
|
|
UX_TEST_ASSERT(this->name_ptr != UX_NULL);
|
|
|
|
if (strcmp(packet_pool_create_params->name_ptr, this->name_ptr))
|
|
{
|
|
act = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_NX_PACKET_ALLOCATE:
|
|
|
|
packet_allocate_params = params;
|
|
|
|
/* We just compare names. */
|
|
|
|
UX_TEST_ASSERT(this->name_ptr != UX_NULL);
|
|
|
|
if (strcmp(packet_allocate_params->pool_ptr->nx_packet_pool_name, this->name_ptr))
|
|
{
|
|
act = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_TX_THREAD_CREATE:
|
|
|
|
thread_create_params = params;
|
|
|
|
/* We just compare names. */
|
|
|
|
UX_TEST_ASSERT(this->name_ptr != UX_NULL);
|
|
|
|
if (strcmp(thread_create_params->name_ptr, this->name_ptr))
|
|
{
|
|
act = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_TX_SEMAPHORE_CREATE:
|
|
|
|
semaphore_create_params = params;
|
|
|
|
/* We just compare names. */
|
|
|
|
UX_TEST_ASSERT(this->semaphore_name != UX_NULL);
|
|
|
|
if (strcmp(semaphore_create_params->semaphore_name, this->semaphore_name))
|
|
{
|
|
act = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE:
|
|
|
|
thread_preemption_change_params = params;
|
|
if (this->thread_ptr != thread_preemption_change_params->thread_ptr ||
|
|
this->new_threshold != thread_preemption_change_params->new_threshold)
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_UX_HOST_STACK_INTERFACE_SET:
|
|
|
|
host_stack_interface_set_params = params;
|
|
if (this->interface->ux_interface_descriptor.bInterfaceNumber != host_stack_interface_set_params->interface->ux_interface_descriptor.bInterfaceNumber ||
|
|
this->interface->ux_interface_descriptor.bAlternateSetting != host_stack_interface_set_params->interface->ux_interface_descriptor.bAlternateSetting)
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_TX_MUTEX_GET:
|
|
|
|
mutex_get_params = params;
|
|
if (this->mutex_ptr &&
|
|
this->mutex_ptr != mutex_get_params->mutex_ptr)
|
|
{
|
|
act = 0;
|
|
}
|
|
if (mutex_get_params->wait_option != this->wait_option)
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_TX_MUTEX_CREATE:
|
|
|
|
mutex_create_params = params;
|
|
if (this->mutex_ptr &&
|
|
this->mutex_ptr != mutex_create_params->mutex_ptr)
|
|
{
|
|
act = 0;
|
|
}
|
|
if (mutex_create_params->inherit != this->inherit)
|
|
{
|
|
act = 0;
|
|
}
|
|
if (this->name_ptr != UX_NULL)
|
|
{
|
|
str_len0 = 0;
|
|
_ux_utility_string_length_check(this->name_ptr, &str_len0, 2048);
|
|
if (mutex_create_params->name_ptr != UX_NULL)
|
|
{
|
|
str_len1 = 0;
|
|
_ux_utility_string_length_check(mutex_create_params->name_ptr, &str_len1, 2048);
|
|
}
|
|
else
|
|
{
|
|
str_len1 = 0;
|
|
}
|
|
if (str_len0 != str_len1)
|
|
{
|
|
act = 0;
|
|
}
|
|
if (str_len0 == str_len1 &&
|
|
ux_utility_memory_compare(this->name_ptr, mutex_create_params->name_ptr, str_len0) != UX_SUCCESS)
|
|
{
|
|
act = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case UX_TEST_OVERRIDE_TX_MUTEX_PUT:
|
|
|
|
mutex_put_params = params;
|
|
if (this->mutex_ptr != UX_NULL &&
|
|
this->mutex_ptr != mutex_put_params->mutex_ptr)
|
|
{
|
|
act = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Non-param checks - these checks happen regardless of the "ignore_params"
|
|
value. */
|
|
|
|
if (this->thread_to_match)
|
|
{
|
|
this_thread = tx_thread_identify();
|
|
if (this_thread != this->thread_to_match)
|
|
act = 0;
|
|
}
|
|
|
|
if (this->check_func && this->check_func(params) != UX_TRUE)
|
|
{
|
|
act = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (act)
|
|
{
|
|
|
|
//stepinfo(" action matched; usbx_function: %d\n", usbx_function);
|
|
|
|
if (usbx_function == UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY ||
|
|
usbx_function == UX_TEST_OVERRIDE_UX_DCD_SIM_SLAVE_FUNCTION ||
|
|
usbx_function == UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST)
|
|
{
|
|
|
|
/* Apply to port status */
|
|
if (this -> port_action)
|
|
{
|
|
|
|
UX_TEST_ASSERT(!this->no_return);
|
|
|
|
ux_test_port_status = this -> port_status;
|
|
// printf("Port status -> %lx\n", port_status);
|
|
/* Signal change on the port (HCD0.RH.PORT0). */
|
|
_ux_system_host -> ux_system_host_hcd_array -> ux_hcd_root_hub_signal[0] = 1;
|
|
/* Signal detach to host enum thread. */
|
|
_ux_host_semaphore_put(&_ux_system_host -> ux_system_host_enum_semaphore);
|
|
}
|
|
|
|
/* Apply to transfer */
|
|
if (this -> req_action & UX_TEST_SIM_REQ_ANSWER)
|
|
{
|
|
|
|
/* We should always return, otherwise the data we copy will just
|
|
get overridden by the actual transfer request. */
|
|
UX_TEST_ASSERT(!this->no_return);
|
|
|
|
/* Is there data to copy? */
|
|
if (this->req_data)
|
|
{
|
|
/* Make sure we don't overflow. */
|
|
min = generic_transfer_parameter.req_requested_len < this->req_actual_len ? generic_transfer_parameter.req_requested_len : this->req_actual_len;
|
|
|
|
/* Copy the data. */
|
|
_ux_utility_memory_copy(generic_transfer_parameter.req_data, this->req_data, min);
|
|
}
|
|
|
|
/* Set actual length */
|
|
if (this->req_actual_len == (~0))
|
|
*req_actual_len = generic_transfer_parameter.req_requested_len;
|
|
else
|
|
*req_actual_len = this->req_actual_len;
|
|
|
|
/* Set status code */
|
|
if (usbx_function == UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY ||
|
|
usbx_function == UX_TEST_OVERRIDE_UX_HOST_STACK_TRANSFER_REQUEST)
|
|
*req_code = this->req_status;
|
|
else
|
|
*slave_req_code = this->req_status;
|
|
}
|
|
}
|
|
|
|
result = *this;
|
|
result.matched = 1;
|
|
|
|
if (advance)
|
|
_ux_test_advance_actions();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#define SLEEP_STEP 1
|
|
UINT ux_test_breakable_sleep(ULONG tick, UINT (*sleep_break_check_callback)(VOID))
|
|
{
|
|
|
|
UINT status;
|
|
ULONG t;
|
|
|
|
while(tick) {
|
|
|
|
/* Sleep for a while. */
|
|
t = (tick > SLEEP_STEP) ? SLEEP_STEP : tick;
|
|
#if defined(UX_HOST_STANDALONE) || defined(UX_DEVICE_STANDALONE)
|
|
ux_system_tasks_run();
|
|
#endif
|
|
tx_thread_sleep(t);
|
|
|
|
/* Check if we want to break. */
|
|
if (sleep_break_check_callback)
|
|
{
|
|
|
|
status = sleep_break_check_callback();
|
|
if (status != UX_SUCCESS)
|
|
{
|
|
|
|
/* We break sleep loop!
|
|
Status is returned for use to check. */
|
|
return status;
|
|
}
|
|
}
|
|
|
|
/* Update remaining ticks. */
|
|
tick -= t;
|
|
}
|
|
|
|
/* Normal end. */
|
|
return UX_SUCCESS;
|
|
}
|
|
UINT ux_test_sleep_break_if(ULONG tick, UINT (*check)(VOID),
|
|
UINT break_on_match_or_not,
|
|
UINT rc_to_check)
|
|
{
|
|
ULONG t0, t1;
|
|
UINT status;
|
|
|
|
t0 = tx_time_get();
|
|
while(1)
|
|
{
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ux_system_tasks_run();
|
|
tx_thread_relinquish();
|
|
#else
|
|
tx_thread_sleep(1);
|
|
#endif
|
|
if (check)
|
|
{
|
|
status = check();
|
|
if (break_on_match_or_not)
|
|
{
|
|
/* If RC match expected, break. */
|
|
if (status == rc_to_check)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/* If RC not match expected, break. */
|
|
if (status != rc_to_check)
|
|
break;
|
|
}
|
|
}
|
|
t1 = tx_time_get();
|
|
if (_ux_utility_time_elapsed(t0, t1) >= tick)
|
|
{
|
|
return(UX_TIMEOUT);
|
|
}
|
|
}
|
|
return(UX_SUCCESS);
|
|
}
|
|
|
|
/* Error callback */
|
|
|
|
UX_TEST_ERROR_CALLBACK_ERROR ux_error_hcd_transfer_stalled = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_STALLED };
|
|
|
|
VOID ux_test_ignore_all_errors()
|
|
{
|
|
ignore_all_errors = UX_TRUE;
|
|
}
|
|
|
|
VOID ux_test_unignore_all_errors()
|
|
{
|
|
ignore_all_errors = UX_FALSE;
|
|
}
|
|
|
|
void test_control_return(UINT status);
|
|
VOID ux_test_error_callback(UINT system_level, UINT system_context, UINT error_code)
|
|
{
|
|
|
|
UX_TEST_ERROR_CALLBACK_PARAMS params = { system_level, system_context, error_code };
|
|
UX_TEST_ACTION action;
|
|
|
|
|
|
if (ignore_all_errors == UX_TRUE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ux_test_do_hooks_before(UX_TEST_OVERRIDE_ERROR_CALLBACK, ¶ms))
|
|
return;
|
|
|
|
action = ux_test_action_handler(UX_TEST_OVERRIDE_ERROR_CALLBACK, ¶ms);
|
|
if (action.matched)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Failed test. Windows has some stupid printf bug where it stalls
|
|
everything if other threads are printing as well. Doesn't matter anyways,
|
|
since I use breakpoints for debugging this error. */
|
|
#ifndef WIN32
|
|
printf("%s:%d Unexpected error: 0x%x, 0x%x, 0x%x\n", __FILE__, __LINE__, system_level, system_context, error_code);
|
|
#endif
|
|
|
|
if (exit_on_errors)
|
|
test_control_return(1);
|
|
}
|
|
|
|
/* Utility methods. */
|
|
|
|
static ULONG ux_test_memory_test_no_device_memory_free_amount;
|
|
|
|
void ux_test_memory_test_initialize()
|
|
{
|
|
|
|
UCHAR connected_when_started = 0;
|
|
|
|
/* Are we connected? */
|
|
if (_ux_system_host->ux_system_host_hcd_array[0].ux_hcd_nb_devices != 0)
|
|
{
|
|
/* Yes. */
|
|
connected_when_started = 1;
|
|
|
|
/* Then disconnect. */
|
|
ux_test_disconnect_slave_and_host_wait_for_enum_completion();
|
|
}
|
|
|
|
/* Get normal amount of free memory when disconnected. This is to detect
|
|
memory leaks. */
|
|
ux_test_memory_test_no_device_memory_free_amount = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available;
|
|
ux_test_connect_slave_and_host_wait_for_enum_completion();
|
|
|
|
/* With basic free memory amount, do basic memory test. */
|
|
ux_test_disconnect_slave_and_host_wait_for_enum_completion();
|
|
ux_test_connect_slave_and_host_wait_for_enum_completion();
|
|
|
|
/* (Let's be nice to the user.) Hello user! :) */
|
|
if (!connected_when_started)
|
|
{
|
|
ux_test_disconnect_slave_and_host_wait_for_enum_completion();
|
|
}
|
|
}
|
|
|
|
void ux_test_memory_test_check()
|
|
{
|
|
|
|
/* Has the memory check value not been initialized yet? */
|
|
if (ux_test_memory_test_no_device_memory_free_amount == 0)
|
|
return;
|
|
UX_TEST_ASSERT(_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available == ux_test_memory_test_no_device_memory_free_amount);
|
|
}
|
|
|
|
#if defined(UX_HOST_STANDALONE)
|
|
static UINT _host_enum_is_pending(void)
|
|
{
|
|
UX_DEVICE *enum_device = _ux_system_host -> ux_system_host_enum_device;
|
|
/* Case 1 : there is nothing in enum list, nothing pending. */
|
|
if (enum_device == UX_NULL)
|
|
return(UX_ERROR);
|
|
/* Case 2 : enum list is not NULL, check enum flags each device. */
|
|
while(enum_device)
|
|
{
|
|
if (enum_device -> ux_device_flags & UX_DEVICE_FLAG_ENUM)
|
|
return(UX_SUCCESS);
|
|
enum_device = enum_device -> ux_device_enum_next;
|
|
}
|
|
return(UX_ERROR);
|
|
}
|
|
static UINT _host_rh_removal_is_pending(void)
|
|
{
|
|
UX_HCD *hcd = &_ux_system_host -> ux_system_host_hcd_array[0];
|
|
/* If device connected, pending. */
|
|
if (hcd -> ux_hcd_rh_device_connection)
|
|
return(UX_SUCCESS);
|
|
return(UX_ERROR);
|
|
}
|
|
#endif
|
|
|
|
/* Wait for the enum thread to finish whatever it's currently doing. Note that
|
|
this implies it's actually _doing_ something when this is called.
|
|
|
|
Specifics: We do this by simply waiting for the the enum thread's semaphore's
|
|
suspended count to be non-zero. */
|
|
VOID ux_test_wait_for_enum_thread_completion()
|
|
{
|
|
#if !defined(UX_HOST_STANDALONE)
|
|
/* Is it actually running? */
|
|
if (_ux_system_host -> ux_system_host_enum_semaphore.tx_semaphore_suspended_count == 0)
|
|
{
|
|
|
|
/* Wait for enum thread to complete. */
|
|
UX_TEST_CHECK_SUCCESS(ux_test_wait_for_value_uint(&_ux_system_host -> ux_system_host_enum_semaphore.tx_semaphore_suspended_count, 1));
|
|
}
|
|
#else
|
|
{
|
|
UINT status;
|
|
if (ux_test_port_status & UX_PS_CCS)
|
|
{
|
|
/* Loop a while to confirm enumeration start. */
|
|
status = ux_test_sleep_break_on_success(10, _host_enum_is_pending);
|
|
if (status == UX_SUCCESS)
|
|
{
|
|
/* Loop a while to confirm enumeration end. */
|
|
status = ux_test_sleep_break_on_error(100, _host_enum_is_pending);
|
|
UX_ASSERT(status == UX_SUCCESS);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Loop a while to confirm device removal. */
|
|
status = ux_test_sleep_break_on_error(100, _host_rh_removal_is_pending);
|
|
UX_ASSERT(status == UX_SUCCESS);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
VOID ux_test_disconnect_host_no_wait()
|
|
{
|
|
|
|
ux_test_hcd_sim_host_disconnect_no_wait();
|
|
}
|
|
|
|
VOID ux_test_disconnect_host_wait_for_enum_completion()
|
|
{
|
|
|
|
/* No wait because ux_test_wait_for_enum_completion() expects the enum thread
|
|
to be running when it's called. */
|
|
ux_test_hcd_sim_host_disconnect_no_wait();
|
|
ux_test_wait_for_enum_thread_completion();
|
|
ux_test_memory_test_check();
|
|
}
|
|
|
|
/* This function should not be called from inside USBX because we wait for the
|
|
deactivation to finish. If we have a semaphore the deactivation routine requires,
|
|
then we have deadlock. */
|
|
void ux_test_disconnect_slave_and_host_wait_for_enum_completion()
|
|
{
|
|
|
|
UX_HCD *hcd = &_ux_system_host->ux_system_host_hcd_array[0];
|
|
|
|
ux_test_dcd_sim_slave_disconnect();
|
|
/* No wait because below. */
|
|
ux_test_disconnect_host_wait_for_enum_completion();
|
|
ux_test_memory_test_check();
|
|
}
|
|
|
|
VOID ux_test_disconnect_slave()
|
|
{
|
|
|
|
ux_test_dcd_sim_slave_disconnect();
|
|
}
|
|
|
|
VOID ux_test_connect_slave()
|
|
{
|
|
|
|
ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE);
|
|
}
|
|
|
|
VOID ux_test_connect_host_wait_for_enum_completion()
|
|
{
|
|
|
|
/* No wait because ux_test_wait_for_enum_completion() expects the enum thread
|
|
to be running when it's called. */
|
|
ux_test_hcd_sim_host_connect_no_wait(UX_FULL_SPEED_DEVICE);
|
|
ux_test_wait_for_enum_thread_completion();
|
|
}
|
|
|
|
VOID ux_test_connect_slave_and_host_wait_for_enum_completion()
|
|
{
|
|
|
|
ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE);
|
|
ux_test_connect_host_wait_for_enum_completion();
|
|
}
|
|
|
|
/* This is supposed to only change these parameters. In other words, the same
|
|
classes should still be registered after calling this. */
|
|
VOID ux_test_change_device_parameters(UCHAR * device_framework_high_speed, ULONG device_framework_length_high_speed,
|
|
UCHAR * device_framework_full_speed, ULONG device_framework_length_full_speed,
|
|
UCHAR * string_framework, ULONG string_framework_length,
|
|
UCHAR * language_id_framework, ULONG language_id_framework_length,
|
|
UINT(*ux_system_slave_change_function)(ULONG))
|
|
{
|
|
|
|
UX_SLAVE_CLASS *class;
|
|
UX_SLAVE_CLASS classes_copy[UX_MAX_SLAVE_CLASS_DRIVER];
|
|
ULONG class_index;
|
|
|
|
/* Disconnect device. */
|
|
ux_test_dcd_sim_slave_disconnect();
|
|
|
|
/* First, save the classes. */
|
|
memcpy(classes_copy, _ux_system_slave->ux_system_slave_class_array, sizeof(classes_copy));
|
|
|
|
/* Uninitialize classes. */
|
|
for (class_index = 0; class_index < UX_SYSTEM_DEVICE_MAX_CLASS_GET(); class_index++)
|
|
{
|
|
|
|
class = &_ux_system_slave->ux_system_slave_class_array[class_index];
|
|
if (class->ux_slave_class_status == UX_USED)
|
|
UX_TEST_CHECK_SUCCESS(ux_device_stack_class_unregister((UCHAR *)class->ux_slave_class_name, class->ux_slave_class_entry_function));
|
|
}
|
|
|
|
/* Uninitialize the stack. */
|
|
UX_TEST_CHECK_SUCCESS(ux_device_stack_uninitialize());
|
|
|
|
/* Now re-initialize stack with correct stuff. */
|
|
UX_TEST_CHECK_SUCCESS(ux_device_stack_initialize(device_framework_high_speed, device_framework_length_high_speed,
|
|
device_framework_full_speed, device_framework_length_full_speed,
|
|
string_framework, string_framework_length,
|
|
language_id_framework, language_id_framework_length,
|
|
ux_system_slave_change_function));
|
|
|
|
/* Now re-register the classes. */
|
|
for (class_index = 0; class_index < UX_SYSTEM_DEVICE_MAX_CLASS_GET(); class_index++)
|
|
{
|
|
|
|
class = &classes_copy[class_index];
|
|
if (class->ux_slave_class_status == UX_USED)
|
|
UX_TEST_CHECK_SUCCESS(ux_device_stack_class_register((UCHAR *)class->ux_slave_class_name,
|
|
class->ux_slave_class_entry_function,
|
|
class->ux_slave_class_configuration_number,
|
|
class->ux_slave_class_interface_number,
|
|
class->ux_slave_class_interface_parameter));
|
|
}
|
|
}
|
|
|
|
UINT ux_test_host_stack_class_instance_get(UX_HOST_CLASS *host_class, UINT class_index, VOID **class_instance)
|
|
{
|
|
|
|
UINT status;
|
|
UINT timeout_ms = UX_TEST_TIMEOUT_MS;
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ULONG t0, t, elapsed;
|
|
t0 = ux_utility_time_get();
|
|
#endif
|
|
|
|
do
|
|
{
|
|
|
|
status = ux_host_stack_class_instance_get(host_class, class_index, class_instance);
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ux_system_tasks_run();
|
|
tx_thread_relinquish();
|
|
t = ux_utility_time_get();
|
|
elapsed = ux_utility_time_elapsed(t0, t);
|
|
if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms))
|
|
return(UX_ERROR);
|
|
#else
|
|
tx_thread_sleep(MS_TO_TICK(10));
|
|
timeout_ms -= 10;
|
|
#endif
|
|
|
|
} while (status != UX_SUCCESS && timeout_ms);
|
|
|
|
if (timeout_ms == 0)
|
|
return UX_ERROR;
|
|
|
|
return UX_SUCCESS;
|
|
}
|
|
|
|
UINT ux_test_wait_for_value_uint(UINT *current_value_ptr, UINT desired_value)
|
|
{
|
|
|
|
UINT timeout_ms = UX_TEST_TIMEOUT_MS;
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ULONG t0, t, elapsed;
|
|
t0 = ux_utility_time_get();
|
|
#endif
|
|
|
|
while (*current_value_ptr != desired_value && timeout_ms)
|
|
{
|
|
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ux_system_tasks_run();
|
|
tx_thread_relinquish();
|
|
t = ux_utility_time_get();
|
|
elapsed = ux_utility_time_elapsed(t0, t);
|
|
if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms))
|
|
return(UX_ERROR);
|
|
#else
|
|
tx_thread_sleep(MS_TO_TICK(10));
|
|
timeout_ms -= 10;
|
|
#endif
|
|
}
|
|
|
|
if (timeout_ms == 0)
|
|
return UX_ERROR;
|
|
|
|
return UX_SUCCESS;
|
|
}
|
|
|
|
UINT ux_test_wait_for_value_ulong(ULONG *current_value_ptr, ULONG desired_value)
|
|
{
|
|
|
|
UINT timeout_ms = UX_TEST_TIMEOUT_MS;
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ULONG t0, t, elapsed;
|
|
t0 = ux_utility_time_get();
|
|
#endif
|
|
|
|
while (*current_value_ptr != desired_value && timeout_ms)
|
|
{
|
|
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ux_system_tasks_run();
|
|
tx_thread_relinquish();
|
|
t = ux_utility_time_get();
|
|
elapsed = ux_utility_time_elapsed(t0, t);
|
|
if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms))
|
|
return(UX_ERROR);
|
|
#else
|
|
tx_thread_sleep(MS_TO_TICK(10));
|
|
timeout_ms -= 10;
|
|
#endif
|
|
}
|
|
|
|
if (timeout_ms == 0)
|
|
return UX_ERROR;
|
|
|
|
return UX_SUCCESS;
|
|
}
|
|
|
|
UINT ux_test_wait_for_value_uchar(UCHAR *current_value_ptr, UCHAR desired_value)
|
|
{
|
|
|
|
UINT timeout_ms = UX_TEST_TIMEOUT_MS;
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ULONG t0, t, elapsed;
|
|
t0 = ux_utility_time_get();
|
|
#endif
|
|
|
|
while (*current_value_ptr != desired_value && timeout_ms)
|
|
{
|
|
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ux_system_tasks_run();
|
|
tx_thread_relinquish();
|
|
t = ux_utility_time_get();
|
|
elapsed = ux_utility_time_elapsed(t0, t);
|
|
if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms))
|
|
return(UX_ERROR);
|
|
#else
|
|
tx_thread_sleep(MS_TO_TICK(10));
|
|
timeout_ms -= 10;
|
|
#endif
|
|
}
|
|
|
|
if (timeout_ms == 0)
|
|
return UX_ERROR;
|
|
|
|
return UX_SUCCESS;
|
|
}
|
|
|
|
UINT ux_test_wait_for_non_null(VOID **current_value_ptr)
|
|
{
|
|
|
|
UINT timeout_ms = UX_TEST_TIMEOUT_MS;
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ULONG t0, t, elapsed;
|
|
t0 = ux_utility_time_get();
|
|
#endif
|
|
|
|
while (*current_value_ptr == UX_NULL && timeout_ms)
|
|
{
|
|
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ux_system_tasks_run();
|
|
tx_thread_relinquish();
|
|
t = ux_utility_time_get();
|
|
elapsed = ux_utility_time_elapsed(t0, t);
|
|
if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms))
|
|
return(UX_ERROR);
|
|
#else
|
|
tx_thread_sleep(MS_TO_TICK(10));
|
|
timeout_ms -= 10;
|
|
#endif
|
|
}
|
|
|
|
if (timeout_ms == 0)
|
|
return UX_ERROR;
|
|
|
|
return UX_SUCCESS;
|
|
}
|
|
|
|
UINT ux_test_wait_for_null_wait_time(VOID **current_value_ptr, UINT wait_time_ms)
|
|
{
|
|
|
|
UINT timeout_ms = wait_time_ms;
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ULONG t0, t, elapsed;
|
|
t0 = ux_utility_time_get();
|
|
#endif
|
|
|
|
while (*current_value_ptr != UX_NULL && timeout_ms)
|
|
{
|
|
|
|
#if defined(UX_HOST_STANDALONE)
|
|
ux_system_tasks_run();
|
|
tx_thread_relinquish();
|
|
t = ux_utility_time_get();
|
|
elapsed = ux_utility_time_elapsed(t0, t);
|
|
if (elapsed >= UX_MS_TO_TICK_NON_ZERO(timeout_ms))
|
|
return(UX_ERROR);
|
|
#else
|
|
tx_thread_sleep(MS_TO_TICK(10));
|
|
timeout_ms -= 10;
|
|
#endif
|
|
}
|
|
|
|
if (*current_value_ptr == UX_NULL)
|
|
return(UX_SUCCESS);
|
|
|
|
return UX_ERROR;
|
|
}
|
|
|
|
UINT ux_test_wait_for_null(VOID **current_value_ptr)
|
|
{
|
|
return ux_test_wait_for_null_wait_time(current_value_ptr, UX_TEST_TIMEOUT_MS);
|
|
}
|
|
|
|
char *ux_test_file_base_name(char *path, int n)
|
|
{
|
|
char *ptr = path, *slash = path;
|
|
int i;
|
|
for (i = 0; i < n; i ++)
|
|
{
|
|
if (*ptr == 0)
|
|
break;
|
|
if (*ptr == '\\' || *ptr == '/')
|
|
slash = ptr + 1;
|
|
ptr ++;
|
|
}
|
|
return(slash);
|
|
}
|
|
|
|
void ux_test_assert_hit_hint(UCHAR on_off)
|
|
{
|
|
ux_test_assert_hit_hint_off = !on_off;
|
|
}
|
|
void ux_test_assert_hit_exit(UCHAR on_off)
|
|
{
|
|
ux_test_assert_hit_exit_off = !on_off;
|
|
}
|
|
ULONG ux_test_assert_hit_count_get(void)
|
|
{
|
|
return ux_test_assert_hit_count;
|
|
}
|
|
void ux_test_assert_hit_count_reset(void)
|
|
{
|
|
ux_test_assert_hit_count = 0;
|
|
}
|
|
void ux_test_assert_hit(char* file, INT line)
|
|
{
|
|
ux_test_assert_hit_count ++;
|
|
if (!ux_test_assert_hit_hint_off)
|
|
printf("%s:%d Assert HIT!\n", file, line);
|
|
if (!ux_test_assert_hit_exit_off)
|
|
test_control_return(ux_test_assert_hit_exit_code);
|
|
}
|
|
|
|
UINT ux_test_host_endpoint_write(UX_ENDPOINT *endpoint, UCHAR *buffer, ULONG length, ULONG *actual_length)
|
|
{
|
|
UINT status;
|
|
UX_TRANSFER *transfer = &endpoint->ux_endpoint_transfer_request;
|
|
transfer->ux_transfer_request_data_pointer = buffer;
|
|
transfer->ux_transfer_request_requested_length = length;
|
|
status = ux_host_stack_transfer_request(transfer);
|
|
#if !defined(UX_HOST_STANDALONE)
|
|
if (status == UX_SUCCESS)
|
|
{
|
|
status = tx_semaphore_get(&transfer->ux_transfer_request_semaphore,
|
|
transfer->ux_transfer_request_timeout_value);
|
|
if (status != TX_SUCCESS)
|
|
{
|
|
ux_host_stack_transfer_request_abort(transfer);
|
|
status = UX_TRANSFER_TIMEOUT;
|
|
}
|
|
}
|
|
#endif
|
|
if (actual_length)
|
|
*actual_length = transfer->ux_transfer_request_actual_length;
|
|
return(status);
|
|
}
|