//----------------------------------------------------------------------------
///
/// \brief  an TSIC digital temperature sensor
///
///         Decoding is done with prefetched slopes so driver is interrupt
///         driven.
///
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


//---Documentation-------------------------------------------------------------


//---Zacwire protocol-----------------
//
// http://www.mikrocontroller.net/attachment/48771/TSIC_ZACWIRE.pdf
// Frame Distance: something > 100ms (start to start) (measured 101,2ms)
// Frame Distance: ca. 10fps (measured 9,88 Hz)
// Frame Time: 2.60ms (Oszi)
// Bit Time: 125us (Sheet)
// Smallest pulse: 31.25us (Sheet)
// Frame: |S00000198PSS76543210P|
//        |      0   t          |
// 21Bits, 40 Slopes (measured oszi, measured logic)
// Stop bit does not exist, its completely high


//---Defines------------------------------------------------------------------


#define TSIC_SLOPE_TIMEOUT        (0x160)         // tSlope was constantly 0x16
#define TSIC_SLOPES_PER_FRAME     (40)


//---Includes-----------------------------------------------------------------


//---Own------------------------------

#include <biwak/temp_tsic.h>
#include <biwak/gpio.h>
#include <biwak/uart.h>
#include <biwak/biwak.h>         // exception();
#include <biwak/lltools.h>       // setExti()
#include <biwak/handler.h>       // getHRTicker()
//#include <lepto/time.h>          // USEC_PER_SEC
//#include <lepto/ring.h>          //
#include <lepto/log.h>          // USEC_PER_SEC


//---Implementation-----------------------------------------------------------



enum ETsicSlope
{
   eTsicSlopeStartBit,
   eTsicSlopeBit1,
   eTsicSlopeBit0,
   eTsicSlopeInvalid,
};


hrtimer_t   tsicPulseWidth[]=
{
   [eTsicSlopeStartBit]=   (128*2)/4,      // 64usec (measured), 0x40
   [eTsicSlopeBit1]=       (128*1)/4,      // 32usec, 0x20
   [eTsicSlopeBit0]=       (128*3)/4,      // 94usec, 0x5e
   [eTsicSlopeInvalid]=    0,
};


enum ETsicBitPos
{
   eTsicBitPosStart                 = 0x00,
   eTsicBitPosBits                  = 0x01,
   eTsicBitPosParity                = 0x02,

   eTsicBitPosFinishedCalculation   = 0x03,
   eTsicBitPosFinished              = 0x04,
   eTsicBitPosErrournous            = 0x05,
};


/// \brief  Le contructeur
///
///         Just for CInput()
CTempTsic::CTempTsic(EGpioPeripheral _eGpioPeripheral, EGpioPin _eGpioPin)
   :CInput(_eGpioPeripheral, _eGpioPin, gpioModeInput)
   ,equalRing(10) // 10 means 1sek
{
   equalRing.setVolatile(true);
}


CTempTsicDecoder::CTempTsicDecoder()
{
   eTsicError=eTsicErrorNone;

   setProtocolTimeout( 1500 );      // ca 1/2 Frame
   //setProtocolTimeout( 125 * 2 );
   setSlopesPerFrame(TSIC_SLOPES_PER_FRAME);
   //setPulseTolerance(125/8);   // 15usec, SuccessPercent 0x5d
   //setPulseTolerance(125/5);   // 25usec, high error qhote
   //setPulseTolerance(128/8);   // 16usec
   setPulseTolerance( (32/2) +1) ;
}

/// \brief  Le destructeur
CTempTsic::~CTempTsic()
{
   // Nothing to do here
}


#define SLOPE_ASSUME(xa,xb)\
   {\
      if(xa!=xb) \
      {\
         bitPos=eTsicBitPosErrournous; \
         eTsicError=eTsicErrorAssume; \
         break;\
      }\
   }


void CTempTsicDecoder::dumpSlopes()
{
   int slopeCount=getSlopeCount();

   for(int i1=0; i1 < slopeCount-1; i1++)
   {
      lHint << "#" << i1 << "/" << slopeCount << " pulseWidth: " << (long int)pulseWidth(i1);
      usleep(10);
      //pf.uart[0]->flushOutput();
   }

   //FREEZE;
}


void CTempTsicDecoder::decodeFrame() /*[virtual]*/
{
   bool doBreak=false;
   int slopePos=0;
   ETsicBitPos bitPos=eTsicBitPosStart;
   char byte[2], parity[2], parityWanted[2];
   int bytePos=0;
   int dataBitPos=0;

   while(!doBreak)
   {
      /*
      if(slopePos<slopeCount-1)
         if( (diff=pulseWidth(slopePos)) < 0 )
            exception("Negative diff", slopePos);
      */

      switch(bitPos)
      {
         case eTsicBitPosStart:
            SLOPE_ASSUME(decodePulsePauseWidth(slopePos++,tsicPulseWidth),eTsicSlopeStartBit);
            SLOPE_ASSUME(decodePulsePauseWidth(slopePos++,tsicPulseWidth),eTsicSlopeStartBit);
            dataBitPos=0;
            byte[bytePos]=parity[bytePos]=parityWanted[bytePos]=0;
            bitPos=eTsicBitPosBits;
            break;

         case eTsicBitPosBits:
            switch(decodePulsePauseWidth(slopePos++,tsicPulseWidth))
            {
               case eTsicSlopeBit1:
                  SLOPE_ASSUME(decodePulsePauseWidth(slopePos++,tsicPulseWidth),eTsicSlopeBit0)
                  byte[bytePos] |= 1 << (7-dataBitPos);
                  parityWanted[bytePos] = 1 - parityWanted[bytePos];
                  break;
               case eTsicSlopeBit0:
                  SLOPE_ASSUME(decodePulsePauseWidth(slopePos++,tsicPulseWidth),eTsicSlopeBit1)
                  break;
               default:
                  bitPos=eTsicBitPosErrournous;
                  eTsicError=eTsicErrorDecodeBit;
                  break;
            }
            if(bitPos!=eTsicBitPosErrournous)
            {
               dataBitPos++;
               if(dataBitPos>=8)
               {
                  dataBitPos=0;
                  bitPos=eTsicBitPosParity;
               }
            }
            break;

         case eTsicBitPosParity:
            if(decodePulsePauseWidth(slopePos++,tsicPulseWidth) == eTsicSlopeBit1)
               parity[bytePos]=1;
            bytePos++;
            slopePos++; // Can not measure second slope, but have to increase
            if(bytePos>=2)
               bitPos=eTsicBitPosFinishedCalculation;
            else
               bitPos=eTsicBitPosStart;
            break;

         case eTsicBitPosFinishedCalculation:
         {
            int tValue=(byte[0]<<8) | byte[1];
            // Calculation from sample code:
            // Temp_float = ((float)temp_value / 2047 * 200) - 50;

            //m_temperature= ( ( ( (float)tValue * 200.0 ) / 2047.0 ) - 50.0 ) * 1000;
            //m_temperature= ( ( tValue * 200 * ( 100 * 2047 ) ) / 2047 ) - ( 50 * 100 );
            int temperature= ( ((float)tValue / 2047 * 200) - 50 ) * 1000;
            sink(temperature);
            if( (parity[0]!=parityWanted[0]) || (parity[1]!=parityWanted[1]) )
            {
               bitPos=eTsicBitPosErrournous;
               eTsicError=eTsicErrorParrity;
            }
            else
               bitPos=eTsicBitPosFinished;
            break;
         }

         case eTsicBitPosFinished:
         {
            //lHint << "TSIC frame (err:" << errorCounter << "): " << m_temperature;
            successCount++;
            doBreak=true;
            break;
         }

         case eTsicBitPosErrournous:
         default:
            /*
            lHint << "Error decoding TSIC(E:" << errorCount << "/S:" << successCount << ")";
            // "   bitPos: " << bitPos <<
            lHint << "; Slopepos: " << slopePos << "; slopeWidth: " << pulseWidth(0);
            */

            //shutup=true;
            //dumpSlopes();

            doBreak=true;
            errorFrameCount++;
            break;
      }
   }

   //totalFrameCount gets incremented by CInput automatically

   return;
}


ETsicError CTempTsicDecoder::getError()
{
   return(eTsicError);
}


int32_t CTempTsic::getTemperature()
{
   //return( m_temperature );
   return( equalRing.crossfoot() );
}


//---fin----------------------------------------------------------------------
