/***************************************************************************
 *
 * Copyright 2015-2019 BES.
 * All rights reserved. All unpublished rights reserved.
 *
 * No part of this work may be used or reproduced in any form or by any
 * means, or stored in a database or retrieval system, without prior written
 * permission of BES.
 *
 * Use of this work is governed by a license granted by BES.
 * This work contains confidential and proprietary information of
 * BES. which is protected by copyright, trade secret,
 * trademark and other intellectual property rights.
 *
 ****************************************************************************/
#include "cmsis_os.h"
#include "tgt_hardware.h"
#include "hal_gpio.h"
#include "hal_iomux.h"
#include "hal_trace.h"
#include "pmu.h"
#include "app_pwl.h"
#include "string.h"

#define APP_PWL_TRACE(s,...)
//TRACE(s, ##__VA_ARGS__)

#if (CFG_HW_PLW_NUM > 0)
static void app_pwl_timehandler(void const *param);

osTimerDef (APP_PWL_TIMER0, app_pwl_timehandler);                      // define timers
#if (CFG_HW_PLW_NUM == 2)
osTimerDef (APP_PWL_TIMER1, app_pwl_timehandler);
#endif

struct APP_PWL_T {
    enum APP_PWL_ID_T id;
    struct APP_PWL_CFG_T config;
    uint8_t partidx;
    osTimerId timer;
};

static struct APP_PWL_T app_pwl[APP_PWL_ID_QTY];

static void app_pwl_timehandler(void const *param)
{
    struct APP_PWL_T *pwl = (struct APP_PWL_T *)param;
    struct APP_PWL_CFG_T *cfg = &(pwl->config);
    APP_PWL_TRACE(2,"%s %x",__func__, param);

    osTimerStop(pwl->timer);

    pwl->partidx++;
    if (cfg->periodic){
        if (pwl->partidx >= cfg->parttotal){
            pwl->partidx = 0;
        }
    }else{
        if (pwl->partidx >= cfg->parttotal){
            return;
        }
    }

    APP_PWL_TRACE(3,"idx:%d pin:%d lvl:%d", pwl->partidx, cfg_hw_pinmux_pwl[pwl->id].pin, cfg->part[pwl->partidx].level);
    if(!cfg->part[pwl->partidx].level){
#if defined(__PMU_VIO_DYNAMIC_CTRL_MODE__)
        pmu_viorise_req(pwl->id == APP_PWL_ID_0 ? PMU_VIORISE_REQ_USER_PWL0 : PMU_VIORISE_REQ_USER_PWL1, true);
#endif
        hal_gpio_pin_set((enum HAL_GPIO_PIN_T)cfg_hw_pinmux_pwl[pwl->id].pin);
    }else{
        hal_gpio_pin_clr((enum HAL_GPIO_PIN_T)cfg_hw_pinmux_pwl[pwl->id].pin);
#if defined(__PMU_VIO_DYNAMIC_CTRL_MODE__)
        pmu_viorise_req(pwl->id == APP_PWL_ID_0 ? PMU_VIORISE_REQ_USER_PWL0 : PMU_VIORISE_REQ_USER_PWL1, false);
#endif
    }
    osTimerStart(pwl->timer, cfg->part[pwl->partidx].time);
}
#endif

int app_pwl_open(void)
{
#if (CFG_HW_PLW_NUM > 0)
    uint8_t i;
    APP_PWL_TRACE(1,"%s",__func__);
    for (i=0;i<APP_PWL_ID_QTY;i++){
        app_pwl[i].id = APP_PWL_ID_QTY;
        memset(&(app_pwl[i].config), 0, sizeof(struct APP_PWL_CFG_T));
        hal_iomux_init((struct HAL_IOMUX_PIN_FUNCTION_MAP *)&cfg_hw_pinmux_pwl[i], 1);
        hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)cfg_hw_pinmux_pwl[i].pin, HAL_GPIO_DIR_OUT, 1);
    }
    app_pwl[APP_PWL_ID_0].timer = osTimerCreate (osTimer(APP_PWL_TIMER0), osTimerOnce, &app_pwl[APP_PWL_ID_0]);
#if (CFG_HW_PLW_NUM == 2)
    app_pwl[APP_PWL_ID_1].timer = osTimerCreate (osTimer(APP_PWL_TIMER1), osTimerOnce, &app_pwl[APP_PWL_ID_1]);
#endif
#endif
    return 0;
}

int app_pwl_start(enum APP_PWL_ID_T id)
{
#if (CFG_HW_PLW_NUM > 0)
    struct APP_PWL_T *pwl = NULL;
    struct APP_PWL_CFG_T *cfg = NULL;


    if (id >= APP_PWL_ID_QTY) {
        return -1;
    }

    APP_PWL_TRACE(2,"%s %d",__func__, id);

    pwl = &app_pwl[id];
    cfg = &(pwl->config);

    if (pwl->id == APP_PWL_ID_QTY){
        return -1;
    }

    pwl->partidx = 0;
    if (pwl->partidx >= cfg->parttotal){
        return -1;
    }

    osTimerStop(pwl->timer);

    APP_PWL_TRACE(3,"idx:%d pin:%d lvl:%d", pwl->partidx, cfg_hw_pinmux_pwl[pwl->id].pin, cfg->part[pwl->partidx].level);
    if(!cfg->part[pwl->partidx].level){
#if defined(__PMU_VIO_DYNAMIC_CTRL_MODE__)
        pmu_viorise_req(pwl->id == APP_PWL_ID_0 ? PMU_VIORISE_REQ_USER_PWL0 : PMU_VIORISE_REQ_USER_PWL1, false);
#endif
        hal_gpio_pin_set((enum HAL_GPIO_PIN_T)cfg_hw_pinmux_pwl[pwl->id].pin);
    }else{
        hal_gpio_pin_clr((enum HAL_GPIO_PIN_T)cfg_hw_pinmux_pwl[pwl->id].pin);
#if defined(__PMU_VIO_DYNAMIC_CTRL_MODE__)
        pmu_viorise_req(pwl->id == APP_PWL_ID_0 ? PMU_VIORISE_REQ_USER_PWL0 : PMU_VIORISE_REQ_USER_PWL1, false);
#endif
    }
    osTimerStart(pwl->timer, cfg->part[pwl->partidx].time);
#endif
    return 0;
}

int app_pwl_setup(enum APP_PWL_ID_T id, struct APP_PWL_CFG_T *cfg)
{
#if (CFG_HW_PLW_NUM > 0)
    if (cfg == NULL || id >= APP_PWL_ID_QTY) {
        return -1;
    }
    APP_PWL_TRACE(2,"%s %d",__func__, id);

    hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)cfg_hw_pinmux_pwl[id].pin, HAL_GPIO_DIR_OUT, cfg->startlevel?0:1);
    app_pwl[id].id = id;
    memcpy(&(app_pwl[id].config), cfg, sizeof(struct APP_PWL_CFG_T));

    osTimerStop(app_pwl[id].timer);
#endif
    return 0;
}

int app_pwl_stop(enum APP_PWL_ID_T id)
{
#if (CFG_HW_PLW_NUM > 0)
    if (id >= APP_PWL_ID_QTY) {
        return -1;
    }

    osTimerStop(app_pwl[id].timer);
    hal_gpio_pin_set((enum HAL_GPIO_PIN_T)cfg_hw_pinmux_pwl[id].pin);
#endif
    return 0;
}

int app_pwl_close(void)
{
#if (CFG_HW_PLW_NUM > 0)
    uint8_t i;
    for (i=0;i<APP_PWL_ID_QTY;i++){
        if (app_pwl[i].id != APP_PWL_ID_QTY)
            app_pwl_stop((enum APP_PWL_ID_T)i);
    }
#endif
    return 0;
}


