#include "TCS34725.h"

tcs34725IntegrationTime_t _tcs34725IntegrationTime;
tcs34725Gain_t _tcs34725Gain;

uint8_t TCS34725_I2C_Read(uint8_t addr, uint8_t reg)
{
    uint8_t TCS34725_I2C[3]={0,};
    uint16_t value = 0;
    uint8_t data = 0;
    data=HAL_I2C_Mem_Read(&hi2c1, addr, reg, 1, TCS34725_I2C, 1, 10);
//    i2c_status(data);
    value = TCS34725_I2C[0];

    return value;
}


void TCS34725_I2C_Write(uint8_t addr, uint8_t reg, uint8_t data)
{
    uint8_t tmp_afe;
    tmp_afe = data;

    HAL_I2C_Mem_Write(&hi2c1, addr, reg, 1, &tmp_afe, 1, 10);
}

  /**************************************************************************/
  /*!
	  Adjusts the gain on the TCS34725 (adjusts the sensitivity to light)
  */
  /**************************************************************************/
void TCS34725_getrawdata(void)
{

    uint8_t data_ret_R =0;
    uint8_t data_ret_G =0;
    uint8_t data_ret_B =0;
    uint8_t data_ret_C =0;

    uint8_t DEV_DATA = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT |  TCS34725_ID);
    uint8_t C_DATA_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT |  TCS34725_CDATAL);
    uint8_t C_DATA_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT |  TCS34725_CDATAH);
    uint8_t R_DATA_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT |  TCS34725_RDATAL);
    uint8_t R_DATA_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT |  TCS34725_RDATAH);
    uint8_t G_DATA_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT |  TCS34725_GDATAL);
    uint8_t G_DATA_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT |  TCS34725_GDATAH);
    uint8_t B_DATA_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT |  TCS34725_BDATAL);
    uint8_t B_DATA_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT |  TCS34725_BDATAH);

    printf("C_DATA_L : %02x C_DATA_H %02x \r\n",C_DATA_L,C_DATA_H);

    printf("R_DATA_L : %02x R_DATA_H %02x \r\n",R_DATA_L,R_DATA_H);

    printf("G_DATA_L : %02x G_DATA_H %02x \r\n",G_DATA_L,G_DATA_H);

    printf("B_DATA_L : %02x B_DATA_H %02x \r\n",B_DATA_L,B_DATA_H);
#if 0
    double CLEAR = 0;
    double RED   = 0;
    double GREEN = 0;
    double BLUE  = 0;

    printf("************************************\r\n");
    printf("1. DEV ID\t:\t%x\r\n",	DEV_DATA);
    CLEAR = (C_DATA_H << 8) | C_DATA_L;
    data_ret_C = (CLEAR / 65535)*255;
    printf("CLEAR : %d\r\n",data_ret_C);
    RED   = (R_DATA_H << 8) | R_DATA_L;
    data_ret_R = (RED / 65535)*255;

    printf("RED : %d\r\n",data_ret_R);
    GREEN = (G_DATA_H << 8) | G_DATA_L;
    data_ret_G = (GREEN / 65535)*255;

    printf("GREEN : %d\r\n",data_ret_G);
    BLUE  = (B_DATA_H << 8) | B_DATA_L;
    data_ret_B = (BLUE / 65535)*255;

    printf("BLUE : %d\r\n",data_ret_B);
//#else
    double CLEAR = 0;
    double RED   = 0;
    double GREEN = 0;
    double BLUE  = 0;


    CLEAR = (C_DATA_H << 8) | C_DATA_L;
    data_ret_C = (CLEAR / 65535)*255;
    RED   = (R_DATA_H << 8) | R_DATA_L;
    data_ret_R = (RED / 65535)*255;

    GREEN = (G_DATA_H << 8) | G_DATA_L;
    data_ret_G = (GREEN / 65535)*255;

    BLUE  = (B_DATA_H << 8) | B_DATA_L;
    data_ret_B = (BLUE / 65535)*255;
#if 0
    printf("02%04x%05d%04x%05d%04x%05d%04x%05d03\r\n",data_ret_C,data_ret_C,data_ret_R,data_ret_R,data_ret_G,data_ret_G,data_ret_B,data_ret_B);
#else
//    printf("%04x,%05d,%04x,%05d,%04x,%05d,%04x,%05d,\r\n",data_ret_C,data_ret_C,data_ret_R,data_ret_R,data_ret_G,data_ret_G,data_ret_B,data_ret_B);
    printf("%x %d %d %d %d %d %d %d %d\r\n",DEV_DATA,(uint16_t)CLEAR,data_ret_C,(uint16_t)RED,data_ret_R,(uint16_t)GREEN,data_ret_G,(uint16_t)BLUE,data_ret_B);

#endif
#endif
#if 0
    uint16_t CLEAR = 0;
    uint16_t RED   = 0;
    uint16_t GREEN = 0;
    uint16_t BLUE  = 0;

    CLEAR = (C_DATA_H << 8) | C_DATA_L;
    RED   = (R_DATA_H << 8) | R_DATA_L;
    GREEN = (G_DATA_H << 8) | G_DATA_L;
    BLUE  = (B_DATA_H << 8) | B_DATA_L;

    printf("1. DEV ID\t:\t%x\r\n",	DEV_DATA);
    printf("3. C\t:\tHEX	: [%04x]\tDEC  : [%05d]\r\n",	CLEAR,CLEAR);
    printf("4. R\t:\tHEX	: [%04x]\tDEC  : [%05d]\r\n",	RED,RED);
    printf("5. G\t:\tHEX	: [%04x]\tDEC  : [%05d]\r\n",	GREEN,GREEN);
    printf("6. B\t:\tHEX	: [%04x]\tDEC  : [%05d]\r\n",	BLUE,BLUE);
#else
    
#endif

}
void TCS34725_disable(void){
    /* Turn the device off to save power */
    uint8_t reg = 0;
    reg = TCS34725_I2C_Read(TCS34725_ADDRESS,TCS34725_ENABLE);
    TCS34725_I2C_Write(TCS34725_ADDRESS,TCS34725_ENABLE, reg & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN));
}

void TCS34725_enable(void)
{
    TCS34725_I2C_Write(TCS34725_ADDRESS, TCS34725_ENABLE, TCS34725_ENABLE_PON);
    HAL_Delay(3);
    TCS34725_I2C_Write(TCS34725_ADDRESS, TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN);

    switch (_tcs34725IntegrationTime)
    {
        case TCS34725_INTEGRATIONTIME_2_4MS:
          HAL_Delay(3);
          break;
        case TCS34725_INTEGRATIONTIME_24MS:
          HAL_Delay(24);
          break;
        case TCS34725_INTEGRATIONTIME_50MS:
          HAL_Delay(50);
          break;
        case TCS34725_INTEGRATIONTIME_101MS:
          HAL_Delay(101);
          break;
        case TCS34725_INTEGRATIONTIME_154MS:
          HAL_Delay(154);
          break;
        case TCS34725_INTEGRATIONTIME_700MS:
          HAL_Delay(700);
          break;
    }
}

void tcs34725SetIntegrationTime(tcs34725IntegrationTime_t it)
{

  TCS34725_I2C_Write(TCS34725_ADDRESS,TCS34725_ATIME, it);
  _tcs34725IntegrationTime = it;
}
void getRawDataOneShot (void)
{
//    TCS34725_enable();
    TCS34725_getrawdata();
//    TCS34725_disable();
}

/**************************************************************************/
/*!
    @brief  Converts the raw R/G/B values to color temperature in degrees
            Kelvin
*/
/**************************************************************************/
uint16_t calculateColorTemperature(uint16_t r, uint16_t g, uint16_t b)
{
  float X, Y, Z;      /* RGB to XYZ correlation      */
  float xc, yc;       /* Chromaticity co-ordinates   */
  float n;            /* McCamy's formula            */
  float cct;

  /* 1. Map RGB values to their XYZ counterparts.    */
  /* Based on 6500K fluorescent, 3000K fluorescent   */
  /* and 60W incandescent values for a wide range.   */
  /* Note: Y = Illuminance or lux                    */
  X = (-0.14282F * r) + (1.54924F * g) + (-0.95641F * b);
  Y = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b);
  Z = (-0.68202F * r) + (0.77073F * g) + ( 0.56332F * b);

  /* 2. Calculate the chromaticity co-ordinates      */
  xc = (X) / (X + Y + Z);
  yc = (Y) / (X + Y + Z);

  /* 3. Use McCamy's formula to determine the CCT    */
  n = (xc - 0.3320F) / (0.1858F - yc);

  /* Calculate the final CCT */
  cct = (449.0F * powf(n, 3)) + (3525.0F * powf(n, 2)) + (6823.3F * n) + 5520.33F;

  /* Return the results in degrees Kelvin */
  return (uint16_t)cct;
}

/**************************************************************************/
/*!
    @brief  Converts the raw R/G/B values to lux
*/
/**************************************************************************/
uint16_t calculateLux(uint16_t r, uint16_t g, uint16_t b)
{
  float illuminance;

  /* This only uses RGB ... how can we integrate clear or calculate lux */
  /* based exclusively on clear since this might be more reliable?      */
  illuminance = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b);

  return (uint16_t)illuminance;
}

/**************************************************************************/
/*!
    @brief  Sets gain to the specified value
*/
/**************************************************************************/
void tcs34725SetGain(tcs34725Gain_t gain)
{
    TCS34725_I2C_Write(TCS34725_ADDRESS,TCS34725_CONTROL, gain);

     _tcs34725Gain = gain;
}

/**************************************************************************/
/*!
    @brief  Converts the raw R/G/B values to color temperature in degrees
            Kelvin using the algorithm described in DN40 from Taos (now AMS).
*/
/**************************************************************************/
uint16_t calculateColorTemperature_dn40(uint16_t r, uint16_t g, uint16_t b, uint16_t c)
{
    int rc;                     /* Error return code */
    uint16_t r2, g2, b2;        /* RGB values minus IR component */
    int gl;                     /* Results of the initial lux conversion */
    uint8_t gain_int;           /* Gain multiplier as a normal integer */
    uint16_t sat;               /* Digital saturation level */
    uint16_t ir;                /* Inferred IR content */

    /* Analog/Digital saturation:
     *
     * (a) As light becomes brighter, the clear channel will tend to
     *     saturate first since R+G+B is approximately equal to C.
     * (b) The TCS34725 accumulates 1024 counts per 2.4ms of integration
     *     time, up to a maximum values of 65535. This means analog
     *     saturation can occur up to an integration time of 153.6ms
     *     (64*2.4ms=153.6ms).
     * (c) If the integration time is > 153.6ms, digital saturation will
     *     occur before analog saturation. Digital saturation occurs when
     *     the count reaches 65535.
     */
    if ((256 - _tcs34725IntegrationTime) > 63) {
        /* Track digital saturation */
        sat = 65535;
    } else {
        /* Track analog saturation */
        sat = 1024 * (256 - _tcs34725IntegrationTime);
    }

    /* Ripple rejection:
     *
     * (a) An integration time of 50ms or multiples of 50ms are required to
     *     reject both 50Hz and 60Hz ripple.
     * (b) If an integration time faster than 50ms is required, you may need
     *     to average a number of samples over a 50ms period to reject ripple
     *     from fluorescent and incandescent light sources.
     *
     * Ripple saturation notes:
     *
     * (a) If there is ripple in the received signal, the value read from C
     *     will be less than the max, but still have some effects of being
     *     saturated. This means that you can be below the 'sat' value, but
     *     still be saturating. At integration times >150ms this can be
     *     ignored, but <= 150ms you should calculate the 75% saturation
     *     level to avoid this problem.
     */
    if ((256 - _tcs34725IntegrationTime) <= 63) {
        /* Adjust sat to 75% to avoid analog saturation if atime < 153.6ms */
        sat -= sat/4;
    }

    /* Check for saturation and mark the sample as invalid if true */
    if (c >= sat) {
        return 0;
    }

    /* AMS RGB sensors have no IR channel, so the IR content must be */
    /* calculated indirectly. */
    ir = (r + g + b > c) ? (r + g + b - c) / 2 : 0;

    /* Remove the IR component from the raw RGB values */
    r2 = r - ir;
    g2 = g - ir;
    b2 = b - ir;

    /* Convert gain to a usable integer value */
    switch(_tcs34725Gain) {
        case TCS34725_GAIN_4X: /* GAIN 4X */
            gain_int = 4;
            break;
        case TCS34725_GAIN_16X: /* GAIN 16X */
            gain_int = 16;
            break;
        case TCS34725_GAIN_60X: /* GAIN 60X */
            gain_int = 60;
            break;
        case TCS34725_GAIN_1X: /* GAIN 1X */
        default:
            gain_int = 1;
            break;
    }

    /* Calculate the counts per lux (CPL), taking into account the optional
     * arguments for Glass Attenuation (GA) and Device Factor (DF).
     *
     * GA = 1/T where T is glass transmissivity, meaning if glass is 50%
     * transmissive, the GA is 2 (1/0.5=2), and if the glass attenuates light
     * 95% the GA is 20 (1/0.05). A GA of 1.0 assumes perfect transmission.
     *
     * NOTE: It is recommended to have a CPL > 5 to have a lux accuracy
     *       < +/- 0.5 lux, where the digitization error can be calculated via:
     *       'DER = (+/-2) / CPL'.
     */
    float cpl = (((256-_tcs34725IntegrationTime)*2.4f) * gain_int) /
        (1.0f * 310.0f);

    /* Determine lux accuracy (+/- lux) */
    float der = 2.0f / cpl;

    /* Determine the maximum lux value */
    float max_lux = 65535.0 / (cpl * 3);

    /* Lux is a function of the IR-compensated RGB channels and the associated
     * color coefficients, with G having a particularly heavy influence to
     * match the nature of the human eye.
     *
     * NOTE: The green value should be > 10 to ensure the accuracy of the lux
     *       conversions. If it is below 10, the gain should be increased, but
     *       the clear<100 check earlier should cover this edge case.
     */
    gl =  0.136f * (float)r2 +                   /** Red coefficient. */
          1.000f * (float)g2 +                   /** Green coefficient. */
         -0.444f * (float)b2;                    /** Blue coefficient. */

    float lux = gl / cpl;

    /* A simple method of measuring color temp is to use the ratio of blue */
    /* to red light, taking IR cancellation into account. */
    uint16_t cct = (3810 * (uint32_t)b2) /      /** Color temp coefficient. */
                   (uint32_t)r2 + 1391;         /** Color temp offset. */

    return cct;
}


void i2c_status(HAL_StatusTypeDef data){
    switch(data){
        case HAL_OK	     :printf("HAL_OK     \r\n");break;
        case HAL_ERROR   :printf("HAL_ERROR  \r\n");break;
        case HAL_BUSY    :printf("HAL_BUSY   \r\n");break;
        case HAL_TIMEOUT :printf("HAL_TIMEOUT\r\n");break;
    }
}


void TCS34725_init(void){
	uint8_t DEV_DATA = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT |  TCS34725_ID);
//    tcs34725SetIntegrationTime(TCS34725_INTEGRATIONTIME_700MS);
//    tcs34725SetGain(TCS34725_GAIN_60X);
    TCS34725_enable();
	if(DEV_DATA == 0x44 || DEV_DATA == 0x4D){
		printf("TCS34725_Success\r\n");
	}else{
		printf("TCS34725_Failed : %02x\r\n",DEV_DATA);
	}

}

