/*******************************************************************************
 * @file	mcp4725_i2c.c
 * @author	CandyPops Co.
 * @version	V1.0.0
 * @date	2022-09-05
 * @brief   
 ******************************************************************************/

/* board driver */
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#include <stdbool.h>
#include <math.h> 
#include "nrf.h"
#include "app_error.h"
#include "boards.h"
#include "nrfx_gpiote.h"

#include "mcp4725_i2c.h"
#include "nrf_delay.h"
#include "debug_print.h"

/* I2C number and slave address for MCP4725 */
#define MCP4725_I2C_ADDR_7bit     0x66
uint8_t MCP4725_I2C_ADDR = MCP4725_I2C_ADDR_7bit << 1;

uint16_t _lastValue;
uint8_t  _powerDownMode;
uint32_t _lastWriteEEPROM;


void mcp4725_i2c_initialize(void)
{
	SCL_OUT();
	SDA_OUT();
	SCL_H();
	SDA_H();
}


static uint8_t mcp4725_i2c_write(uint8_t data)
{
	for(uint8_t i = 0; i < 8; i++)
	{
		// MSB first
		if(data & 0x80) SDA_H();
		else SDA_L();
		i2c_clock();
		data = data << 1;
	}

	// read ACK
	SDA_H();						// leave SDA HI
	SDA_IN();						// change direction to input on SDA line

	i2c_delay();
	SCL_H();						// clock back up
	i2c_delay();
	uint8_t ack = SDA_READ();		// get the ACK bit
	SCL_L();

	SDA_OUT();						// change direction back to output

	if(ack) {
		DBG_PRINTF("ACK Extra=%d,Data=%d\r\n", ack,data);
	}

	return ack;
}


static uint8_t mcp4725_i2c_read(bool ack)
{
	uint8_t	data;

	SDA_H();						// leave SDA HI
	SDA_IN();						// change direction to input on SDA line

	data = 0;
	for(uint8_t i = 0; i < 8; i++)
	{
		// MSB first
		data = data << 1;

		SCL_H();
		do{
		}while(SCL_READ() != 0);	// Wait for any SCL clock stratching

		i2c_delay();
		if(SDA_READ())				// get the Data bit
			data |= 1;
		else
			data |= 0;
		SCL_L();					// clock LO
		i2c_delay();
	}

	SDA_OUT();						// change direction back to output

	// send ACK
	if(ack == ACK) SDA_L();
	else if(ack == NACK) SDA_H();
	i2c_clock();
	SDA_H();						// leave with SDA HI

	return data;
}


void mcp4725_writeFastMode(const uint16_t value)
{
	uint8_t low = value & 0xFF;
	uint8_t high = ((value >> 8) & 0x0F);  			// set C2,c1 == 0,0(FastMode Write)    pd1,pd0 == 0,0 (Normal Mode)

	i2c_start();
	mcp4725_i2c_write(MCP4725_I2C_ADDR|TWI_WRITE);		// slave address
	
	//uint8_t address = MCP4725_I2C_ADDR | TWI_WRITE;
	//DBG_PRINTF("[I2C] Write to 0x%02X\r\n", address);  //oxCC 
	
	mcp4725_i2c_write(high);							// value1 ~ 3
	mcp4725_i2c_write(low);
	i2c_stop();
}


void mcp4725_generalCall(const uint8_t gc)
{
	i2c_start();
	mcp4725_i2c_write(0x00);	  						// First Byte 0x00
	mcp4725_i2c_write(gc);	  							// Second Byte, General Call Reset = 0x06, General Call Wake-Up = 0x09
	i2c_stop();
}


void mcp4725_init(void)
{
	mcp4725_i2c_initialize();
}

// DAC value is reset to EEPROM value
// need to reflect this in cached value
void mcp4725_powerOnReset(void)
{
	mcp4725_generalCall(MCP4725_GC_RESET);
}


// _powerDownMode DAC resets to 0 -- PDM EEPROM stays same !!!
// need to reflect this in cached value
void mcp4725_powerOnWakeUp(void)
{
	mcp4725_generalCall(MCP4725_GC_WAKEUP);
}

/* 현재 DAC값 읽어서 그 값에 Power Down 넣고 Write */
void mcp4725_PowerDownMode(void)
{
	uint8_t low = 0x00; //read_value & 0xFF;
	uint8_t high = 0x00; //((read_value >> 8) & 0x0F);
	high = high | (MCP4725_PDMODE_1K << 4);			// set C2,c1 == 0,0(FastMode Write)    pd1,pd0 == 0,1 (Power Down Mode, 1Kohm to GND)

	i2c_start();
	mcp4725_i2c_write(MCP4725_I2C_ADDR|TWI_WRITE);		// slave address
	mcp4725_i2c_write(high);							// value
	mcp4725_i2c_write(low);
	i2c_stop();
}

////////////////////////////////////////////////////////////////////////////////

uint16_t mcp4725_readDAC(void)
{
	while(!mcp4725_ready());
	uint8_t buffer[3];
	mcp4725_readRegister(buffer, 3);
	uint16_t value = buffer[1];
	value = value << 4;
	value = value + (buffer[2] >> 4);
	return value;
}


// ready checks if the last write to EEPROM has been written.
// until ready all writes to the MCP4725 are ignored!
bool mcp4725_ready(void)
{
	uint8_t buffer[1];
	mcp4725_readRegister(buffer, 1);
	return ((buffer[0] & 0x80) > 0);
}


void mcp4725_writeRegisterMode(const uint16_t value, uint8_t reg)
{
	uint8_t high = (value / 16);
	uint8_t low = (value & 0x0F) << 4;
	reg = reg | (_powerDownMode << 1);

	i2c_start();
	mcp4725_i2c_write(MCP4725_I2C_ADDR|TWI_WRITE);		// slave address
	mcp4725_i2c_write(reg);								// configuration
	mcp4725_i2c_write(high);							// value1 ~ 3
	mcp4725_i2c_write(low);
	i2c_stop();
}


void mcp4725_readRegister(uint8_t* buffer, const uint8_t length)
{
	i2c_start();
	mcp4725_i2c_write(MCP4725_I2C_ADDR|TWI_READ);		// slave address with READ
	switch(length) {
		case 1:
			buffer[0] = mcp4725_i2c_read(NACK);			// NACK, SDA = 1;
			break;

		case 2:
			buffer[0] = mcp4725_i2c_read(ACK);			// ACK, SDA = 0;
			buffer[1] = mcp4725_i2c_read(NACK);			// NACK, SDA = 1;
			break;

		case 3:
			buffer[0] = mcp4725_i2c_read(ACK);			// ACK, SDA = 0;
			buffer[1] = mcp4725_i2c_read(ACK);			// ACK, SDA = 0;
			buffer[2] = mcp4725_i2c_read(NACK); 		// NACK, SDA = 1;
			break;

		case 4:
			buffer[0] = mcp4725_i2c_read(ACK);			// ACK, SDA = 0;
			buffer[1] = mcp4725_i2c_read(ACK);			// ACK, SDA = 0;
			buffer[2] = mcp4725_i2c_read(ACK);			// ACK, SDA = 0;
			buffer[3] = mcp4725_i2c_read(NACK); 		// NACK, SDA = 1;
			break;

		case 5:
			buffer[0] = mcp4725_i2c_read(ACK);			// ACK, SDA = 0;
			buffer[1] = mcp4725_i2c_read(ACK);			// ACK, SDA = 0;
			buffer[2] = mcp4725_i2c_read(ACK);			// ACK, SDA = 0;
			buffer[3] = mcp4725_i2c_read(ACK);			// ACK, SDA = 0;
			buffer[4] = mcp4725_i2c_read(NACK); 		// NACK, SDA = 1;
			break;

		default:
#if FEATURE_PRINTF
			DBG_PRINTF("ERR!! mcp4725_i2c_readregister\r\n");
#endif
			break;
	}
	
	i2c_stop();

}


void mcp4725_setValue(const uint16_t value)
{
	if (value == _lastValue) return;
	if (value > MCP4725_MAXVALUE) return;
	mcp4725_writeFastMode(value);
	_lastValue = value;
}


uint16_t mcp4725_getValue(void)
{
	return _lastValue;
}


void mcp4725_setPercentage(float percentage)
{
	if ((percentage > 100) || (percentage < 0)) 
		DBG_PRINTF("ERR!!! mcp4725 percentage error\r\n");
	mcp4725_setValue(round(percentage * (0.01 * MCP4725_MAXVALUE)));
}


// unfortunately it is not possible to write a different value
// to the DAC and EEPROM simultaneously or write EEPROM only.
void mcp4725_writeDAC(const uint16_t value, const bool EEPROM)
{
	if (value > MCP4725_MAXVALUE) 
#if FEATURE_PRINTF
		DBG_PRINTF("ERR!!! mcp4725 writeDAC error\r\n");
#endif
	while(!mcp4725_ready());
	mcp4725_writeRegisterMode(value, EEPROM ? MCP4725_DACEEPROM : MCP4725_DAC);
	_lastValue = value;
}


uint16_t mcp4725_readEEPROM(void)
{
	while(!mcp4725_ready());
	uint8_t buffer[5];
	mcp4725_readRegister(buffer, 5);
	uint16_t value = buffer[3] & 0x0F;
	value = value << 8;
	value = value + buffer[4];
	return value;
}


// depending on bool EEPROM the value of PDM is written to
// (false) DAC or
// (true) DAC & EEPROM,
void mcp4725_writePowerDownMode(const uint8_t PDM, const bool EEPROM)
{
	_powerDownMode = (PDM & 0x03); // mask PDM bits only (written later low level)
	
	_lastValue = mcp4725_readDAC();
	_powerDownMode = mcp4725_readPowerDownModeDAC();
	mcp4725_writeDAC(_lastValue, EEPROM);
}


uint8_t mcp4725_readPowerDownModeEEPROM(void)
{
	while(!mcp4725_ready());
	uint8_t buffer[4];
	mcp4725_readRegister(buffer, 4);
	uint8_t value = (buffer[3] >> 5) & 0x03;
	return value;
}


uint8_t mcp4725_readPowerDownModeDAC(void)
{
	while(!mcp4725_ready());  // TODO needed?
	uint8_t buffer[1];
	mcp4725_readRegister(buffer, 1);
	uint8_t value = (buffer[0] >> 1) & 0x03;
	return value;
}







void ds_i2c_start(void) {
      SDA_H();//nrf_gpio_pin_set(I2C_SDA_PIN);
      SCL_H();//nrf_gpio_pin_set(I2C_SCL_PIN);
    i2c_delay();//nrf_delay_us(I2C_DELAY_US);
    SDA_L();//nrf_gpio_pin_clear(I2C_SDA_PIN);
    i2c_delay();//nrf_delay_us(I2C_DELAY_US);
		SCL_L();//nrf_gpio_pin_clear(I2C_SCL_PIN);
		i2c_delay();//nrf_delay_us(I2C_DELAY_US);
}

void ds_i2c_stop(void) {
		i2c_delay();//nrf_delay_us(I2C_DELAY_US);
    SDA_L();//nrf_gpio_pin_clear(I2C_SDA_PIN);
    SCL_H();// nrf_gpio_pin_set(I2C_SCL_PIN);
    i2c_delay();//nrf_delay_us(I2C_DELAY_US);
    SDA_H();//nrf_gpio_pin_set(I2C_SDA_PIN);
    i2c_delay();//nrf_delay_us(I2C_DELAY_US);
}













void i2c_write_bit(uint8_t bit) {
    if (bit) {
        SDA_H();
    } else {
        SDA_L();
    }
    i2c_delay();//nrf_delay_us(I2C_DELAY_US);
    SCL_H(); //nrf_gpio_pin_set(SCL_PIN);
     i2c_delay();//nrf_delay_us(I2C_DELAY_US);
    SCL_L();//nrf_gpio_pin_clear(SCL_PIN);
}

uint8_t i2c_read_bit(void) {
    uint8_t bit;
    SDA_IN();//nrf_gpio_cfg_input(SDA_PIN, NRF_GPIO_PIN_NOPULL);
    i2c_delay();//nrf_delay_us(I2C_DELAY_US);
    SCL_H(); ////nrf_gpio_pin_set(SCL_PIN);
    i2c_delay();//nrf_delay_us(I2C_DELAY_US);
    bit = SDA_READ();//nrf_gpio_pin_read(SDA_PIN);
    SCL_L(); //nrf_gpio_pin_clear(SCL_PIN);
    SDA_OUT();//nrf_gpio_cfg_output(SDA_PIN);
    return bit;
}
uint8_t i2c_write_byte(uint8_t byte) {
    for (uint8_t i = 0; i < 8; i++) {
        i2c_write_bit(byte & 0x80);
        byte <<= 1;
    }
    return i2c_read_bit(); // Read ACK/NACK
}

uint8_t i2c_read_byte(uint8_t ack) {
    uint8_t byte = 0;
     SDA_IN();//nrf_gpio_cfg_input(SDA_PIN, NRF_GPIO_PIN_NOPULL);
    for (uint8_t i = 0; i < 8; i++) {
        byte <<= 1;
        byte |= i2c_read_bit();
    }
    SDA_OUT();//nrf_gpio_cfg_output(SDA_PIN);
    i2c_write_bit(!ack); // Send ACK/NACK
    return byte;
}
void i2c_repeated_start(void) {
    SDA_H();//nrf_gpio_pin_set(SDA_PIN);
    SCL_H();//nrf_gpio_pin_set(SCL_PIN);
    i2c_delay();//nrf_delay_us(I2C_DELAY_US);
    SDA_L();////nrf_gpio_pin_clear(SDA_PIN);
    i2c_delay();//nrf_delay_us(I2C_DELAY_US);
    SCL_L();//nrf_gpio_pin_clear(SCL_PIN);
}

//    i2c_start();
//    i2c_write_byte(I2C_ADDRESS << 1); // Write address
//    i2c_write_byte(0x00); // Register address
//    i2c_write_byte(0xFF); // Data
//    i2c_stop();

//    // Read example
//    i2c_start();
//    i2c_write_byte((I2C_ADDRESS << 1) | 1); // Read address
//    uint8_t data = i2c_read_byte(0); // Read data with NACK
//    i2c_stop();


void DS3930_write(uint8_t id, uint8_t addr, uint8_t wdata)
{	
//i2c_start();
//		ds_i2c_stop();
	ds_i2c_start();
		i2c_write_byte(id << 1); // Write address
    i2c_write_byte(addr); // Register address
    i2c_write_byte(wdata); // Data
	
//	mcp4725_i2c_write(id << 1);
//	mcp4725_i2c_write(addr);
//	mcp4725_i2c_write(wdata);
//	
//	}
//i2c_delay();
//i2c_stop();
	ds_i2c_stop();
}	



uint8_t DS3930_read(uint8_t id, uint8_t addr, uint8_t* rdata)
{
		ds_i2c_start();
		i2c_write_byte(id << 1); // Write address
    i2c_write_byte(addr); // Register address
		i2c_repeated_start();
    i2c_write_byte((id << 1) | 1); // Read address
    uint8_t data = i2c_read_byte(0); // Read data with NACK
    ds_i2c_stop();
		rdata[0] = data;
		DBG_PRINTF("Data 0x%x  . \r\n", data);
	//i2c_stop();
   return data;
}




//void CAT24_write(uint8_t id, uint8_t addr, uint8_t* wdata)
//{	
////i2c_start();
////		ds_i2c_stop();
//	ds_i2c_start();
//		i2c_write_byte(id << 1); // Write address
//    i2c_write_byte(addr); // Register address
//    i2c_write_byte(wdata); // Data
//	
////	mcp4725_i2c_write(id << 1);
////	mcp4725_i2c_write(addr);
////	mcp4725_i2c_write(wdata);
////	
////	}
////i2c_delay();
////i2c_stop();
//	ds_i2c_stop();
//}


//uint8_t CAT24_read(uint8_t id, uint8_t addr, uint8_t* rdata,uint8_t length)
//{
//		ds_i2c_start();
//		i2c_write_byte(id << 1); // Write address
//    i2c_write_byte(addr); // Register address
//		i2c_repeated_start();
//    i2c_write_byte((id << 1) | 1); // Read address
//    uint8_t data = i2c_read_byte(0); // Read data with NACK
//    ds_i2c_stop();
//		rdata[0] = data;
//		DBG_PRINTF("Data 0x%x  . \r\n", data);
//	//i2c_stop();
//   return data;
//}

