#include "sr_utest.h"
#include <string.h>
#include <stdlib.h>

#include "option_parse.h"

#include "cmsis_os2.h"
#include "sr_shell.h"


#define SR_USING_UTEST

       
#define SR_LOG_BUFF_SIZE           256
#define SR_UTEST_TASK_STACK_SIZE   2048 


#ifdef SR_USING_UTEST

#if SR_LOG_BUFF_SIZE < 256
#error "SR_LOG_BUFF_SIZE is less than 256!"
#endif

//#if (utest_TASK_PRIORITY > OS_TASK_PRIORITY_MAX - 1)
//#error "utest task priority is greater than or equal to OS_TASK_PRIORITY_MAX"
//#endif

#define SR_UTEST_ARGS_MAX_LEN       64
#define SR_UTEST_NAME_MAX_LEN       128
#define SR_UTEST_TAG                "UTEST"

struct utest_tc_table_info
{
    utest_tc_entry_t *tc_table;
    uint32_t          tc_num;
};
typedef struct utest_tc_table_info utest_tc_table_info_t;

struct utest_ctrl_info
{
    char                   tc_name[SR_UTEST_NAME_MAX_LEN];
	char                   args[SR_UTEST_ARGS_MAX_LEN];
    int32_t                loop_cnt;
    srBool_t               use_task;
    srBool_t               fail_stop;
    srBool_t               print_help;
    enum utest_tc_priority run_priority;
    utest_stats_t          test_stats;
    utest_tp_stats_t       tp_stats;
};
typedef struct utest_ctrl_info utest_ctrl_info_t;

static utest_tc_table_info_t gs_tc_table_info;
static utest_ctrl_info_t     gs_ctrl_info;

static srBool_t gs_is_busy = SR_FALSE;

#ifdef SR_UTEST_USING_DLOG
static uint16_t gs_old_log_level;
#endif




#if  defined(__GNUC__)

SR_USED  const utest_tc_entry_t __utest_tc_table_start SR_SECTION(".sunrise.testcase.0") = {"utest_start", 0, 0, 0, 0};
SR_USED  const utest_tc_entry_t __utest_tc_table_end SR_SECTION(".sunrise.testcase.1.end") = {"utest_end", 0, 0, 0, 0};
#endif



#if defined(__ICCARM__) || defined(__ICCRX__) /* For IAR compiler */
#pragma section = "utestTcTab"
#endif

static int utest_init(void)
{
    /* Initialize the utest commands table.*/
#if defined(__CC_ARM) || defined(__CLANG_ARM) /* ARM C Compiler */
    extern const int utestTcTab$$Base;
    extern const int utestTcTab$$Limit;

    gs_tc_table_info.tc_table = (utest_tc_entry_t *)&utestTcTab$$Base;
    gs_tc_table_info.tc_num   = (utest_tc_entry_t *)&utestTcTab$$Limit - gs_tc_table_info.tc_table;

#elif defined(__ICCARM__) || defined(__ICCRX__) /* For IAR Compiler */
    gs_tc_table_info.tc_table = (utest_tc_entry_t *)__section_begin("utestTcTab");
    gs_tc_table_info.tc_num   = (utest_tc_entry_t *)__section_end("utestTcTab") - gs_tc_table_info.tc_table;

#elif defined(__GNUC__) /* For GCC Compiler */
    //extern const int __utest_tc_table_start;
    //extern const int __utest_tc_table_end;

    gs_tc_table_info.tc_table = (utest_tc_entry_t *)&__utest_tc_table_start + 1;
    gs_tc_table_info.tc_num   = (utest_tc_entry_t *)&__utest_tc_table_end - gs_tc_table_info.tc_table;
    
#else
#error "Use the compilier that is not supported!!!"
#endif

    UTEST_LOG_I(SR_UTEST_TAG, "utest is initialized success!");

    return SR_OK;
}
//OS_INIT_CALL(utest_init, OS_INIT_LEVEL_COMPONENT, OS_INIT_SUBLEVEL_LOW);
SR_INIT_COMPONENT_EXPORT(utest_init,SR_PRIORITY_1);  //LW_ERR


/**
 ***********************************************************************************************************************
 * @brief           Execute test unit function.
 *
 * @param[in]       func            Test unit function.
 * @param[in]       unit_func_name  Test unit name.
 *
 * @return          None.
 ***********************************************************************************************************************
 */
void utest_unit_run(utest_unit_func_t func, const char *unit_func_name)
{
    uint16_t old_tp_passed_num;
    uint16_t old_tp_failed_num;

    old_tp_passed_num = gs_ctrl_info.tp_stats.tp_passed_num;
    old_tp_failed_num = gs_ctrl_info.tp_stats.tp_failed_num;

    UTEST_LOG_I(SR_UTEST_TAG, "[   TU   ] [ ====== ] Unit name (%s).", unit_func_name);

    if (SR_NULL != func)
    {
        func();
    }

    if (gs_ctrl_info.tp_stats.tp_failed_num == old_tp_failed_num)
    {
        gs_ctrl_info.test_stats.tu_passed_num++;

        UTEST_LOG_I(SR_UTEST_TAG,
                    "[   TU   ] [ PASSED ] Unit name (%s), tp passed (%u), tp failed (%u).",
                    unit_func_name,
                    gs_ctrl_info.tp_stats.tp_passed_num - old_tp_passed_num,
                    gs_ctrl_info.tp_stats.tp_failed_num - old_tp_failed_num);
    }
    else
    {
        gs_ctrl_info.test_stats.tu_failed_num++;

        UTEST_LOG_E(SR_UTEST_TAG,
                    "[   TU   ] [ FAILED ] Unit name (%s), tp passed (%u), tp failed (%u).",
                    unit_func_name,
                    gs_ctrl_info.tp_stats.tp_passed_num - old_tp_passed_num,
                    gs_ctrl_info.tp_stats.tp_failed_num - old_tp_failed_num);
    }

    SR_PRINTF("\r\n");

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Get Statistical results of test points in a testcase.
 *
 * @param           None.
 *
 * @return          Statistical results of test points.
 ***********************************************************************************************************************
 */
utest_tp_stats_t *utest_tp_stats_get(void)
{
    return &gs_ctrl_info.tp_stats;
}

static const char *utest_file_basename(const char *file)
{
    char *slash_pos;
    char *rst;

    /* Find the last slash position */
    slash_pos = strrchr(file, '\\');
    if (!slash_pos)
    {
        slash_pos = strrchr(file, '/');
    }

    /* Not found slash in filename or filename length is less than 2 */
    if ((SR_NULL == slash_pos) || (strlen(file) < 2))
    {
        rst = (char *)file;
    }
    /* Found slash in filename, and filename length is more than or equal 2 */
    else
    {
        rst = (char *)(slash_pos + 1);
    }

    return (const char *)rst;
}

/**
 ***********************************************************************************************************************
 * @brief           utest assert function.
 *
 * @param[in]       condition       Assert condition.
 *                                      - 0:    Assert.
 *                                      - else: Not assert.
 * @param[in]       file            File name.
 * @param[in]       line            Flie line number.
 * @param[in]       func            Function nmae.
 * @param[in]       msg             Assert message.
 *
 * @return          None.
 ***********************************************************************************************************************
 */
void utest_assert(srBool_t condition, const char *file, int32_t line, const char *func, const char *msg)
{
    if (!condition)
    {
        gs_ctrl_info.tp_stats.tp_failed_num++;
        gs_ctrl_info.test_stats.tp_failed_num++;

        UTEST_LOG_E(SR_UTEST_TAG,
                    "[   TP   ] [ ASSERT ] File: (%s); func: (%s:%d); msg: (%s)",
                    utest_file_basename(file),
                    func,
                    line,
                    msg);
    }
    else
    {
        gs_ctrl_info.tp_stats.tp_passed_num++;
        gs_ctrl_info.test_stats.tp_passed_num++;

        UTEST_LOG_I(SR_UTEST_TAG,
                    "[   TP   ] [ PASSED ] File: (%s); func: (%s:%d).",
                    utest_file_basename(file),
                    func,
                    line);
    }

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Judge whether to assert according to the string comparison result and the desired comparison
 *                  condition.
 *
 * @param[in]       str_a           String a.
 * @param[in]       str_b           String b.
 * @param[in]       equal           The desired comparison condition.
 *                                      - SR_TRUE:  Want to be equal.
 *                                      - SR_FALSE: Want to not be equal.
 * @param[in]       file            File name.
 * @param[in]       line            File line number.
 * @param[in]       func            Function name.
 * @param[in]       msg             Assert message.
 *
 * @return          None.
 ***********************************************************************************************************************
 */
void utest_assert_string(const char *str_a,
                         const char *str_b,
                         srBool_t   equal,
                         const char *file,
                         int32_t     line,
                         const char *func,
                         const char *msg)
{
    if ((SR_NULL == str_a) || (SR_NULL == str_b))
    {
        utest_assert(SR_FALSE, file, line, func, msg);
        return;
    }

    if (equal)
    {
        if (!strcmp(str_a, str_b))
        {
            utest_assert(SR_TRUE, file, line, func, msg);
        }
        else
        {
            utest_assert(SR_FALSE, file, line, func, msg);
        }
    }
    else
    {
        if (!strcmp(str_a, str_b))
        {
            utest_assert(SR_FALSE, file, line, func, msg);
        }
        else
        {
            utest_assert(SR_TRUE, file, line, func, msg);
        }
    }

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Judge whether to assert according to the buffer comparison result and the desired comparison
 *                  condition.
 *
 * @param[in]       buff_a          Buffer a.
 * @param[in]       buff_b          Buffer b.
 * @param[in]       size            The size you want to compare.
 * @param[in]       equal           The desired comparison condition.
 *                                      - SR_TRUE:  Want to be equal.
 *                                      - SR_FALSE: Want to not be equal.
 * @param[in]       file            File name.
 * @param[in]       line            File line number.
 * @param[in]       func            Function name.
 * @param[in]       msg             Assert message.
 *
 * @return          None.
 ***********************************************************************************************************************
 */
void utest_assert_buf(const uint8_t *buff_a,
                      const uint8_t *buff_b,
                      srSize_t      size,
                      srBool_t      equal,
                      const char    *file,
                      int32_t        line,
                      const char    *func,
                      const char    *msg)
{
    if ((SR_NULL == buff_a) || (SR_NULL == buff_b))
    {
        utest_assert(SR_FALSE, file, line, func, msg);
        return;
    }

    if (equal)
    {
        if (!memcmp(buff_a, buff_b, size))
        {
            utest_assert(SR_TRUE, file, line, func, msg);
        }
        else
        {
            utest_assert(SR_FALSE, file, line, func, msg);
        }
    }
    else
    {
        if (!memcmp(buff_a, buff_b, size))
        {
            utest_assert(SR_FALSE, file, line, func, msg);
        }
        else
        {
            utest_assert(SR_TRUE, file, line, func, msg);
        }
    }

    return;
}

static void utest_help(void)
{
    SR_PRINTF("\r\n");

    SR_PRINTF("Command: utest_run\r\n");
    SR_PRINTF("   Info: Execute testcases.\r\n");
    SR_PRINTF(" Format: utest_run [-n testacse name] [-l loop count] [-p priority level] [-t] [-s] [-h]\r\n");
    SR_PRINTF("\r\n");

    SR_PRINTF("  Usage:\r\n");

    SR_PRINTF("         -n     Specify a testcase name.\r\n");
    SR_PRINTF("                If don't specify this option, run all testcases.\r\n");
    SR_PRINTF("\r\n");

    SR_PRINTF("         -l     Specify a loop count that the testcase runs.\r\n");
    SR_PRINTF("                If don't specify this option, the testcase only run one times.\r\n");
    SR_PRINTF("\r\n");

    SR_PRINTF("         -p     Specify a priority level. Only testcases greater or equal than this level can be run.\r\n");
    SR_PRINTF("                H  -- High priority level.\r\n");
    SR_PRINTF("                M  -- Middle priority level.\r\n");
    SR_PRINTF("                L  -- Low priority level.\r\n");
    SR_PRINTF("                If don't specify this option, low priority level is be used by default.\r\n");
    SR_PRINTF("\r\n");

    SR_PRINTF("         -t     Create a new task to execute the testcase(s).\r\n");
    SR_PRINTF("                If don't specify this option, execute the testcase(s) in shell task.\r\n");
    SR_PRINTF("\r\n");

    SR_PRINTF("         -s     If specify this option, as long as a testcase fails, the subsequent testcases are no\r\n"
               "                longer running.\r\n");
    SR_PRINTF(
        "                If don't specify this option, when a testcase fails, the subsequent testcases still run.\r\n");
    SR_PRINTF("\r\n");

    SR_PRINTF("         -h     Print help information of utest_run command.\r\n");
    SR_PRINTF("                If specify this option, other options are ignored.\r\n");
    SR_PRINTF("\r\n");

	SR_PRINTF("         -a     Pass test parameters separated by commas. e.g  123,iqa,1wi4 \r\n");
    SR_PRINTF("\r\n");

    return;
}

static int utest_ctrl_info_get(int32_t argc, char *const *argv, utest_ctrl_info_t *ctrl_info)
{
    opt_state_t state;
    int32_t     opt_ret;
    int32_t     ret;

    memset(ctrl_info, 0, sizeof(utest_ctrl_info_t));
    ctrl_info->loop_cnt     = 1;
    ctrl_info->use_task     = SR_FALSE;
    ctrl_info->fail_stop    = SR_FALSE;
    ctrl_info->print_help   = SR_FALSE;
    ctrl_info->run_priority = TC_PRIORITY_LOW;

    memset(&state, 0, sizeof(state));
    opt_init(&state, 1);

    ret = SR_OK;
    while (1)
    {
        opt_ret = opt_get(argc, argv, "n:a:l:p:tsh", &state);
        if (opt_ret == OPT_EOF)
        {
            break;
        }

        if ((opt_ret == OPT_BADOPT) || (opt_ret == OPT_BADARG))
        {
            ret = SR_FAIL;
            break;
        }

        switch (opt_ret)
        {
        case 'n':
            memset(ctrl_info->tc_name, 0, SR_UTEST_NAME_MAX_LEN);
            strncpy(ctrl_info->tc_name, state.opt_arg, SR_UTEST_NAME_MAX_LEN);
            break;

        case 'l':
            ctrl_info->loop_cnt = atoi(state.opt_arg);
            if (ctrl_info->loop_cnt <= 0)
            {
                SR_PRINTF("Invalid loop count(%s)\r\n", state.opt_arg);

                ret = SR_INVALID;
                break;
            }

            break;

        case 'p':
            if (!strcmp(state.opt_arg, "H"))
            {
                ctrl_info->run_priority = TC_PRIORITY_HIGH;
            }
            else if (!strcmp(state.opt_arg, "M"))
            {
                ctrl_info->run_priority = TC_PRIORITY_MIDDLE;
            }
            else if (!strcmp(state.opt_arg, "L"))
            {
                ctrl_info->run_priority = TC_PRIORITY_LOW;
            }
            else
            {
                SR_PRINTF("Invalid priority(%s)\r\n", state.opt_arg);

                ret = SR_INVALID;
                break;
            }

            break;

        case 't':
            ctrl_info->use_task = SR_TRUE;
            break;

        case 's':
            ctrl_info->fail_stop = SR_TRUE;
            break;
        case 'h':
            ctrl_info->print_help = SR_TRUE;
            break;

        case 'a':
            //命令行传来的形参
            //SR_PRINTF("args: %s\r\n", state.opt_arg);
            memset(ctrl_info->args, 0, SR_UTEST_ARGS_MAX_LEN);
            strncpy(ctrl_info->args, state.opt_arg, SR_UTEST_ARGS_MAX_LEN);
            break;

        default:
            SR_PRINTF("Invalid option: %c\r\n", (char)opt_ret);

            ret = SR_INVALID;
            break;
        }

        if (ret != SR_OK)
        {
            break;
        }
    }

    return ret;
}

static int utest_run_a_testcase(utest_tc_entry_t *tc_entry, utest_ctrl_info_t *ctrl_info)
{
    int init_ret;
    int cleanup_ret;
    int ret;

    ret                               = SR_OK;
    ctrl_info->tp_stats.tp_passed_num = 0;
    ctrl_info->tp_stats.tp_failed_num = 0;

    do
    {
        UTEST_LOG_I(SR_UTEST_TAG, "[   TC   ] [ ====== ] Testcase (%s) begin to run.", tc_entry->name);
        SR_PRINTF("\r\n");

        if (SR_NULL != tc_entry->init)
        {
            init_ret = tc_entry->init();
            if (SR_OK != init_ret)
            {
                UTEST_LOG_E(SR_UTEST_TAG, "[   TC   ] [ FAILED ] Testcase (%s) init failed", tc_entry->name);

                ret = SR_FAIL;
                break;
            }
        }

        if (SR_NULL != tc_entry->tc)
        {
            tc_entry->tc();

            if (0 == ctrl_info->tp_stats.tp_failed_num)
            {
                UTEST_LOG_I(SR_UTEST_TAG,
                            "[   TC   ] [ PASSED ] Testcase (%s), tp passed (%u), tp failed (%u)",
                            tc_entry->name,
                            ctrl_info->tp_stats.tp_passed_num,
                            ctrl_info->tp_stats.tp_failed_num);
            }
            else
            {
                UTEST_LOG_E(SR_UTEST_TAG,
                            "[   TC   ] [ FAILED ] Testcase (%s), tp passed (%u), tp failed (%u)",
                            tc_entry->name,
                            ctrl_info->tp_stats.tp_passed_num,
                            ctrl_info->tp_stats.tp_failed_num);
                ret = SR_FAIL;
            }
        }
        else
        {
            UTEST_LOG_E(SR_UTEST_TAG, "[   TC   ] [ FAILED ] Testcase (%s) has no execute function.", tc_entry->name);
            ret = SR_FAIL;
        }

        if (SR_NULL != tc_entry->cleanup)
        {
            cleanup_ret = tc_entry->cleanup();
            if (SR_OK != cleanup_ret)
            {
                UTEST_LOG_E(SR_UTEST_TAG, "[   TC   ] [ FAILED ] Testcase (%s) cleanup failed.", tc_entry->name);

                ret = SR_FAIL;
                break;
            }
        }
    } while (0);

    return ret;
}

static utest_tc_entry_t *utest_get_next_tc_entry(const utest_ctrl_info_t     *ctrl_info,
                                                 const utest_tc_table_info_t *tc_table_info,
                                                 uint16_t                    *next_query_index)
{
    utest_tc_entry_t *tc_entry;
    srSize_t         cmp_len;
    uint16_t          index;

    if (*next_query_index >= tc_table_info->tc_num)
    {
        return SR_NULL;
    }

    cmp_len = 0;
    if (*ctrl_info->tc_name)
    {
        cmp_len = strlen(ctrl_info->tc_name);
        if (ctrl_info->tc_name[cmp_len - 1] == '*')
        {
            cmp_len -= 1;
        }
    }

    tc_entry = SR_NULL;
    for (index = *next_query_index; index < tc_table_info->tc_num; index++)
    {
        if (cmp_len > 0)
        {
            if (memcmp(tc_table_info->tc_table[index].name, ctrl_info->tc_name, cmp_len))
            {
                continue;
            }
        }

        if (tc_table_info->tc_table[index].priority > ctrl_info->run_priority)
        {
            continue;
        }

        tc_entry          = &tc_table_info->tc_table[index];
        *next_query_index = index + 1;

        break;
    }

    return tc_entry;
}

static void utest_tc_do_run(void *arg)
{
    utest_ctrl_info_t *ctrl_info;
    utest_tc_entry_t  *tc_entry;
    srBool_t          found_entry;
    srBool_t          abort;
    uint16_t           loop_index;
    uint16_t           next_query_index;
    uint16_t           total;
    int           ret;

    ctrl_info                           = (utest_ctrl_info_t *)arg;
    ctrl_info->test_stats.tc_passed_num = 0;
    ctrl_info->test_stats.tc_failed_num = 0;
    ctrl_info->test_stats.tu_passed_num = 0;
    ctrl_info->test_stats.tu_failed_num = 0;
    ctrl_info->test_stats.tp_passed_num = 0;
    ctrl_info->test_stats.tp_failed_num = 0;

    SR_PRINTF("\r\n");

    abort = SR_FALSE;

    for (loop_index = 0; loop_index < ctrl_info->loop_cnt; loop_index++)
    {
        SR_PRINTF("-----------------------------------Loop: %u-------------------------------------\r\n",
                   loop_index + 1);
        SR_PRINTF("\r\n");

        found_entry      = SR_FALSE;
        next_query_index = 0;

        while (1)
        {
            tc_entry = utest_get_next_tc_entry(ctrl_info, &gs_tc_table_info, &next_query_index);
            if (!tc_entry)
            {
                break;
            }

            if (!found_entry)
            {
                found_entry = SR_TRUE;
            }

            ret = utest_run_a_testcase(tc_entry, ctrl_info);
            if (SR_OK == ret)
            {
                ctrl_info->test_stats.tc_passed_num++;
            }
            else
            {
                ctrl_info->test_stats.tc_failed_num++;

                if (ctrl_info->fail_stop)
                {
                    abort = SR_TRUE;
                    break;
                }
            }

            SR_PRINTF("\r\n");
            SR_PRINTF("-----------------------------------Loop: %u-------------------------------------\r\n",
                       loop_index + 1);
            SR_PRINTF("\r\n");
        }

        if (!found_entry)
        {
            UTEST_LOG_W(SR_UTEST_TAG, "[ utest  ] [ ====== ] Not find testcase(%s).", ctrl_info->tc_name);
            break;
        }

        if (abort)
        {
            break;
        }
    }

    SR_PRINTF("\r\n");
    UTEST_LOG_I(SR_UTEST_TAG, "[ utest  ] [ ====== ] Finished.");
    SR_PRINTF("\r\n");

    SR_PRINTF("  type        total      passed      failed      pass rate \r\n");
    SR_PRINTF("----------    -----      ------      ------      ---------\r\n");

    total = ctrl_info->test_stats.tc_passed_num + ctrl_info->test_stats.tc_failed_num;
    SR_PRINTF("test case      %3u         %3u         %3u          %2u%% \r\n",
               total,
               ctrl_info->test_stats.tc_passed_num,
               ctrl_info->test_stats.tc_failed_num,
               total > 0 ? ctrl_info->test_stats.tc_passed_num * 100 / total : 0);

    total = ctrl_info->test_stats.tu_passed_num + ctrl_info->test_stats.tu_failed_num;
    SR_PRINTF("test unit      %3u         %3u         %3u          %2u%% \r\n",
               total,
               ctrl_info->test_stats.tu_passed_num,
               ctrl_info->test_stats.tu_failed_num,
               total > 0 ? ctrl_info->test_stats.tu_passed_num * 100 / total : 0);

    total = ctrl_info->test_stats.tp_passed_num + ctrl_info->test_stats.tp_failed_num;
    SR_PRINTF("test point     %3u         %3u         %3u          %2u%% \r\n",
               total,
               ctrl_info->test_stats.tp_passed_num,
               ctrl_info->test_stats.tp_failed_num,
               total > 0 ? ctrl_info->test_stats.tp_passed_num * 100 / total : 0);

    SR_PRINTF("\r\n");   

    gs_is_busy = SR_FALSE;

#ifdef SR_UTEST_USING_DLOG
    dlog_global_lvl_set(gs_old_log_level);
#endif


    if(gs_ctrl_info.use_task) osThreadExit(); //退出线程    LW_ERR一定要加

    return;
}

/**
 ***********************************************************************************************************************
 * @brief           Run testcase(s).
 *
 * @param[in]       argc            Argument count.
 * @param[in]       argv            Argument value.
 *
 * @return          The result of executing command.
 * @retval          SR_OK          Success.
 * @retval          else            Failed.
 ***********************************************************************************************************************
 */
static int utest_tc_run(int argc, char **argv)
{
    //os_task_id task;
    osThreadId_t task;
	
    int   ret;

    ret = SR_OK;

    do
    {
        if (SR_TRUE == gs_is_busy)
        {
            SR_PRINTF("Testcases are running, please try again later.\r\n");

            ret = SR_BUSY;
            break;
        }

        gs_is_busy = SR_TRUE;

        ret = utest_ctrl_info_get(argc, argv, &gs_ctrl_info);
        if (ret != SR_OK)
        {
            utest_help();
            gs_is_busy = SR_FALSE;

            break;
        }

        if (SR_TRUE == gs_ctrl_info.print_help)
        {
            utest_help();

            gs_is_busy = SR_FALSE;
            break;
        }

#ifdef SR_UTEST_USING_DLOG
        gs_old_log_level = dlog_global_lvl_get();
        dlog_global_lvl_set(DLOG_INFO);
#endif

        if (!gs_ctrl_info.use_task)
        {
            utest_tc_do_run((void *)&gs_ctrl_info);
        }
        else
        {

		   #if  0
            task = os_task_create(NULL,
                                  NULL,
                                  SR_UTEST_TASK_STACK_SIZE,
                                  "utest",
                                  utest_tc_do_run,
                                  (void *)&gs_ctrl_info,
                                  utest_TASK_PRIORITY);
           #endif

		   
        #if   1

		  //设置参数
		  const osThreadAttr_t threadAttr = 
		  { 
		    .name = "utest",
		    .stack_size = SR_UTEST_TASK_STACK_SIZE, 
		    .priority = osPriorityNormal,
		  };
		 
		  task = osThreadNew(utest_tc_do_run, (void *)&gs_ctrl_info, &threadAttr);
      #endif

								  
            if (task)
            {
                //ret = os_task_startup(task);
                //if (SR_OK != ret)
                //{
                   // SR_ASSERT_EX(0, "utest start task to execute testcase failed");
                //}
            }
            else
            {
                SR_PRINTF("Create utest task failed, execute testcase(s) failed.\r\n");

                gs_is_busy = SR_FALSE;

#ifdef SR_UTEST_USING_DLOG
                dlog_global_lvl_set(gs_old_log_level);
#endif

                ret = SR_FAIL;
            }
        }
    } while (0);

    return ret;
}
//SH_CMD_EXPORT(utest_run,utest_tc_run,"utest_run [-n testacse name] [-l loop count] [-p priority level] [-t] [-s] [-h]");
SR_SHELL_CMD_EXPORT(utest_run,utest_tc_run);     //LW_ERR




/**
 ***********************************************************************************************************************
 * @brief           Display all utest testcases.
 *
 * @param[in]       argc            Argument count.
 * @param[in]       argv            Argument value.
 *
 * @return          The result of executing command.
 * @retval          SR_OK          Success.
 * @retval          else            Failed.
 ***********************************************************************************************************************
 */
SR_UNUSED static int utest_tc_list(int argc, char **argv)
{
    srSize_t index;
    int32_t   priority;
    char     *prior_str[TC_PRIORITY_CNT_MAX];

    prior_str[TC_PRIORITY_HIGH]   = "High";
    prior_str[TC_PRIORITY_MIDDLE] = "Middle";
    prior_str[TC_PRIORITY_LOW]    = "Low";

	
	SR_PRINTF("[UTEST] tc_table addr: 0x%x  tc_num:%d", gs_tc_table_info.tc_table,gs_tc_table_info.tc_num);

    SR_PRINTF("\r\n");
    SR_PRINTF("%-61s %-10s\r\n", "Testcase name", "Priority");
    SR_PRINTF("---------------------------------                             --------\r\n");
	

    for (index = 0; index < gs_tc_table_info.tc_num; index++)
    {

	#if  0
        if (!memcmp(gs_tc_table_info.tc_table[index].name, "utest_occupancy", strlen("utest_occupancy")))
        {
            continue;
        }

	#endif

        priority = (int32_t)gs_tc_table_info.tc_table[index].priority;

        if ((priority < TC_PRIORITY_HIGH) || (priority > TC_PRIORITY_LOW))
        {
            priority = TC_PRIORITY_CNT_MAX;
        }

        SR_PRINTF("%-62s %s\r\n",
                   gs_tc_table_info.tc_table[index].name,
                   priority != TC_PRIORITY_CNT_MAX ? prior_str[priority] : "Invalid");
    }

    SR_PRINTF("\r\n");

    return SR_OK;
}
//SH_CMD_EXPORT(utest_list, utest_tc_list, "Display all utest testcases");
SR_SHELL_CMD_EXPORT(utest_list,utest_tc_list);//  LW_ERR



#if   0

/**
 ***********************************************************************************************************************
 * @brief           This is a occupancy testcase.
 *
 * @attention       If there are no testcases, a warning will appear during compilation. This occupancy testcase will
 *                  resolve it.
 *
 * @param           None.
 *
 * @return          None.
 ***********************************************************************************************************************
 */
static void occupancy_testcase(void)
{
    /* Do nothing */

    return;
}
UTEST_TC_EXPORT(utest_occupancy, occupancy_testcase, SR_NULL, SR_NULL, TC_PRIORITY_CNT_MAX);



static void occupancy2_testcase(void)
{
    /* Do nothing */

    return;
}
UTEST_TC_EXPORT(utest_occupancy2, occupancy2_testcase, SR_NULL, SR_NULL, TC_PRIORITY_CNT_MAX);

#endif


uint32_t os_tick_get_value(void)
{
    return 0;
}



static char *utest_strtok(char *string_org, const char *demial)
{
	static unsigned char *last;
	unsigned char *str;
	const unsigned char *ctrl = (const unsigned char *)demial;
	unsigned char map[32];
	int count;

	for (count = 0; count < 32; count++)
	{
		map[count] = 0;
	}
	do
	{
		map[*ctrl >> 3] |= (1 << (*ctrl & 7));
	} while (*ctrl++);
	if (string_org)
	{
		str = (unsigned char *)string_org;
	}
	else
	{
		str = last;
	}
	while ((map[*str >> 3] & (1 << (*str & 7))) && *str)
	{
		str++;
	}
	string_org = (char *)str;
	for (; *str; str++)
	{
		if (map[*str >> 3] & (1 << (*str & 7)))
		{
			*str++ = '\0';
			break;
		}
	}
	last = str;
	if (string_org == (char *)str)
	{
		return NULL;
	}
	else
	{
		return string_org;
	}
}

void UtestGetArgs(int *argc,char **argv)
{
	uint8_t i,len,tmpArgc=0;
	if(gs_ctrl_info.args[0]==0)  //没有参数
	{
		*argc=0;
		return;
	}


	//将参数中的 逗号改成空格
	len = strlen(gs_ctrl_info.args);
	for(i=0;i<len;i++) if(gs_ctrl_info.args[i]==',') gs_ctrl_info.args[i]=' ';

	//SR_PRINTF("args: %s\r\n", gs_ctrl_info.args);

	char *token = gs_ctrl_info.args;

	//以空格为分隔符，获取第一个分解字符串
	token = utest_strtok(token, " ");
	argv[tmpArgc++] = token;	

	
    //获取剩余分解字符串,总共最多获取10个以空格间隔的参数
	token = utest_strtok(SR_NULL, " ");
	while (token != SR_NULL && *argc<10)
	{
		argv[tmpArgc++] = token;

		token = utest_strtok(SR_NULL, " ");
	}

	//(*argv)[*argc] = SR_NULL;

	*argc = tmpArgc;

	//SR_LOG(WARN,"\r\nPrint args:");
    //for(i=0;i<tmpArgc;i++) SR_PRINTF("argv[%d]: %s\r\n", i,argv[i]);
  
}


#endif /* SR_USING_UTEST */
