/*
 ******************************************************************************
 * @file    lp5569_reg.c
 * @author  MEMS Software Solution Team
 * @brief   SI47XX driver file
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2018 STMicroelectronics</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its
 *      contributors may be used to endorse or promote products derived from
 *      this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */
#include "FreeRTOS.h"
#include "task.h"

#include "string.h"
#include "hal_log.h"

#include "bsp_customer_config.h"

#include "lp5569_reg.h"
#include "bsp_led_taillight.h"

#define BSP_LP5569_TYPE "LP5569"

static lp5569_ctx_t g_dev_ctx;
static LED_Taillight_type_t g_led_taillight_status;
static void led_driver_init(void);

int32_t lp5569_read_reg(uint8_t reg, uint8_t *data, uint16_t len)
{
    return g_dev_ctx.read_reg(g_dev_ctx.handle, reg, data, len);
}

int32_t lp5569_write_reg(uint8_t *data, uint16_t len)
{
    return g_dev_ctx.write_reg(g_dev_ctx.handle, data, len);
}

bool lp5569_init(lp5569_write_ptr write_reg, lp5569_read_ptr read_reg, void* handle)
{
    bsp_led_taillight_t *led_taillight = (bsp_led_taillight_t*)handle;

    if ((write_reg == NULL) || (read_reg == NULL) || (handle == NULL)) {
        log_hal_msgid_info("[lp5569_init] init error\r\n", 0);
        return false;
    }

    g_dev_ctx.write_reg = (lp5569_write_ptr)write_reg;
    g_dev_ctx.read_reg  = (lp5569_read_ptr)read_reg;
    g_dev_ctx.handle    = handle;
	
	led_taillight->i2c_addr = LP5569_ADDRESS;

	log_hal_msgid_info("slave addr %d check done\r\n", 1, led_taillight->i2c_addr);
	return true;
}

const char* lp5569_get_type(void)
{
    return BSP_LP5569_TYPE;
}

static void led_driver_init(void)
{
	uint8_t tx[2] = {0x00, 0x00};
	int32_t ack = 0;
	g_led_taillight_status = LED_TAILLIGHT_OFF;

	LED_TAILLIGHT_EN_HIGH();
	
	vTaskDelay(20 / portTICK_RATE_MS);

//	uint16 i = 0;
//	/*32 * 16*/ /*s6.src*/
//	const uint8 table_32[] = {0x01, 0xB6, 0x9F, 0x80, 0x40, 0x00, 0x32, 0x32, 0x07, 0xFF, 0x66, 0x00, 0x00, 0x00, 0x9F, 0x80,
//						0x40, 0x00, 0x0A, 0xFF, 0x07, 0xFF, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
//						
//	const uint8 table_32[] = {0x01, 0xB6, 0x9F, 0x80, 0x40, 0x00, 0x32, 0x32, 0x07, 0xFF, 0x66, 0x00, 0x00, 0x00, 0x9F, 0x80,
//						0x40, 0x00, 0x0A, 0xFF, 0x07, 0xFF, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
//
//
//	/*s7_a.src left led*/
//	const uint8 table_32[] = {0x00, 0x92, 0x9F, 0x80, 0x40, 0x00, 0x20, 0x32, 0x03, 0xFF, 0x5A, 0x00, 0x00, 0x00, 0x9F, 0x80,
//							  0x40, 0x00, 0x06, 0xFF, 0x03, 0xFF, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
//	
//	/*s7_a.src right led*/
//	const uint8 table_32[] = {0x01, 0x24, 0x9F, 0x80, 0x40, 0x00, 0x20, 0x32, 0x03, 0xFF, 0x5A, 0x00, 0x00, 0x00, 0x9F, 0x80,
//							  0x40, 0x00, 0x06, 0xFF, 0x03, 0xFF, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};						  

	/*s7.src*/
	uint8_t table_32[] = {0x50, /*memory start address*/
							01, B6, 9F, 80, 40, 00, 06, FF, 74, 00, 74, 00, 5A, 00, 05, FF, 74, 00, 74, 00, 5A, 00, A0, 87, A0, 02, /* ENGIN 1 - breathing pattern*/
							9F, 80, 40, FF, 48, 00, 40, 00, 48, 00, A0, 8D, 7A, 00, 7A, 00, A0, 92, A0, 0D, /* ENGIN 2 - double flash pattern */ 
							9F, 80, 40, FF, 48, 00, 40, 00, 48, 00, A0, 17, /* ENGIN 3 - fast flash pattern*/
							00, 00};

	/*chip disable*/
	tx[0] = 0x00;	tx[1] = 0x00;
	ack = lp5569_write_reg(tx, 2);
    
	/*chip enable*/
	tx[0] = 0x00;	tx[1] = 0x40;
	ack = lp5569_write_reg(tx, 2);

	/*MISC Register*/
//	tx[0] = 0x2F;	tx[1] = 0x48;	/*address auto disable*/
	tx[0] = 0x2F;	tx[1] = 0x70;	/*address auto enable*/
	ack = lp5569_write_reg(tx, 2);
	
	/*control*/
	tx[0] = 0x02;	tx[1] = 0x54;	// 1CH, 2CH, 3CH Load Program to SRAM
	ack = lp5569_write_reg(tx, 2);
     
	/*Engine Program Starting Address*/
	tx[0] = 0x4B;	tx[1] = 0x01;	// ENGINE1_PROG_START Register
	ack = lp5569_write_reg(tx, 2);
    
   	tx[0] = 0x4C;	tx[1] = 0x0D;	// ENGINE2_PROG_START Register
	ack = lp5569_write_reg(tx, 2);

   	tx[0] = 0x4D;	tx[1] = 0x17;	// ENGINE3_PROG_START Register
	ack = lp5569_write_reg(tx, 2);

	tx[0] = 0x4F;	tx[1] = 0x00;	// ENGINE4_PROG_START Register
	ack = lp5569_write_reg(tx, 2);

	/*load data*/
  	ack = lp5569_write_reg(table_32, 33);

	/*chip disable*/
	tx[0] = 0x00;	tx[1] = 0x00;
	ack = lp5569_write_reg(tx, 2);
}

static void led_driver_deinit(void) {
	vTaskDelay(20 / portTICK_RATE_MS);
	
	LED_TAILLIGHT_EN_LOW();
}

LED_Taillight_type_t lp5569_led_driver_get_mode(void)
{
	return g_led_taillight_status;
}

void lp5569_led_driver_set_mode(LED_Taillight_type_t mode)
{
	uint8_t tx[2] = {0x00, 0x00};
	int32_t ack = 0;
	uint16_t i = 0;
	led_driver_init();

	switch(mode)
	{
		/*LED Off*/
		case LED_TAILLIGHT_OFF:
			/*chip disable*/
			tx[0] = 0x00;	tx[1] = 0x00;
			ack = lp5569_write_reg(tx, 2);

			led_driver_deinit();
			g_led_taillight_status = LED_TAILLIGHT_OFF;
			break;
		case LED_TAILLIGHT_NIGHT_SOLID:
			/*Night Solid*/
			/*chip disable*/
			tx[0] = 0x00;	tx[1] = 0x00;
			ack = lp5569_write_reg(tx, 2);
		    
			/*chip enable*/
			tx[0] = 0x00;	tx[1] = 0x40;
			ack = lp5569_write_reg(tx, 2);

//			tx[0] = 0x01;	tx[1] = 0xA8;	// Free Run
			tx[0] = 0x01;	tx[1] = 0x00;	// Execution: Hold
			ack = lp5569_write_reg(tx, 2);
			
			/*MISC Register*/
			tx[0] = 0x2F;	tx[1] = 0x48;
			ack = lp5569_write_reg(tx, 2);
		    
			/*control*/
			tx[0] = 0x02;	tx[1] = 0x54;	// 1CH, 2CH, 3CH Load Program to SRAM
			ack = lp5569_write_reg(tx, 2);
		  
			/*LED0_PWM ~ LED8_PWM*/
			for(i=0;i<9;i++)
			{
				tx[0] = 0x16 + i;
				tx[1] = 80;					// 80 = 31% duty cycle	// 80h = 50% duty cycle
				ack = lp5569_write_reg(tx, 2);
			}

			g_led_taillight_status = LED_TAILLIGHT_NIGHT_SOLID;
			break;
		case LED_TAILLIGHT_NIGHT_FLASH:
			/*Night Flash*/
			/*chip disable*/
			tx[0] = 0x00;	tx[1] = 0x00;
			ack = lp5569_write_reg(tx, 2);
		    
			/*chip enable*/
			tx[0] = 0x00;	tx[1] = 0x40;
			ack = lp5569_write_reg(tx, 2);

			/*MISC Register*/
			tx[0] = 0x2F;	tx[1] = 0x49;	// Address auto-increment is enabled, 
											// Charge-pump mode selection 1× mode
											// Internal 32-kHz oscillator is enabled
			ack = lp5569_write_reg(tx, 2);

			/*control*/
			tx[0] = 0x02;	tx[1] = 0x80;	// 1CH Free Run
			ack = lp5569_write_reg(tx, 2);

			tx[0] = 0x01;	tx[1] = 0x80;	// 1CH Run Program
			ack = lp5569_write_reg(tx, 2);

			g_led_taillight_status = LED_TAILLIGHT_NIGHT_FLASH;
			break;
		case LED_TAILLIGHT_DAY_FLASH:
			/*Day Flash*/
			/*chip disable*/
			tx[0] = 0x00;	tx[1] = 0x00;
			ack = lp5569_write_reg(tx, 2);
		    
			/*chip enable*/
			tx[0] = 0x00;	tx[1] = 0x40;
			ack = lp5569_write_reg(tx, 2);
			
			/*MISC Register*/
			tx[0] = 0x2F;	tx[1] = 0x49;	// Address auto-increment is enabled, 
											// Charge-pump mode selection 1× mode
											// Internal 32-kHz oscillator is enabled
			ack = lp5569_write_reg(tx, 2);
			
			/*control*/
			tx[0] = 0x02;	tx[1] = 0x20;	// 2CH Free Run
			ack = lp5569_write_reg(tx, 2);	
			
			tx[0] = 0x01;	tx[1] = 0x20;	// 2CH Run Program
			ack = lp5569_write_reg(tx, 2);

			g_led_taillight_status = LED_TAILLIGHT_DAY_FLASH;
			break;
		case LED_TAILLIGHT_BREATHING:
			/*Night Flash*/
			/*chip disable*/
			tx[0] = 0x00;	tx[1] = 0x00;
			ack = lp5569_write_reg(tx, 2);
		    
			/*chip enable*/
			tx[0] = 0x00;	tx[1] = 0x40;
			ack = lp5569_write_reg(tx, 2);

			/*MISC Register*/
			tx[0] = 0x2F;	tx[1] = 0x49;	// Address auto-increment is enabled, 
											// Charge-pump mode selection 1× mode
											// Internal 32-kHz oscillator is enabled
			ack = lp5569_write_reg(tx, 2);

			/*control*/
			tx[0] = 0x02;	tx[1] = 0x80;	// 1CH Free Run
			ack = lp5569_write_reg(tx, 2);

			tx[0] = 0x01;	tx[1] = 0x80;	// 1CH Run Program
			ack = lp5569_write_reg(tx, 2);		
			g_led_taillight_status = LED_TAILLIGHT_BREATHING;
			break;
		
		case LED_TAILLIGHT_BURST_FLASH:
			/*Day Flash*/
			/*chip disable*/
			tx[0] = 0x00;	tx[1] = 0x00;
			ack = lp5569_write_reg(tx, 2);
		    
			/*chip enable*/
			tx[0] = 0x00;	tx[1] = 0x40;
			ack = lp5569_write_reg(tx, 2);
			
			/*MISC Register*/
			tx[0] = 0x2F;	tx[1] = 0x49;	// Address auto-increment is enabled, 
											// Charge-pump mode selection 1× mode
											// Internal 32-kHz oscillator is enabled
			ack = lp5569_write_reg(tx, 2);
			
			/*control*/
			tx[0] = 0x02;	tx[1] = 0x20;	// 2CH Free Run
			ack = lp5569_write_reg(tx, 2);	
			
			tx[0] = 0x01;	tx[1] = 0x20;	// 2CH Run Program
			ack = lp5569_write_reg(tx, 2);		
			g_led_taillight_status = LED_TAILLIGHT_BURST_FLASH;
			break;

		case LED_TAILLIGHT_FAST_FLASH:
			/*Day Flash*/
			/*chip disable*/
			tx[0] = 0x00;	tx[1] = 0x00;
			ack = lp5569_write_reg(tx, 2);
		    
			/*chip enable*/
			tx[0] = 0x00;	tx[1] = 0x40;
			ack = lp5569_write_reg(tx, 2);
			
			/*MISC Register*/
			tx[0] = 0x2F;	tx[1] = 0x49;	// Address auto-increment is enabled, 
											// Charge-pump mode selection 1× mode
											// Internal 32-kHz oscillator is enabled
			ack = lp5569_write_reg(tx, 2);
			
			/*control*/
			tx[0] = 0x02;	tx[1] = 0x08;	// 3CH Free Run
			ack = lp5569_write_reg(tx, 2);	
			
			tx[0] = 0x01;	tx[1] = 0x08;	// 3CH Run Program
			ack = lp5569_write_reg(tx, 2);		
			g_led_taillight_status = LED_TAILLIGHT_FAST_FLASH;
			break;	
		default:
			break;
	}
}

LED_Taillight_type_t lp5569_led_driver_change_mode(void)
{
	if(lp5569_led_driver_get_mode() == LED_TAILLIGHT_OFF)
	{
		lp5569_led_driver_set_mode(LED_TAILLIGHT_NIGHT_SOLID);
		return LED_TAILLIGHT_NIGHT_SOLID;
	}
	else if(lp5569_led_driver_get_mode() == LED_TAILLIGHT_NIGHT_SOLID)
	{
		lp5569_led_driver_set_mode(LED_TAILLIGHT_NIGHT_FLASH);
		return LED_TAILLIGHT_NIGHT_FLASH;
	}
	else if(lp5569_led_driver_get_mode() == LED_TAILLIGHT_NIGHT_FLASH)
	{
		lp5569_led_driver_set_mode(LED_TAILLIGHT_DAY_FLASH);
		return LED_TAILLIGHT_DAY_FLASH;
	}
	else if(lp5569_led_driver_get_mode() >= LED_TAILLIGHT_DAY_FLASH)
	{
		lp5569_led_driver_set_mode(LED_TAILLIGHT_OFF);
		return LED_TAILLIGHT_OFF;
	}

	lp5569_led_driver_set_mode(LED_TAILLIGHT_OFF);
	return LED_TAILLIGHT_OFF;
}

bsp_led_function_t lp5569_led_func = {
	lp5569_led_driver_get_mode, 
	lp5569_led_driver_set_mode, 
	lp5569_led_driver_change_mode,
};

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
