#include "sr_gpio.h"
#include "sr_led.h"

#include "sr_stddef.h"
#include "sr_config.h"
#include "sr_osal.h"
#include "sr_shell.h"

#include "sr_utest.h"

extern char *getErrorString(int errorCode);

static int LedInit(void)
{
    return 0;
}

static int LedCleanup(void)
{
    return 0;
}

static void LedOnOff_Testcase(void)
{
    SR_LedSwitch(LED0, SR_LED_ON);
    SR_LOG(INFO, "[ledOnOff]: LED ON.\r\n");
    osDelay(1000);

    SR_LedSwitch(LED0, SR_LED_OFF);
    SR_LOG(INFO, "[ledOnOff]: LED OFF.\r\n");
    osDelay(1000);

    SR_LedSwitch(LED0, SR_LED_TOGGLE);
    SR_LOG(INFO, "[ledOnOff]: LED TOGGLE.\r\n");
    osDelay(1000);

    SR_LedSwitch(LED0, SR_LED_TOGGLE);
    SR_LOG(INFO, "[ledOnOff]: LED TOGGLE.\r\n");
    osDelay(1000);
}
UTEST_TC_EXPORT(led_onoff,
                LedOnOff_Testcase,
                LedInit,
                LedCleanup,
                TC_PRIORITY_HIGH);

static void ledBlink_Testcase(void)
{
    SR_LedBlink(LED0, 5, 300, 300, 0);
    SR_LOG(INFO, "[ledBlink]: LED fast blink, blink time = 3s.\r\n");
    osDelay(4000);

    SR_LedBlink(LED0, 3, 500, 500, 0);
    SR_LOG(INFO, "[ledBlink]: LED slow blink, blink time = 3s.\r\n");
    osDelay(4000);
}
UTEST_TC_EXPORT(led_blink,
                ledBlink_Testcase,
                LedInit,
                LedCleanup,
                TC_PRIORITY_HIGH);

static void ledBlinkInvalid_Testcase(void)
{
    int ret = -1;

    ret = SR_LedSwitch(-1, SR_LED_TOGGLE);
    SR_LOG(INFO, "[ledInvalid]: out-range id: -1, return = %s", getErrorString(ret));

    ret = SR_LedSwitch(100, SR_LED_TOGGLE);
    SR_LOG(INFO, "[ledInvalid]: out-range id: 100, return = %s", getErrorString(ret));

    ret = SR_LedSwitch(LED0, -1);
    SR_LOG(INFO, "[ledInvalid]: out-range level: -1, return = %s", getErrorString(ret));

    ret = SR_LedSwitch(LED0, 100);
    SR_LOG(INFO, "[ledInvalid]: out-range level: 100, return = %s", getErrorString(ret));

    ret = SR_LedBlink(-1, 3, 500, 500, 0);
    SR_LOG(INFO, "[ledInvalid]: out-range id: -1, return = %s", getErrorString(ret));

    ret = SR_LedBlink(100, 3, 500, 500, 0);
    SR_LOG(INFO, "[ledInvalid]: out-range id: 100, return = %s", getErrorString(ret));
}
UTEST_TC_EXPORT(led_invalid,
                ledBlinkInvalid_Testcase,
                LedInit,
                LedCleanup,
                TC_PRIORITY_HIGH);

static void ledTime_Testcase(void)
{
    // 耗时测试
    uint32_t startTick, endTick, i;
    float onTotalTime, offTotalTime, toggleTotalTime,
        onAverageTime = 0, offAverageTime = 0, toggleAverageTime = 0;

    for (i = 0; i < 10; i++)
    {
        SR_GET_EXCT_TIME(SR_LedSwitch(LED0, SR_LED_TOGGLE), startTick, endTick, toggleTotalTime);
        SR_LOG(INFO, "[ledTime]: led toggle, startTick: %u, endTick: %u, totalTime: %f us", startTick, endTick, toggleTotalTime);
        toggleAverageTime += toggleTotalTime;

        /* LED off average time test */
        SR_GET_EXCT_TIME(SR_LedSwitch(LED0, SR_LED_OFF), startTick, endTick, offTotalTime);
        SR_LOG(INFO, "[ledTime]: led off, startTick: %u, endTick: %u, totalTime: %f us", startTick, endTick, offTotalTime);
        offAverageTime += offTotalTime;

        /* LED on average time test */
        SR_GET_EXCT_TIME(SR_LedSwitch(LED0, SR_LED_ON), startTick, endTick, onTotalTime);
        SR_LOG(INFO, "[ledTime]: led on, startTick: %u, endTick: %u, totalTime: %f us", startTick, endTick, onTotalTime);
        onAverageTime += onTotalTime;

        /* LED toggle average time test */
        SR_GET_EXCT_TIME(SR_LedSwitch(LED0, SR_LED_TOGGLE), startTick, endTick, toggleTotalTime);
        SR_LOG(INFO, "[ledTime]: led toggle, startTick: %u, endTick: %u, totalTime: %f us", startTick, endTick, toggleTotalTime);
        toggleAverageTime += toggleTotalTime;
    }
    SR_LOG(INFO, "[ledTime]: led on, averageTime: %f us", onAverageTime / 10.0);
    SR_LOG(INFO, "[ledTime]: led off, averageTime: %f us", offAverageTime / 10.0);
    SR_LOG(INFO, "[ledTime]: led toggle, averageTime: %f us", toggleAverageTime / 20.0);
}
UTEST_TC_EXPORT(led_time,
                ledTime_Testcase,
                LedInit,
                LedCleanup,
                TC_PRIORITY_HIGH);

static void ledStress_Testcase(void)
{
    SR_LOG(INFO, "[ledStress]: LED stress test\r\n");

    gShellThreadRun = 1; // CTRL+C会将这个变量置0

    while (gShellThreadRun)
    {
        SR_LedSwitch(LED0, SR_LED_ON);
        SR_LOG(INFO, "[ledStress]: LED ON.\r\n");
        osDelay(1000);

        SR_LedSwitch(LED0, SR_LED_OFF);
        SR_LOG(INFO, "[ledStress]: LED OFF.\r\n");
        osDelay(1000);

        SR_LedSwitch(LED0, SR_LED_TOGGLE);
        SR_LOG(INFO, "[ledStress]: LED TOGGLE.\r\n");
        osDelay(1000);

        SR_LedSwitch(LED0, SR_LED_TOGGLE);
        SR_LOG(INFO, "[ledStress]: LED TOGGLE.\r\n");
        osDelay(1000);

        SR_LedBlink(LED0, 5, 300, 300, 0);
        SR_LOG(INFO, "[ledStress]: LED fast blink, blink time = 3s.\r\n");
        osDelay(4000);

        SR_LedBlink(LED0, 3, 500, 500, 0);
        SR_LOG(INFO, "[ledStress]: LED slow blink, blink time = 3s.\r\n");
        osDelay(4000);
    }
}
UTEST_TC_EXPORT(led_stress,
                ledStress_Testcase,
                LedInit,
                LedCleanup,
                TC_PRIORITY_HIGH);
