/**
 * rgb_led.c
 *
 * Low level control of the AWINIC AW2033 RGB LED over I2C.
 * 
 * Copyright (c) 2022 Bigscreen, Inc.
 */

#include "asf.h"
#include "rgb_led.h"
#include <string.h>

RGB_Color_t currently_set_color = {.r = 0, .b = 0, .g = 0};
uint8_t current_dimming_value = 0x80; // Max is 0x80 = full brightness

static uint8_t compute_dimmed_color(uint8_t color, uint8_t dim) {
	uint16_t temp = (uint16_t) color;
	temp = temp * ((uint16_t)dim);
	return (uint8_t) (temp >> 7);
}

void rgb_led_init(I2C_Handle* hi2c) {
	I2C_Transaction_Request i2ctxn;
	uint8_t dummy_byte;
	// Initialize AW2033 chip
	
	i2ctxn.cb = NULL; // no callback needed

	i2ctxn.dev_addr = RGB_LED_I2C_ADDR;
	i2ctxn.shift = I2C_Unshifted;
	i2ctxn.len = 1;
	i2ctxn.data = &dummy_byte;
	
	i2c_lock(hi2c);
	
	// Apply reset
	dummy_byte = RGB_RESET_CODE;
	i2ctxn.internal_addr = RGB_RESET_REG;
	i2ctxn.ttype = I2C_INT_ADDR_WRITE;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);

	// Enable chip and disable the auto-charge feature
	dummy_byte = RGB_GCR1_CHIPEN + RGB_GCR1_CHRGDIS;
	i2ctxn.internal_addr = RGB_GCR1_REG;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
	
	// Set global maximum current (30mA)
	dummy_byte = RGB_GCR2_IMAX_30MA;
	i2ctxn.internal_addr = RGB_GCR2_REG;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
	
	// Enable LED outputs
	dummy_byte = RGB_LCTR_LED0_EN + RGB_LCTR_LED1_EN + RGB_LCTR_LED2_EN;
	i2ctxn.internal_addr = RGB_LCTR_REG;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
	
	// Set LED0 max current
	dummy_byte = RGB_LCFGX_CUR_MAX;
	i2ctxn.internal_addr = RGB_LCFG0_REG;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
	
	// Set LED1 max current
	dummy_byte = RGB_LCFGX_CUR_MAX;
	i2ctxn.internal_addr = RGB_LCFG1_REG;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
	
	// Set LED2 max current
	dummy_byte = RGB_LCFGX_CUR_MAX;
	i2ctxn.internal_addr = RGB_LCFG2_REG;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
	
	i2c_unlock(hi2c);
}

static void rgb_led_set_output(I2C_Handle* hi2c, const RGB_Color_t* color) {
	uint8_t dummy_byte;
	I2C_Transaction_Request i2ctxn;
	
	i2c_lock(hi2c);
	i2ctxn.cb = NULL;
	i2ctxn.dev_addr = RGB_LED_I2C_ADDR;
	i2ctxn.shift = I2C_Unshifted;
	i2ctxn.len = 1;
	i2ctxn.data = &dummy_byte;
	
	i2ctxn.internal_addr = RGB_PWM0_REG;
	i2ctxn.ttype = I2C_INT_ADDR_WRITE;
	dummy_byte = color->r;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
	
	// For some reason red doesn't play nice. Do it again
	i2ctxn.internal_addr = RGB_PWM0_REG;
	dummy_byte = color->r;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
	
	// Third time's the charm?
	i2ctxn.internal_addr = RGB_PWM0_REG;
	dummy_byte = color->r;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
	
	i2ctxn.internal_addr = RGB_PWM1_REG;
	dummy_byte = color->g;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
	
	i2ctxn.internal_addr = RGB_PWM2_REG;
	dummy_byte = color->b;
	i2c_transact_blocking(hi2c, &i2ctxn, DEFAULT_I2C_WAIT_TIME);
				
	i2c_unlock(hi2c);
}

void rgb_led_set_color(I2C_Handle* hi2c, const RGB_Color_t* color) {
	memcpy(&currently_set_color, color, sizeof(RGB_Color_t));
	
	rgb_led_set_dimming(hi2c, current_dimming_value);
}

void rgb_led_set_dimming(I2C_Handle* hi2c, uint8_t dimval) {
	if(dimval > 0x80) dimval = 0x80; // maximum at 0x80 = full brightness
	current_dimming_value = dimval;
	RGB_Color_t temp_color;
#if 1
	temp_color.r = compute_dimmed_color(currently_set_color.r, dimval);
	temp_color.g = compute_dimmed_color(currently_set_color.g, dimval);
	temp_color.b = compute_dimmed_color(currently_set_color.b, dimval);
#else
	temp_color.r = 0xFF;
	temp_color.g = 0x00;
	temp_color.b = 0xFF;
#endif
	
	rgb_led_set_output(hi2c, &temp_color);
	
}
