#include "user_led.h"
#include "user_ws2812b.h"
#include "define.h"
#include "stdarg.h"

tmosTaskID led_task_id = INVALID_TASK_ID;

static uint32_t alarm_stat = 0;

static uint16_t led_task_process_event(uint8_t task_id, uint16_t events);
static void prvSet_led_duty(LED_TYPE type);

static led_work_s led_work[LED_TYPE_MAX] = {
  {
      .idx = DEV_LED,
      .color = {
        .red = 0,
        .green = 0xFF,
        .blue = 0,
      },
      .workStat = LED_WORK_OFF,
      .viewStat = LED_VIEW_NULL,
      .single_flicker_period = 0,
      .flicker_period = 0,
      .flicker_onperiod = 0,
      .flicker_count = 0,
      .duty_value = 0,
      .single_on_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .on_durationTime = 0,				    //PWM变化结束后持续时间，单位：ms
      .single_off_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .off_durationTime = 0,				//PWM变化结束后持续时间，单位：ms
  },
  {
      .idx = LED_01,
      .color = {
        .red = 0,
        .green = 0,
        .blue = 0,
      },
      .workStat = LED_WORK_OFF,
      .viewStat = LED_VIEW_NULL,
      .single_flicker_period = 0,
      .flicker_period = 0,
      .flicker_onperiod = 0,
      .flicker_count = 0,
      .duty_value = 0,
      .single_on_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .on_durationTime = 0,				    //PWM变化结束后持续时间，单位：ms
      .single_off_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .off_durationTime = 0,				//PWM变化结束后持续时间，单位：ms
  },
  {
      .idx = LED_02,
      .color = {
        .red = 0,
        .green = 0,
        .blue = 0,
      },
      .workStat = LED_WORK_OFF,
      .viewStat = LED_VIEW_NULL,
      .single_flicker_period = 0,
      .flicker_period = 0,
      .flicker_onperiod = 0,
      .flicker_count = 0,
      .duty_value = 0,
      .single_on_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .on_durationTime = 0,				    //PWM变化结束后持续时间，单位：ms
      .single_off_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .off_durationTime = 0,				//PWM变化结束后持续时间，单位：ms
  },
  {
      .idx = LED_03,
      .color = {
        .red = 0,
        .green = 0,
        .blue = 0,
      },
      .workStat = LED_WORK_OFF,
      .viewStat = LED_VIEW_NULL,
      .single_flicker_period = 0,
      .flicker_period = 0,
      .flicker_onperiod = 0,
      .flicker_count = 0,
      .duty_value = 0,
      .single_on_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .on_durationTime = 0,				    //PWM变化结束后持续时间，单位：ms
      .single_off_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .off_durationTime = 0,				//PWM变化结束后持续时间，单位：ms
  },
  {
      .idx = LED_04,
      .color = {
        .red = 0,
        .green = 0,
        .blue = 0,
      },
      .workStat = LED_WORK_OFF,
      .viewStat = LED_VIEW_NULL,
      .single_flicker_period = 0,
      .flicker_period = 0,
      .flicker_onperiod = 0,
      .flicker_count = 0,
      .duty_value = 0,
      .single_on_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .on_durationTime = 0,				    //PWM变化结束后持续时间，单位：ms
      .single_off_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .off_durationTime = 0,				//PWM变化结束后持续时间，单位：ms
  },
  {
      .idx = LED_05,
      .color = {
        .red = 0,
        .green = 0,
        .blue = 0,
      },
      .workStat = LED_WORK_OFF,
      .viewStat = LED_VIEW_NULL,
      .single_flicker_period = 0,
      .flicker_period = 0,
      .flicker_onperiod = 0,
      .flicker_count = 0,
      .duty_value = 0,
      .single_on_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .on_durationTime = 0,				    //PWM变化结束后持续时间，单位：ms
      .single_off_durationTime = 0,			//PWM变化结束后持续时间，单位：ms
      .off_durationTime = 0,				//PWM变化结束后持续时间，单位：ms
  },
};

/*******************************************************************************
  * @函数名称   prvSet_led_duty
  * @函数说明   设置指示灯亮度
  * @输入参数  	type：灯下标
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvSet_led_duty(LED_TYPE type)
{
    vUser_ws2812b_set_stat(type, led_work[type].color.red, led_work[type].color.green, 
                            led_work[type].color.blue, led_work[type].duty_value);
}

/*******************************************************************************
  * @函数名称   led_invert
  * @函数说明   LED闪烁处理
  * @输入参数  	led_work：led灯结构体直针
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void led_invert(led_work_s *led_work)
{
    if(led_work->flicker_count > 0)
    {
        if(led_work->single_flicker_period == 0)
        {
            led_work->single_flicker_period = led_work->flicker_period;
            led_work->stat = LED_STAT_ON;
            led_work->duty_value = 100;
            prvSet_led_duty(led_work->idx);
        }
        else if(led_work->single_flicker_period == (led_work->flicker_period - led_work->flicker_onperiod))
        {
            led_work->single_flicker_period--;
            led_work->stat = LED_STAT_OFF;
            led_work->duty_value = 0;
            prvSet_led_duty(led_work->idx);
            led_work->flicker_count--;
        }
        else{
            led_work->single_flicker_period--;
        }
    }
    else{
        led_work->workStat = LED_WORK_OFF;
        led_work->duty_value = 0;
        prvSet_led_duty(led_work->idx);
    }
}

/*******************************************************************************
  * @函数名称   led_heart
  * @函数说明   LED呼吸灯处理
  * @输入参数  	led_work：led灯结构体直针
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void led_heart(led_work_s *led_work)
{
  if(led_work->flicker_count > 0)
  {
      uint32_t off_period = led_work->flicker_period - led_work->flicker_onperiod;
      if(led_work->single_flicker_period == 0)
      {
        led_work->single_flicker_period = led_work->flicker_period;
        led_work->duty_value = 0;
        led_work->single_off_durationTime = led_work->off_durationTime;
        prvSet_led_duty(led_work->idx);
        led_work->flicker_count--;
      }
      else if(led_work->single_flicker_period == off_period)
      {
        led_work->single_flicker_period--;
        led_work->duty_value = 100;
        led_work->single_on_durationTime = led_work->on_durationTime;
        prvSet_led_duty(led_work->idx);
      }
      else{
        if(led_work->single_flicker_period > off_period)
        {
            if(led_work->single_off_durationTime == 0)
            {
                led_work->single_flicker_period--;
                led_work->duty_value = (led_work->flicker_period - led_work->single_flicker_period) * 100 / led_work->flicker_onperiod;
                prvSet_led_duty(led_work->idx);
            }
            else{
                led_work->single_off_durationTime--;
            }
        }
        else{
            if(led_work->single_on_durationTime == 0)
            {
                led_work->single_flicker_period--;
                led_work->duty_value = led_work->single_flicker_period * 100 / off_period;
                prvSet_led_duty(led_work->idx);
            }
            else{
                led_work->single_on_durationTime--;
            }
        }
      }
  }
  else{
      led_work->workStat = LED_WORK_OFF;
  }
}

/*******************************************************************************
  * @函数名称   led_indication
  * @函数说明   LED灯处理
  * @输入参数  	led_work：led灯结构体直针
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void led_indication(led_work_s *led_work)
{
    switch(led_work->workStat)
    {
        case LED_WORK_OFF:
        {
            break;
        }
        case LED_WORK_ON:
        {
            break;
        }
        case LED_WORK_INVERT:
        {
            led_invert(led_work);
            break;
        }
        case LED_WORK_BREATHE:
        {
            led_heart(led_work);
            break;
        }
        default:break;
    }
}

/*******************************************************************************
  * @函数名称   led_task
  * @函数说明   LED任务
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void led_task(void)
{
    for(int i = 0; i < LED_TYPE_MAX; i++)
    {
	    led_indication(&led_work[i]);
    }
}

/*******************************************************************************
  * @函数名称   led_task
  * @函数说明   task的event处理回调函数,需要在注册task时候,传进去
  * @输入参数  	task_id：任务ID
               events：事件
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static uint16_t led_task_process_event(uint8_t task_id, uint16_t events)
{
    //event 处理
    if(events & (1 << LED_QUEUE_TIME))
    {
        led_task();
        return (events ^ (1 << LED_QUEUE_TIME)); //异或的方式清除该事件运行标志，并返回未运行的事件标志
    }

    return 0;
}

/*******************************************************************************
  * @函数名称   set_led_indication
  * @函数说明   LED参数设置
  * @输入参数  	type：LED灯号
               color：颜色
               workStat：状态
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
bool set_led_indication(LED_TYPE type, uint32_t color, LED_WORK_STAT work_stat, ...)
{
    bool stat = false;

    if(type >= LED_TYPE_MAX)
    {
	    goto exit;
    }

    led_work[type].color.red = (color >> 16) & 0xFF;
    led_work[type].color.green = (color >> 8) & 0xFF;
    led_work[type].color.blue = color & 0xFF;

    if(work_stat == LED_WORK_OFF || work_stat == LED_WORK_ON)
    {
        led_work[type].workStat = work_stat;
        led_work[type].duty_value = (work_stat == LED_WORK_ON) ? 100 : 0;
        prvSet_led_duty(led_work[type].idx);
        stat = true;
    }
    else if(work_stat == LED_WORK_INVERT || work_stat == LED_WORK_BREATHE)
    {
        led_work[type].workStat = work_stat;
        led_work[type].duty_value = 0;
        led_work[type].stat = LED_STAT_OFF;

        va_list ap;    						//保存所有参数
        va_start(ap, work_stat);	//第一个参数的位置
        led_work[type].flicker_period = va_arg(ap, uint32_t)/LED_INTERVAL;
        led_work[type].flicker_onperiod = va_arg(ap, uint32_t)/LED_INTERVAL;
        led_work[type].flicker_count = va_arg(ap, uint32_t);
        if(led_work[type].flicker_count == 0)
        {
            led_work[type].flicker_count = 0x7FFFFFFF;
        }
        led_work[type].single_flicker_period = led_work[type].flicker_period;

        if(work_stat == LED_WORK_BREATHE)
        {
            led_work[type].on_durationTime = va_arg(ap, uint32_t) / LED_INTERVAL;
            led_work[type].off_durationTime = va_arg(ap, uint32_t) / LED_INTERVAL;
            led_work[type].single_on_durationTime = led_work[type].on_durationTime;
            led_work[type].single_off_durationTime = led_work[type].off_durationTime;
        }

        va_end(ap);

        for(int i = 0; i < LED_TYPE_MAX; i++)
        {
            if(led_work[i].workStat == LED_WORK_INVERT 
            || led_work[i].workStat == LED_WORK_BREATHE)
            {
                led_work[i].single_flicker_period = led_work[i].flicker_period;
                led_work[i].duty_value = 0;
                if(led_work[i].workStat == LED_WORK_BREATHE)
                {
                    led_work[i].single_on_durationTime = led_work[i].on_durationTime;
                    led_work[i].single_off_durationTime = led_work[i].off_durationTime;
                }
            }
        }

        stat = true;
    }
exit:
    return stat;
}

/*******************************************************************************
  * @函数名称   led_task_init
  * @函数说明   LED任务初始化
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void led_task_init(void)
{
    led_task_id  = TMOS_ProcessEventRegister(led_task_process_event);
    PRINT("led_task_id=%d\n", led_task_id);
}

/*******************************************************************************
  * @函数名称   led_task_start
  * @函数说明   LED任务开始
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void led_task_start(void)
{
    bStatus_t stat = tmos_start_reload_task(led_task_id, (1 << LED_QUEUE_TIME), MS1_TO_SYSTEM_TIME(LED_INTERVAL));
}

/*******************************************************************************
  * @函数名称   vUser_led_set_view_stat
  * @函数说明   设置LED显示状态
  * @输入参数  	stat：led显示状态
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void vUser_led_set_view_stat(LED_TYPE idx, led_view_stat_e stat)
{
    PRINT("set No.%d led stat:%d\n", idx + 1, stat);
    led_work[idx + 1].viewStat = stat;
    if(alarm_stat == 0)
    {
        switch(stat)
        {
            case LED_VIEW_ALARM:set_led_indication(idx + 1, LED_VIEW_ALARM_COLOR, LED_WORK_INVERT, 1000, 500, 0);break;                       //报警
            case LED_VIEW_WARN:set_led_indication(idx + 1, LED_VIEW_WARN_COLOR, LED_WORK_BREATHE, 3000, 1500, 0, 500, 500);break;            //警告
            case LED_VIEW_ELECT_FAUIL:set_led_indication(idx + 1, LED_VIEW_ELECT_FAULT_COLOR, LED_WORK_INVERT, 200, 100, 0);break;            //电磁锁故障
            case LED_VIEW_LOCK_ELECT:set_led_indication(idx + 1, LED_VIEW_LOCK_ELECT_COLOR, LED_WORK_ON);break;                                       //有挂锁并上锁
            case LED_VIEW_NOLOCK_ELECT:set_led_indication(idx + 1, LED_VIEW_NOLOCK_ELECT_COLOR, LED_WORK_BREATHE, 500, 250, 0, 100, 100);break;         //无挂锁并上锁
            case LED_VIEW_LOCK_NOELECT:set_led_indication(idx + 1, LED_VIEW_LOCK_NOELECT_COLOR, LED_WORK_BREATHE, 500, 250, 0, 100, 100);break;       //有挂锁没上锁
            case LED_VIEW_NOLOCK_NOELECT:set_led_indication(idx + 1, LED_VIEW_NOLOCK_NOELECT_COLOR, LED_WORK_ON);break;                                 //无挂锁没上锁
            default:break;
        }
    }
}

/*******************************************************************************
  * @函数名称   vUser_led_set_alarm_view
  * @函数说明   设置LED故障显示状态
  * @输入参数  	alarmStat：故障类型
                stat：故障状态
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void vUser_led_set_alarm_view(led_all_alarm_stat_e alarmStat, bool stat)
{
    if(stat == true)
    {
        alarm_stat |= (1 << alarmStat);
    }
    else{
        alarm_stat &= ~(1 << alarmStat);
    }

    if((alarm_stat & (1 << LED_ALL_ALARM_RST)) != 0)
    {
        for(int i = 0; i < LED_TYPE_MAX; i++)
        {
            set_led_indication(i, WS2812B_RST_RGB, LED_WORK_INVERT, 1000, 500, 0, 0, 0);
        }
    }
    else if((alarm_stat & (1 << LED_ALL_ALARM_BLE)) != 0)
    {
        for(int i = 0; i < LED_TYPE_MAX; i++)
        {
            set_led_indication(i, WS2812B_BLE_RGB, LED_WORK_INVERT, 200, 100, 0, 0, 0);
        }
    }
    else if((alarm_stat & (1 << LED_ALL_ALARM_CAN_IDX_ERROR)) != 0)
    {
        for(int i = 0; i < LED_TYPE_MAX; i++)
        {
            set_led_indication(i, WS2812B_CANID_ERROR_RGB, LED_WORK_BREATHE, 3000, 1500, 0, 500, 500);
        }
    }
    else if((alarm_stat & (1 <<  LED_ALL_ALARM_OFFLINE)) != 0)
    {
        for(int i = 0; i < LED_TYPE_MAX; i++)
        {
            set_led_indication(i, WS2812B_OFFLINE_RGB, LED_WORK_BREATHE, 300, 150, 0, 100, 100);
        }
    }
    else if(alarm_stat == 0)
    {
        set_led_indication(DEV_LED, WS2812B_NORMAL_RGB, LED_WORK_INVERT, 5000, 2500, 0);
        for(int i = 1; i < LED_TYPE_MAX; i++)
        {
            vUser_led_set_view_stat(i - 1, led_work[i].viewStat);
        }
    }
}
