/*
 * sm72442.c
 *
 * Created: 21.4.2020 11:35:27
 *  Author: Martin Košút
 */ 

#include <stdio.h>
#include <stdlib.h>         // itoa() function
#include <stdbool.h>
#include <avr/io.h>
#include "sm72442.h"
#include "twi.h"
#include "uart.h"

	

uint8_t i2c_buffer[8];

uint8_t MPPT_read_register(uint8_t MPPTreg)					//read register from MPPT SM72442
{
	uint8_t status;
	
	status = twi_start((MPPT_address<<1) + TWI_WRITE);		//start i2c communication and write address of register which we want to read
	if(status == 0)
	{
		twi_write(MPPTreg);
	}
	twi_stop();
	status = twi_start((MPPT_address<<1) + TWI_READ);		//read and store 7 bytes of register
	if(status == 0)
	{
		for(int i = 0; i < 7; i++)
		{
			i2c_buffer[i] = twi_read_ack();
		}
		i2c_buffer[7] = twi_read_nack();
	}
	twi_stop();
	if (status == 0)										//parse received data from register
	{
		parse_data(MPPTreg);
		return 0;											//return 0 if I2C transmission was successful
	}
	
	/*uint8_t uart_string[10];
	for (int i = 0; i < 8; i++)
	{
		itoa(i2c_buffer[i], uart_string, 16);
		uart_puts("\r\n");
		uart_puts(uart_string);
	}
	*/
	return 1;												//return 1 if I2C crashed somewhere or SM72442 reported NAK
}

void parse_data(uint8_t MPPTreg)							//parse received or send data in buffer
{															//order of bits from SM72442 (little-endian) 7-0, 15-8, 23-16, 31-24, 39-32, 47-40, 55-48
	float V_pin;
	switch (MPPTreg)
	{
		case MPPT_reg0:										//ADC channels info													
			MPPT.ADC0_V_out_max = (((i2c_buffer[2] & 0x03) << 8) | i2c_buffer[1]) * ((float)V_REF / 1023);						//1st 10 bits of message, 7-0, 9-8
			MPPT.set_V_out_max = MPPT.ADC0_V_out_max * (((float)R_FB1 + (float)R_FB2) / (float)R_FB2);							//calculate set_V_out_max from ADC0 voltage
			
			MPPT.ADC2_Operating_mode = (((i2c_buffer[3] & 0x0F) << 6) | ((i2c_buffer[2] & 0xFC) >> 2)) * ((float)V_REF / 1023);	//2nd 10 bits of message, 10-15, 16-19
			
			MPPT.ADC4_I_out_max = (((i2c_buffer[4] & 0x3F) << 4) | ((i2c_buffer[3] & 0xF0) >> 4)) * ((float)V_REF / 1023);		//3rd 10 bits of message, 20-23, 24-29
			MPPT.set_I_out_max = (MPPT.ADC4_I_out_max * (float)R_SIB) / ((float)R_IOUT * (float)R_SH);							//calculate set_I_out_max from ADC4 voltage
			
			MPPT.ADC6_Slew_rate = ((i2c_buffer[5] << 2) | ((i2c_buffer[4] & 0xC0) >> 6)) * ((float)V_REF / 1023);				//4th 10 bits of message, 30-31, 32-39
			break;
		case MPPT_reg1:										//input and output voltage and current values
			V_pin = (((i2c_buffer[2] & 0x03) << 8) | i2c_buffer[1]) * ((float)V_REF / 1023);									//1st 10 bits of message, 7-0, 9-8
			MPPT.I_in = (V_pin * (float)R_SIA) / ((float)R_IIN * (float)R_SH);													//calculate current I_in from AIIN voltage
			
			V_pin = (((i2c_buffer[3] & 0x0F) << 6) | ((i2c_buffer[2] & 0xFC) >> 2)) * ((float)V_REF / 1023);					//2nd 10 bits of message, 10-15, 16-19
			MPPT.V_in = (V_pin * ((float)R_IN1 + (float)R_IN2)) / (float)R_IN2;													//calculate current V_in from AVIN voltage
			
			V_pin = (((i2c_buffer[4] & 0x3F) << 4) | ((i2c_buffer[3] & 0xF0) >> 4)) * ((float)V_REF / 1023);					//3rd 10 bits of message, 20-23, 24-29
			MPPT.I_out = (V_pin * (float)R_SIB) / ((float)R_IOUT * (float)R_SH);												//calculate current I_out from AIOUT voltage
			
			V_pin = ((i2c_buffer[5] << 2) | ((i2c_buffer[4] & 0xC0) >> 6)) * ((float)V_REF / 1023);								//4th 10 bits of message, 30-31, 32-39
			MPPT.V_out = (V_pin * ((float)R_FB2 + (float)R_FB1)) / (float)R_FB2;												//calculate V_out from AVOUT voltage
			break;
		case MPPT_reg3:										//configuration parameters
			MPPT.dead_time_ON = ((i2c_buffer[3] & 0x01) << 2) | ((i2c_buffer[2] & 0xC0) >> 6);									//14-15,16
			MPPT.dead_time_OFF = ((i2c_buffer[3] & 0x0E) >> 1);																	//17-19
			MPPT.Override_V_out_max = (((i2c_buffer[4] & 0x3F) << 4) | ((i2c_buffer[3] & 0xF0) >> 4)) * ((float)V_REF / 1023);	//20-23, 24-29
			MPPT.Override_I_out_max = ((i2c_buffer[5] << 2) | ((i2c_buffer[4] & 0xC0) >> 6)) * ((float)V_REF / 1023);			//30-31, 32-39
			
			if(((i2c_buffer[6] & 0x40) >> 6) == 1)			//check if ADC override is active
			{
				MPPT.Override_active = true;
				MPPT.set_V_out_max = MPPT.Override_V_out_max * (((float)R_FB1 + (float)R_FB2) / (float)R_FB2);					//calculate set_V_out_max from override voltage
				MPPT.set_I_out_max = (MPPT.Override_I_out_max * (float)R_SIB) / ((float)R_IOUT * (float)R_SH);					//calculate set_I_out_max from override current
			}
			else
			{
				MPPT.Override_active = false;
				MPPT.set_V_out_max = 0;
				MPPT.set_I_out_max = 0;
			}
			break;
		case MPPT_reg4:										//current and voltage offsets (not used)
		
			break;
		case MPPT_reg5:										//current threshold to start in MPPT (not used)
			
			break;
	}
} 

uint8_t MPPT_set_parameters(float set_V_out, float set_I_out, uint8_t dead_time_ON, uint8_t dead_time_OFF, bool override)	//set V_out, I_out, dead ON,OFF time (e.g. MPPT_set_parameters(16.6, 1, 0x03, 0x03, true);)
{												
	uint8_t status;
	uint16_t V_out, I_out;
	
	if(override == true)																				//order of bits from SM72442 (little-endian) 7-0, 15-8, 23-16, 31-24, 39-32, 47-40, 55-48
	{
		V_out = (set_V_out / (((float)R_FB1 + (float)R_FB2) / (float)R_FB2)) / ((float)V_REF / 1023);	//calculate V_out 10bit digital value from input parameter
		I_out = ((set_I_out * (float)R_IOUT * (float)R_SH) / (float)R_SIB) / ((float)V_REF / 1023);		//calculate I_out 10bit digital value from input parameter
		
		i2c_buffer[0] = 0x07;
		i2c_buffer[1] = 0xe0;
		i2c_buffer[2] = ((dead_time_ON & 0x03) << 6) | 0x3f;											//dead_time_ON 15-14, other bits to reset value
		i2c_buffer[3] = ((V_out & 0x000F) << 4) | ((dead_time_OFF & 0x07) << 1) | ((dead_time_ON & 0x04) >> 2);	//V_out 23-20, dead_time_OFF 19-17, dead_time_ON 16
		i2c_buffer[4] = ((I_out & 0x0003) << 6) | ((V_out & 0x03F0) >> 4) ;								//I_out 31-30, V_out 29-24
		i2c_buffer[5] = ((I_out & 0x03FC) >> 2);														//I_out 39-32
		i2c_buffer[6] = (override << 6) | 0x08;															//override 46
		i2c_buffer[7] = 0;
	}
	else
	{															//default data in reg3 after RESET if OVERRIDE is false
		i2c_buffer[0]=0x07;
		i2c_buffer[1]=0xe0;
		i2c_buffer[2]=0xdf;
		i2c_buffer[3]=0xf6;
		i2c_buffer[4]=0xff;
		i2c_buffer[5]=0xff;
		i2c_buffer[6]=0x08;
		i2c_buffer[7]=0;
	}
	
	status = twi_start((MPPT_address<<1) + TWI_WRITE);			//start i2c communication + send address of reg3
	if(status == 0)
	{
		twi_write(MPPT_reg3);
		for(int i = 0; i < 8; i++)								//send i2c_buffer
		{
			twi_write(i2c_buffer[i]);
		}
		twi_stop();
	}
	if (status == 0)											//after send parse send data
	{
		parse_data(MPPT_reg3);
		return 0;												//return 0 if I2C transmission was successful
	}
	return 1;													//return 1 if I2C crashed somewhere or SM72442 reported NAK
}
