#include "LTC2439.h"
#include <math.h>

#define DEBUG

LTC2439::LTC2439(uint8_t csPin, uint8_t sdoPin, double vref) :_csPin(csPin), _statusPin(sdoPin), _sampleTriggered(false), _vref(vref), _adcRes(16), _quantum(_vref / (pow(2, _adcRes)-1)),
_channelMap{0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15},
_SPIsettings(500000, MSBFIRST,SPI_MODE0)
{
  pinMode(_csPin, OUTPUT);
  digitalWrite(_csPin, HIGH);
  SPI.begin();
}

void LTC2439::setVref(double vref)
{
  _vref = vref;
  _quantum = _vref / (pow(2, _adcRes) - 1);
}

void LTC2439::startAsyncSample(uint8_t channel, boolean sgl, boolean force)
{
  if(!_sampleTriggered || force)
  {
    //On envoie la demande de conversion
    //On sélectionne l'adc
    pinMode(_statusPin, INPUT);
    digitalWrite(_csPin, LOW);
    while(digitalRead(_statusPin));
    uint8_t commande = 0b10100000;
    commande |= sgl << 4;
	
	SPI.beginTransaction(_SPIsettings);
    SPI.transfer(commande | _channelMap[channel]);
    SPI.endTransaction();
	
    digitalWrite(_csPin, HIGH);
    _sampleTriggered = true;
	
	//restoreRadioSpi();
  }
}

boolean LTC2439::asyncResultAvailable()
{
  //On désactive le bus SPI
  SPI.end();
  //On regarde si la valeur est prête à être lue:
  pinMode(_statusPin, INPUT);
  digitalWrite(_csPin, LOW);
  boolean ready = !digitalRead(_statusPin); //Si la pin sdo est à l'état haut, c'est que la conversion n'est pas terminée.
  digitalWrite(_csPin, HIGH);
  //On réactive le bus SPI
  SPI.begin();
  return ready;
}

double LTC2439::convertToVoltage(int32_t value)
{
  value += 32767;
  value *= _quantum;
  return value;
}

int32_t LTC2439::getAsyncValue()
{
  if(!_sampleTriggered)
    return -1;
    
  digitalWrite(_csPin, LOW);
  
  SPI.beginTransaction(_SPIsettings);
  int8_t bitsleft = 19;
  long result = 0; 
  while(bitsleft > 0) 
  {
    result <<= 8;
    result |= SPI.transfer(0);
    bitsleft -= 8;
  }
  SPI.endTransaction();
  
  digitalWrite(_csPin, HIGH);
    
  result >>= -bitsleft;
  int pos = (result & 0b10000000000000000)>> 16;
  unsigned long mask = 0b1111111111111111;
  result &= mask;
    
  if(!pos && result != 0)
  {
    result = result | (~mask);
  }

  _sampleTriggered = false;

  return result;
}
