/*************************************************  
  File name     : hal_interface_nv.c
  Module        : hal floodlight library interface typedefs
  Author        : 
  Version       :
  Created on    : 2020-10-20
  Description   :
      Data structure and function definitions required by 
      the floodlight interface
    
  Modify History:   
  1. Date:        Author:         Modification:
  2020-10-20    amir.liang         create
*************************************************/
#include <stdbool.h>
#include "hal_product_config.h"
#include "hal_interface_spotlight.h"
#include "pwm.h"
#include <stdarg.h>
#include "product_bsp_config.h"
#include "hal_gpio.h"

#if HAL_CFG_MCU_ENABLE == HAL_TRUE
#include "mcu_interface.h"
#endif

//#define SPLIGHT_PWM_PERIOD   1000000 // ns, 1K Hz
#define SPLIGHT_PWM_PERIOD   50000 // ns, 20K Hz

static int32_t pwm_init_state = 0;
static int8_t pwm_power_state = 0;
static int8_t pwm_control_called = 0;

static int popen_call(char *args, int size, char *result, int max_size)
{
	int nReadLen = 0;

	if (args != NULL) {
		FILE *pFile = NULL;
		pFile = popen(args, "r");

		if (pFile != NULL) {
			nReadLen = fread(result, 1, max_size, pFile);
			pclose(pFile);
		} else {
			HAL_SPL_LOG_ERROR("popen error:%s\n", args);
			return -1;
		}
	}

	return nReadLen;
}

static int call_system_cmd(char *fmt, ...)
{
    int ret = -1;
	va_list ap;
    char cmd[256] = {0};
	char out[256] = {0};
  
    va_start(ap, fmt);
    vsprintf(cmd, fmt, ap);
    va_end(ap);
    ret = popen_call(cmd, 255, out, 255);
    HAL_SPL_LOG_INFO("popen_call: %s, return=%d, out=%s", cmd, ret, out);
    return ret;
}



static int32_t HAL_SPL_Init(int32_t channel)
{
	int32_t ret = ZFAILED;
	SUPWMChnAttr attr = {0};
	if (pwm_init_state == 1 )
	{
		HAL_SPL_LOG_ERROR("pwm has inited !");
		return 0;
	}

	HAL_SPL_LOG_INFO("pwm init !");

	ret = SU_PWM_Init();
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("pwm init error !");
		return ZFAILED;
	}

	attr.period = SPLIGHT_PWM_PERIOD;
	attr.duty = 0;
	attr.polarity = 1;

	// PWM0
	ret = SU_PWM_CreateChn(PWM0_CHN, &attr);
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("SU_PWM_CreateChn pwm0 error !");
		SU_PWM_Exit();	
		return ZFAILED;
	}

	// PWM1
	ret = SU_PWM_CreateChn(PWM1_CHN, &attr);
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("SU_PWM_CreateChn pwm1 error !");
		SU_PWM_DestroyChn(PWM0_CHN);
		SU_PWM_Exit();	
		return ZFAILED;
	}

#ifdef PRODUCT_IRLED_POWER_PIN
	hal_gpio_export(PRODUCT_IRLED_POWER_PIN);
	hal_gpio_set_dir(PRODUCT_IRLED_POWER_PIN, 1);
#endif
#ifdef PRODUCT_IRLED_ENABLE_PIN
	hal_gpio_export(PRODUCT_IRLED_ENABLE_PIN);
	hal_gpio_set_dir(PRODUCT_IRLED_ENABLE_PIN, 1);
#endif
	pwm_init_state = 1;
	
	return 0;
}

static int32_t HAL_SPL_Deinit(int32_t channel)
{
	if (pwm_init_state == 1)
	{
		SU_PWM_DisableChn(PWM0_CHN);
		SU_PWM_DestroyChn(PWM0_CHN);

		SU_PWM_DisableChn(PWM1_CHN);
		SU_PWM_DestroyChn(PWM1_CHN);

		SU_PWM_Exit();

		pwm_init_state = 0;
		pwm_control_called = 0;	
	}
	
	return 0;
}

static int32_t HAL_SPL_TurnOn(int32_t channel, int32_t colortemp, int32_t brightness)
{
	int ret = -1;
	int duty;
	int bright_value_ch0 = 50;
	int bright_value_ch1 = 50;

	if (pwm_init_state == 0)
	{
		HAL_SPL_LOG_ERROR("pwm not inited !");
		return ZFAILED;
	}

	HAL_SPL_LOG_ERROR("HAL_SPL_TurnOn colortemp %d, brightness %d",colortemp, brightness);

	switch(colortemp) 
	{

		case 5:
		{
			bright_value_ch0 = 0;
			bright_value_ch1 =  (((brightness * 79) / 100) + 21);
		}
		break;
		case 4:
		{
			bright_value_ch0 = (((brightness * 14) / 100) + 6);
			bright_value_ch1 = (((brightness * 55) / 100) + 15);
		}
		break;
		case 3:
		{
			bright_value_ch0 = (((brightness * 35) / 78) + 10);
			bright_value_ch1 = (((brightness * 35) / 78) + 10);	
		}
		break;
		case 2:
		{
			bright_value_ch0 = (((brightness * 55) / 78) + 15);
			bright_value_ch1 = (((brightness * 14) / 78) + 6);
		}
		break;
		case 1:
		{
			bright_value_ch0 = (((brightness * 79) / 100) + 21);
			bright_value_ch1 = 0;
		}
		break;
		default:
		{
			return ZFAILED;
		}
		break;
	}


	//if (brightness > 0)
	{
		ret = SU_PWM_EnableChn(PWM0_CHN);
		if (ret < 0)
		{
			HAL_SPL_LOG_ERROR("chn0 pwm enable error !");
			return ZFAILED;
		}

		ret = SU_PWM_EnableChn(PWM1_CHN);
		if (ret < 0)
		{
			HAL_SPL_LOG_ERROR("chn0 pwm enable error !");
			return ZFAILED;
		}
	}

	duty = bright_value_ch0 * SPLIGHT_PWM_PERIOD / 100;
	ret = SU_PWM_ModifyChnDuty(PWM0_CHN, duty);
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("Failed to modify duty(%d) !",duty);
		return ZFAILED;
	}

	duty = bright_value_ch1 * SPLIGHT_PWM_PERIOD / 100;
	ret = SU_PWM_ModifyChnDuty(PWM1_CHN, duty);
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("Failed to modify duty(%d) !",duty);
		return ZFAILED;
	}

	HAL_SPL_LOG_ERROR("HAL_SPL_TurnOn bright_value_ch0=%d, bright_value_ch1 = %d,ret=%d,duty=%d", bright_value_ch0,bright_value_ch1, ret,duty);

/*	if (pwm_init_state)
	{
		HAL_SPL_LOG_ERROR("pwm has inited !");
		return 0;
	}
	call_system_cmd("devmem 0x10011048 32 0x00040000");
	pwm_init_state = 1;*/

	pwm_control_called = 1;
	pwm_power_state = SPL_POWER_ON;

	return 0;
}

static int32_t HAL_SPL_TurnOff(int32_t channel)
{
	int ret = -1;
	if (pwm_init_state == 0)
	{
		HAL_SPL_LOG_ERROR("pwm not inited !");
		return ZFAILED;
	}

	ret = SU_PWM_DisableChn(PWM0_CHN);
	ret = SU_PWM_DisableChn(PWM1_CHN);
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("pwm disable error !");
		return ZFAILED;
	}

	HAL_SPL_LOG_INFO("HAL_SPL_TurnOff called!");
/*
	if (pwm_init_state == 1) {
		call_system_cmd("devmem 0x10011044 32 0x00040000");
	}	
	pwm_init_state = 0;
*/
	pwm_control_called = 1;	
	pwm_power_state = SPL_POWER_OFF;
	return 0;
}

static int32_t HAL_SPL_SlightSet(int32_t channel, int32_t colortemp, int32_t brightness)
{
	int ret = -1;
	int duty;
	int bright_value_ch0 = 50;
	int bright_value_ch1 = 50;
	char tmpbuf[32] = {0};

	if (pwm_init_state == 0)
	{
		HAL_SPL_LOG_ERROR("pwm not inited !");
		return ZFAILED;
	}

	HAL_SPL_LOG_ERROR("HAL_SPL_SlightSet colortemp %d, brightness %d", colortemp, brightness);

	

	switch(colortemp) 
	{

		case 5:
		{
			bright_value_ch0 = 0;
			bright_value_ch1 =  (((brightness * 79) / 100) + 21);
		}
		break;
		case 4:
		{
			bright_value_ch0 = (((brightness * 14) / 100) + 6);
			bright_value_ch1 = (((brightness * 55) / 100) + 15);
		}
		break;
		case 3:
		{
			bright_value_ch0 = (((brightness * 35) / 78) + 10);
			bright_value_ch1 = (((brightness * 35) / 78) + 10);	
		}
		break;
		case 2:
		{
			bright_value_ch0 = (((brightness * 55) / 78) + 15);
			bright_value_ch1 = (((brightness * 14) / 78) + 6);
		}
		break;
		case 1:
		{
			bright_value_ch0 = (((brightness * 79) / 100) + 21);
			bright_value_ch1 = 0;
		}
		break;
		default:
		{
			return ZFAILED;
		}
		break;
	}

	//if (bright_value > 0)
	{
		ret = SU_PWM_EnableChn(PWM0_CHN);
		if (ret < 0)
		{
			HAL_SPL_LOG_ERROR("chn2 pwm0 enable  error !");
			return ZFAILED;
		}
		ret = SU_PWM_EnableChn(PWM1_CHN);
		if (ret < 0)
		{
			HAL_SPL_LOG_ERROR("chn2 pwm1 enable error !");
			return ZFAILED;
		}
	}

	duty = bright_value_ch0 * SPLIGHT_PWM_PERIOD / 100;
	ret = SU_PWM_ModifyChnDuty(PWM0_CHN, duty);
	if (ret)
	{
		HAL_SPL_LOG_ERROR("Failed to modify pwm0 duty(%d) !",duty);
		duty = 0;
	}

	duty = bright_value_ch1 * SPLIGHT_PWM_PERIOD / 100;
	ret = SU_PWM_ModifyChnDuty(PWM1_CHN, duty);
	if (ret)
	{
		HAL_SPL_LOG_ERROR("Failed to modify pwm1 duty(%d) !",duty);
		duty = 0;
	}

	HAL_SPL_LOG_ERROR("set slight light pwm bright_value_chn0 %d, bright_value_chn1 %d,  ret=%d", bright_value_ch0, bright_value_ch1, ret);


	//call_system_cmd("tag_env_info --set HW pwm0_duty %d",bright_value_chn0);
	//call_system_cmd("tag_env_info --set HW pwm1_duty %d",bright_value_chn1);
	sprintf(tmpbuf, "pwm0_duty=%d", bright_value_ch0);
	_IMP_Tag_SetParameter(tmpbuf, 0, 0);
	HAL_SPL_LOG_ERROR("set slight light pwm bright_value_chn0 %s", tmpbuf);
	memset(tmpbuf,0,sizeof(tmpbuf));
	sprintf(tmpbuf, "pwm1_duty=%d", bright_value_ch1);
	_IMP_Tag_SetParameter(tmpbuf, 0, 0);
	HAL_SPL_LOG_ERROR("set slight light pwm bright_value_chn1 %s", tmpbuf);
	return 0;
}

static int32_t HAL_SPL_GetStatus(int32_t channel,int32_t *value)
{
	int8_t cmd_res[16] = {0};
	if (pwm_control_called == 0)
	{
		popen_call("cat /proc/ir_status",strlen("cat /proc/ir_status"),cmd_res,16);
		if (strcmp(cmd_res,"led") == 0) 
		{
			pwm_power_state = SPL_POWER_ON;
		}else{
			pwm_power_state = SPL_POWER_OFF;
		}
	}

	if (value == NULL)
	{
		return ZFAILED;
	}
	*value = pwm_power_state;
	HAL_SPL_LOG_ERROR("HAL_SPL_GetStatus status : %s,pwm_power_state : %d,pwm_control_called : %d", cmd_res,pwm_power_state,pwm_control_called);
	return 0;
}

static int32_t HAL_SPL_ModeSet(int32_t channel,int32_t mode)
{
	char modes[5][16] = {"ir_mode=auto","ir_mode=on","ir_mode=off","ir_mode=off","ir_mode=pwm"};
	int ret = 0;

	HAL_SPL_LOG_ERROR("HAL_SPL_ModeSet mode %d--modes : %s", mode, modes[mode]);
	ret = _IMP_Tag_SetParameter(modes[mode], 0,0);
	HAL_SPL_LOG_ERROR("HAL_SPL_ModeSetIMP_Sync_Client_Proc return  : %d", ret);

	return 0;
	
}

#ifdef PRODUCT_SPOTLIGHT_ONE_PWM

//白光灯电源控制
int32_t spotlight_Power_SetSwitch(bool enable)
{
#if HAL_CFG_MCU_ENABLE == HAL_TRUE
    UN_MCU_WRITE_CMD_ID_VALUE value;
    EN_MCU_MSG_RESULT ret = EN_MCU_MSG_RESULT_FAIL;
    value.data = enable;
    ret = mcu_interface_type1_process(EN_MCU_CMD_SPOTLIGHT_POWER_CTRL,&value,NULL);
    if (EN_MCU_MSG_RESULT_SUCCESS == ret)
    {
        HAL_SPL_LOG_ERROR("spotlight_Power_SetSwitch = %d suc",enable);
        return 0;
    }
	HAL_SPL_LOG_ERROR("spotlight_Power_SetSwitch = %d fail, ret:%d",enable,ret);
#else
	#ifdef PRODUCT_SPOTLIGHT_POWER_PIN
	hal_gpio_set_value(PRODUCT_SPOTLIGHT_POWER_PIN, enable?1:0);
	#endif
	#ifdef PRODUCT_SPOTLIGHT_ENABLE_PIN
	hal_gpio_set_value(PRODUCT_SPOTLIGHT_ENABLE_PIN, enable?1:0);
	#endif
#endif
    return ZFAILED;
}

int32_t HAL_SPL_Init_One_Pwm(int32_t channel)
{
	int32_t ret = ZFAILED;
	SUPWMChnAttr attr = {0};

	if (pwm_init_state == 1 )
	{
		HAL_SPL_LOG_ERROR("pwm has inited !");
		return 0;
	}

	HAL_SPL_LOG_INFO("pwm init !");

	ret = SU_PWM_Init();
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("pwm init error !");
		return ZFAILED;
	}

	attr.period = SPLIGHT_PWM_PERIOD;
	attr.duty = 0;
	attr.polarity = 1;

	// PWM0
	ret = SU_PWM_CreateChn(PRODUCT_SPOTLIGHT_PWM_CH, &attr);
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("SU_PWM_CreateChn pwm0 error !");
		SU_PWM_Exit();	
		return ZFAILED;
	}
#ifdef PRODUCT_SPOTLIGHT_POWER_PIN
	hal_gpio_export(PRODUCT_SPOTLIGHT_POWER_PIN);
	hal_gpio_set_dir(PRODUCT_SPOTLIGHT_POWER_PIN, 1);
#endif
#ifdef PRODUCT_SPOTLIGHT_ENABLE_PIN
	hal_gpio_export(PRODUCT_SPOTLIGHT_ENABLE_PIN);
	hal_gpio_set_dir(PRODUCT_SPOTLIGHT_ENABLE_PIN, 1);
#endif
	pwm_init_state = 1;
	
	return 0;
}

static int32_t HAL_SPL_Deinit_One_Pwm(int32_t channel)
{
	if (pwm_init_state == 1)
	{
		SU_PWM_DisableChn(PRODUCT_SPOTLIGHT_PWM_CH);
		SU_PWM_DestroyChn(PRODUCT_SPOTLIGHT_PWM_CH);

		SU_PWM_Exit();

		pwm_init_state = 0;
		pwm_control_called = 0;	
	}
	
	return 0;
}

int32_t HAL_SPL_TurnOn_One_Pwm(int32_t channel, int32_t colortemp, int32_t brightness)
{
	int ret = -1;
	int duty;
	int bright_value_ch0 = 50;

	if (pwm_init_state == 0)
	{
		HAL_SPL_LOG_ERROR("pwm not inited !");
		return ZFAILED;
	}

	HAL_SPL_LOG_INFO("HAL_SPL_TurnOn colortemp %d, brightness %d",colortemp, brightness);


	bright_value_ch0 = (((brightness * 79) / 100) + 21);


	ret = SU_PWM_EnableChn(PRODUCT_SPOTLIGHT_PWM_CH);
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("chn0 pwm enable error !");
		return ZFAILED;
	}

    //开启白光灯灯源
    spotlight_Power_SetSwitch(true);

	duty = bright_value_ch0 * SPLIGHT_PWM_PERIOD / 100;
	ret = SU_PWM_ModifyChnDuty(PRODUCT_SPOTLIGHT_PWM_CH, duty);
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("Failed to modify duty(%d) !",duty);
		return ZFAILED;
	}

	HAL_SPL_LOG_INFO("HAL_SPL_TurnOn bright_value_ch0=%d,ret=%d,duty=%d", bright_value_ch0,ret,duty);

	pwm_control_called = 1;
	pwm_power_state = SPL_POWER_ON;

	return 0;
}

int32_t HAL_SPL_TurnOff_One_Pwm(int32_t channel)
{
	int ret = -1;

	if (pwm_init_state == 0)
	{
		HAL_SPL_LOG_ERROR("pwm not inited !");
		return ZFAILED;
	}

	ret = SU_PWM_DisableChn(PRODUCT_SPOTLIGHT_PWM_CH);
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("pwm disable error !");
		return ZFAILED;
	}

    //关闭白光灯灯源
    spotlight_Power_SetSwitch(false);

	HAL_SPL_LOG_INFO("HAL_SPL_TurnOff called!");

	pwm_control_called = 1;	
	pwm_power_state = SPL_POWER_OFF;
	return 0;
}

int32_t HAL_SPL_SlightSet_One_Pwm(int32_t channel, int32_t colortemp, int32_t brightness)
{
	int ret = -1;
	int duty;
	int bright_value_ch0 = 50;
	char tmpbuf[32] = {0};

	if (pwm_init_state == 0)
	{
		HAL_SPL_LOG_ERROR("pwm not inited !");
		return ZFAILED;
	}

	HAL_SPL_LOG_INFO("HAL_SPL_SlightSet colortemp %d, brightness %d", colortemp, brightness);

    //开启白光灯灯源
    spotlight_Power_SetSwitch(true);

	bright_value_ch0 = (((brightness * 79) / 100) + 21);

	ret = SU_PWM_EnableChn(PRODUCT_SPOTLIGHT_PWM_CH);
	if (ret < 0)
	{
		HAL_SPL_LOG_ERROR("chn pwm0 enable  error !");
		return ZFAILED;
	}

	duty = bright_value_ch0 * SPLIGHT_PWM_PERIOD / 100;
	ret = SU_PWM_ModifyChnDuty(PRODUCT_SPOTLIGHT_PWM_CH, duty);
	if (ret)
	{
		HAL_SPL_LOG_ERROR("Failed to modify pwm0 duty(%d) !",duty);
		duty = 0;
	}


	HAL_SPL_LOG_INFO("set slight light pwm bright_value_chn0 %d,  ret=%d", bright_value_ch0, ret);


	//call_system_cmd("tag_env_info --set HW pwm0_duty %d",bright_value_chn0);
	sprintf(tmpbuf, "pwm0_duty=%d", bright_value_ch0);
	_IMP_Tag_SetParameter(tmpbuf, 0, 0);
	HAL_SPL_LOG_INFO("set slight light pwm bright_value_chn0 %s", tmpbuf);

	return 0;
}
#endif

#if defined(PRODUCT_SPOTLIGHT)
static ST_HAL_SPOTLIGHT_INTERFACE gHalSpotlightInterface[] = 
{
#ifdef PRODUCT_SPOTLIGHT_ONE_PWM
	{
    	.pfnInit = HAL_SPL_Init_One_Pwm,
    	.pfnDeinit = HAL_SPL_Deinit_One_Pwm,
    	.pfnTurnOn = HAL_SPL_TurnOn_One_Pwm,
    	.pfnTurnOff = HAL_SPL_TurnOff_One_Pwm,
    	.pfnGetLightStatus = HAL_SPL_GetStatus,
    	.pfnSlightSet = HAL_SPL_SlightSet_One_Pwm,
		.pfnModeSet = HAL_SPL_ModeSet,
    },
#else
    {
    	.pfnInit = HAL_SPL_Init,
    	.pfnDeinit = HAL_SPL_Deinit,
    	.pfnTurnOn = HAL_SPL_TurnOn,
    	.pfnTurnOff = HAL_SPL_TurnOff,
    	.pfnGetLightStatus = HAL_SPL_GetStatus,
    	.pfnSlightSet = HAL_SPL_SlightSet,
		.pfnModeSet = HAL_SPL_ModeSet,
    },
#endif
};
#endif

ST_HAL_SPOTLIGHT_INTERFACE *HAL_Spotlight_GetInterface(int32_t channel)
{
#if defined(PRODUCT_SPOTLIGHT)
    return &gHalSpotlightInterface[0];
#else
    return NULL;
#endif
}


