/*
 * rf_listener_arduino.
 * 
 */

#include <Wire.h>

#define kSlave_Address 0x12

int gGetAddr = 0;

int gRxPin = 5;

unsigned int    gTemperatureCelsius;
unsigned int    gRainfallMillimeters;
  
#define kWeatherInovalley_Frame_LengthBytes               5
#define kWeatherInovalley_Frame_LengthBytes_WithoutCRC    4

#define kWeatherInovalley_Lock_Min                7500
#define kWeatherInovalley_Lock_Max                8500

#define kWeatherInovalley_Bit1_Min                3500
#define kWeatherInovalley_Bit1_Max                4500

#define kWeatherInovalley_Bit0_Min                1500
#define kWeatherInovalley_Bit0_Max                2500

#define kWeatherInovalley_ReadBit_MaxTimeout      kWeatherInovalley_Bit1_Max

#define kWeatherInovalley_Frame_LengthBits    (8+4+12+8+5) //8bits=>StationID 4bits=>Unknown 12bits=>Temperature 8bits=>Rainfall 5bits=>CRC

#define kWeatherInovalley_CRC_LengthBits      5

/*!  ----------------------------------------------------------------------------
 *  @fn setup
 *
 *  @brief This function setup the MCU.
 */
void setup (void)
{
    Serial.begin (9600);

    // Setup I2C
    Wire.begin (kSlave_Address);
    Wire.onReceive (receiveData);
    Wire.onRequest (sendData);

    // Setup 
    pinMode (gRxPin, INPUT);
}


/*!  ----------------------------------------------------------------------------
 *  @fn loop
 *
 *  @brief Main Loop.
 */
void loop (void)
{
  unsigned char   theBuffer[kWeatherInovalley_Frame_LengthBytes];
  unsigned long   thePulse = 0;
  unsigned int    theBitRead = 0;
  int             theRet;

  /* Wait Lock */
  while ((thePulse < kWeatherInovalley_Lock_Min || thePulse > kWeatherInovalley_Lock_Max)) {
    
    thePulse = pulseIn (gRxPin, LOW, 1000000);
  }

  /* Read NEC */
  theBitRead = readNEC (theBuffer, kWeatherInovalley_Frame_LengthBits);
  if (theBitRead != kWeatherInovalley_Frame_LengthBits) {

    //Serial.println ("Unable to properly read NEC");
    //Serial.println(theBitRead);
    return;
  }
  
  /* Verify CRC */
  theRet = checkCRC (theBuffer, kWeatherInovalley_Frame_LengthBits);
  if (theRet != 0) {
    
    //Serial.println ("CRC Failed.");
    return;
  }

  /* Extract Data. */
  gTemperatureCelsius = theBuffer[1] << 8 | theBuffer[2];
  gRainfallMillimeters = theBuffer[3];
  
  Serial.print("Temperature: ");
  Serial.println(gTemperatureCelsius);

  Serial.print("Rainfall: ");
  Serial.println(gRainfallMillimeters);
  
}


/*!  ----------------------------------------------------------------------------
 *  @fn receiveData
 *
 *  @brief IIC receive data function.
 */
void receiveData (int byteCount)
{
  while (Wire.available ()) {
    
    gGetAddr = Wire.read ();
    Serial.print ("Get Addr: ");
    Serial.println (gGetAddr);
  }
}


/*!  ----------------------------------------------------------------------------
 *  @fn sendData
 *
 *  @brief IIC send data function.
 */
void sendData (void)
{
  if (gGetAddr == 0) {

    Wire.write(gTemperatureCelsius);
  }
  
  if (gGetAddr == 1) {

    Wire.write(gRainfallMillimeters);
  }
}


/*!  ----------------------------------------------------------------------------
 *  @fn readNEC
 *
 *  @brief Read the NEC Protocol.
 */
unsigned int readNEC (unsigned char *aBuffer, unsigned int aDataLengthBits)
{
    unsigned long thePulseTimeMicro = 0;
   // unsigned long theStartFunctionTimeMs = mDigitalOutput->nowMicroseconds()/1000;
    unsigned long theBitRead = 0;

    for (unsigned int i=0; i<(aDataLengthBits/8)+1; i++)
        aBuffer[i] = 0x00;

    for (theBitRead=0; theBitRead<aDataLengthBits; theBitRead++)
    {
        thePulseTimeMicro = pulseIn (gRxPin, LOW, kWeatherInovalley_ReadBit_MaxTimeout);
        if (thePulseTimeMicro > kWeatherInovalley_Bit1_Min && thePulseTimeMicro < kWeatherInovalley_Bit1_Max)
        {
            //Bit 1
            aBuffer[theBitRead/8] |= (1 << (7 - (theBitRead%8)));
        }
        else if (thePulseTimeMicro > kWeatherInovalley_Bit0_Min && thePulseTimeMicro < kWeatherInovalley_Bit0_Max)
        {
            //Bit 0
            aBuffer[theBitRead/8] |= (0 << (7 - (theBitRead%8)));
        }
        else
        {
            break; //Invalid read
        }
    }

    return theBitRead;
}


/*!  ----------------------------------------------------------------------------
 *  @fn checkCRC
 *
 *  @brief Read the NEC Protocol.
 */
int checkCRC (unsigned char *aBuffer, unsigned int aDataLengthBits)
{
  unsigned char theCRCFrame = *(aBuffer + kWeatherInovalley_Frame_LengthBytes_WithoutCRC);
  theCRCFrame >>= 8 - kWeatherInovalley_CRC_LengthBits;
  
  unsigned char theCRCComputed = CRC (aBuffer, (aDataLengthBits - kWeatherInovalley_CRC_LengthBits) / 8, theCRCFrame >> 4 & 0x01);

  if (theCRCComputed != theCRCFrame)
    return -1;
  
  return 0;
}


/*!  ----------------------------------------------------------------------------
 *  @fn CRC
 *
 *  @brief Compute the CRC.
 */
unsigned char CRC (unsigned char *aBuffer, unsigned int aBufferLength, unsigned char aXorOut)
{
    unsigned char theCRC = 0x00;
    unsigned char theWidth = 5;
    unsigned char thePoly = 0x10;

    theCRC <<= 8 - theWidth;
    for (unsigned int i=0; i<aBufferLength; i++)
    {
        theCRC ^= aBuffer[i];
        for (unsigned int k=0; k<8; k++)
            theCRC = theCRC & 0x80 ? (theCRC << 1) ^ thePoly : theCRC << 1;
    }
    theCRC &= 0xFF;
    theCRC >>= 8 - theWidth;

    theCRC = theCRC ^ aXorOut;

    return theCRC;
}

