//----------------------------------------------------------------------------
//
// \brief   MCP25050 Programmer
//
//          Programm custom CAN Id into MCP25050
//          Not implemented yet.
//
// \date    20160401
// \author  Maximilian Seesslen <mes@seesslen.net>
//
//----------------------------------------------------------------------------


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

#if 0
#include <biwak/timer.hpp>
#include <biwak/rtc.h>
#include <biwak/uart.h>
#include <biwak/qjtimer.h>
#include <biwak/eadisplay.h>
#include <biwak/temp_tsic.h>
//#include <biwak/can.h>
#include <biwak/button.h>
#include <biwak/led.h>
#include <lepto/log.h>
#include <lepto/tools.h>         // itoa
#include <lepto/time.h>
#include <lepto/can_message.h>
#include <biwak/timer.h>         // delay
#include <biwak/flash.h>

#include <stdio.h>              // snprintf
#include <math.h>              // snprintf
//#include <resolv.h>              // b64_ntop / base64
#endif

#include <stdint.h>
#include <biwak/rfm64w.hpp>
#include <biwak/led.hpp>
#include <lepto/log.h>
#include <lepto/lepto.h>         // IS_ENABLED

#define RX_MODE
//#define PAYLOAD_SIZE       64l
#define PAYLOAD_SIZE    64
//#define PAYLOAD_SIZE    32
//#define PAYLOAD_SIZE    16

#if ! defined ( LRTIMER_INVAL )
   #define LRTIMER_INVAL   ((hrtimer_t)0x80000000)
#endif

enum ECommand
{
   eCommandLoad=    2,
   eCommandRead=     4,
   eCommandIncrease= 6,
   eCommandBeginProgramming= 8,
   eCommandEndProgramming= 0xE,
};


struct SBitFieldDescriptors
{
   int addr;
   int bitStart;
   int bitSize;
   const char *name;
};

struct SPacket
{
   uint8_t addr;
   int32_t counter;
   uint32_t magic;
   char data[ PAYLOAD_SIZE - ( ( 2 * 4 ) + 1) ];
} __attribute__ ( ( packed ) );


enum ERegister: unsigned int{
   eRegisterTxDone=0,
   eRegisterFifoOverronClr,
   eRegisterFifoFill,
   eRegisterFifoFillMethod,
   eRegisterModuleMode,
   eRegisterDataMode,
   eRegisterTxStartIrq0,
   eRegisterTxIrq1,
   eRegisterFifoFull,
   eRegisterFifoEmpty,
   eRegisterPayloadLength,
   eRegisterFifoStbyAccess,
   eRegisterPllLocked,
   eRegisterPllLockEnable,
   eRegisterRxStbyIrq0,
   eRegisterRxStbyIrq1,
   eRegisterCrcStatus,
   eRegisterManchasterOn,
   eRegisterWhiteningOn,
   eRegisterCrcOn,
   eRegisterPacketFormat,
   eRegisterSyncOn,
   eRegisterSyncSize,
   eRegisterSyncTolerance,
   eRegisterSync0,
   eRegisterSync1,
   eRegisterSync2,
   eRegisterSync3,
   eRegisterFskOokControl,
   eRegisterFifoSize,
   eRegisterNodeAddress,
   eRegisterAddressFilter,
   eRegisterEnd,
};


struct SBitFieldDescriptors bitFieldDescriptors[]=
{
   // Addr, BitStart, BitSize, Name
   [eRegisterTxDone]={ 14, 5, 1, "Tx_done"},
   [eRegisterFifoOverronClr]={ 13, 4, 1, "Fifo_overrun_clr"},
   [eRegisterFifoFill]={ 14, 6, 1, "Fifo_fill"},
   [eRegisterFifoFillMethod]={ 13, 7, 1, "Fifo_fill_method"},
   [eRegisterModuleMode]={ 0, 5, 3, "Module_mode"},
   [eRegisterDataMode]={ 1, 6, 2, "Data_mode"},
   [eRegisterTxStartIrq0]={ 13, 3, 1, "Tx_start_irq_0"},
   [eRegisterTxIrq1]={ 13, 2, 1, "Tx_irq_1"},
   [eRegisterFifoFull]={ 13, 1, 1, "Fifofull"},
   [eRegisterFifoEmpty]={ 13, 0, 1, "Fifoempty"},
   [eRegisterPayloadLength]={ 28, 0, 7, "Payload_length"},
   [eRegisterFifoStbyAccess]={ 31, 6, 1, "Fifo_stby_access"},
   [eRegisterPllLocked]={ 14, 1, 1, "PLL_locked"},
   [eRegisterPllLockEnable]={ 14, 0, 1, "PLL_lock_en"},
   [eRegisterRxStbyIrq0]={13, 6, 2, "Rx_stby_irq_0"},
   [eRegisterRxStbyIrq1]={13, 4, 2, "Rx_stby_irq_1"},
   [eRegisterCrcStatus]={30, 0, 1, "CRC_status"},
   [eRegisterManchasterOn]={28, 7, 1, "Manchaster_on"},
   [eRegisterWhiteningOn]={30, 4, 1, "Whitening_on"},
   [eRegisterCrcOn]={30, 3, 1, "CRC_on"},
   [eRegisterPacketFormat]={30, 7, 1, "Pkt_format"},
   [eRegisterSyncOn]={18, 5, 1, "Sync_on"},
   [eRegisterSyncSize]={18, 3, 2, "Sync_size"},
   [eRegisterSyncTolerance]={18, 1, 2, "Sync_tol"},
   [eRegisterSync0]={22, 0, 8, "Sync_0"},
   [eRegisterSync1]={23, 0, 8, "Sync_1"},
   [eRegisterSync2]={24, 0, 8, "Sync_2"},
   [eRegisterSync3]={25, 0, 8, "Sync_3"},
   [eRegisterFskOokControl]={1, 4, 2, "FSK_OOK_ctrl"},
   [eRegisterFifoSize]={12, 6, 2, "Fifo_size"},
   [eRegisterNodeAddress]={29, 0, 8, "Node_adrs"},
   [eRegisterAddressFilter]={30, 1, 2, "Adrs_filt"},
};


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



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


bool handleInterrupt=false;

//#define MD  usleep(100);
//#define MD  usleep(1000);
//#define MD  usleep(30000);
#define MD

CRfm64w::CRfm64w( CSpi &_spi,
                  EGpioPeripheral eGpioPeripheralInterrupt, EGpioPin eGpioPinInterrupt,
                  const SExtiConfig &extiConfig,
                  EGpioPeripheral eGpioPeripheralNssConfig, EGpioPin eGpioPinNssConfig,
                  EGpioPeripheral eGpioPeripheralNssData,   EGpioPin eGpioPinNssData,
                  EGpioPeripheral eGpioPeripheralReset,   EGpioPin eGpioPinReset,
                  CLed *_trafficLed
                  )
   : m_spi( _spi )
   , m_irq( eGpioPeripheralInterrupt, eGpioPinInterrupt, extiConfig )
   , nssConfig( eGpioPeripheralNssConfig, eGpioPinNssConfig )
   , nssData( eGpioPeripheralNssData, eGpioPinNssData )
   , outputReset( eGpioPeripheralReset, eGpioPinReset )
   , trafficLed( _trafficLed )
{
   setCsNone();
   m_spi.setDataSize(8);
   m_spi.writeData( (uint32_t)0, 1);

   data=NULL;
   
   #if IS_ENABLED( CONFIG_BIWAK_USE_INPUT_SIGNAL )
   m_irq.interruptSignal.connect(this, &CRfm64w::interrupt);
   #else
   #endif

   outputReset.setValue( true );
   usleep(0x100);
   outputReset.setValue( false );
   usleep(0x100);

   return;
   readConfig();
   lInfo("Initial Values: ");
   dumpConfig();

   initConfig();
   readConfig();
   dumpConfig();
   state=eRfmStateNone;

   setRxMode();
}


void CRfm64w::setCsConfig()
{
   nssConfig.setValue(NSS_ACTIVE);
   nssData.setValue(NSS_INACTIVE);
   MD;
}


void CRfm64w::setCsData()
{
   nssConfig.setValue(NSS_INACTIVE);
   nssData.setValue(NSS_ACTIVE);
   MD;
}


void CRfm64w::setCsNone()
{
   nssConfig.setValue(NSS_INACTIVE);
   nssData.setValue(NSS_INACTIVE);
   MD;
}


void CRfm64w::readConfig( )
{
   uint8_t rData[0x2];
   uint8_t wData[0x2];
   bool empty=true;

   setCsConfig();

   for( int address=0; address < RFM_CONFIG_SIZE; address++)
   {
      // From left to right, MSB First
      // 0 :   Stopbit(0)
      // 1 :   1=read; 0=write
      // 2..6: Address
      // 7 :   Stop(0)
      //setConfigMode();
      wData[0]=RFM_READ_FLAG | ( address << 1 );
      wData[1]=0;

      m_spi.writeReadData(wData, rData, 2);
      config[address]=rData[1];
      if(config[address])
         empty=false;
   }

   if(empty)
   {
      lCritical("Seems the module is dead");
      configValid=false;
      lFatal( "Module dead ", -1);
   }
   else
      configValid=true;

   setCsNone();
}


void CRfm64w::readConfig( int address)
{
   uint8_t rData[0x2];
   uint8_t wData[0x2];

   setCsConfig();

   // From left to right, MSB First
   // 0 :   Stopbit(0)
   // 1 :   1=read; 0=write
   // 2..6: Address
   // 7 :   Stop(0)
   wData[0]=( 1<<6 ) | ( address << 1 );
   wData[1]=0;
   lAssert(address<RFM_CONFIG_SIZE);

   m_spi.writeReadData(wData, rData, 2);
   config[address]=rData[1];

   setCsNone();

   return;
}


int CRfm64w::getConfig( ERegister eRegister )
{
   return( getConfig(
              bitFieldDescriptors[eRegister].addr ,
              bitFieldDescriptors[eRegister].bitStart ,
              bitFieldDescriptors[eRegister].bitSize
           )
         );
}


int CRfm64w::setConfig( ERegister eRegister, int value )
{
   return( setConfig(
              bitFieldDescriptors[eRegister].addr ,
              bitFieldDescriptors[eRegister].bitStart ,
              bitFieldDescriptors[eRegister].bitSize,
              value
           )
         );
}

void CRfm64w::setWriteConfig( ERegister eRegister, int value )
{
   uint8_t rData[0x2];
   uint8_t wData[0x2];
   int address;

   setCsConfig();
   setConfig(
              bitFieldDescriptors[eRegister].addr ,
              bitFieldDescriptors[eRegister].bitStart ,
              bitFieldDescriptors[eRegister].bitSize,
              value
           );

   address=bitFieldDescriptors[eRegister].addr ;
   wData[0]=RFM_WRITE_FLAG | ( address << 1 );
   wData[1]= config[address];

   m_spi.writeReadData(wData, rData, 2);
   setCsNone();

   return;
}


void CRfm64w::writeConfig( )
{
   uint8_t rData[0x2];
   uint8_t wData[0x2];

   setCsConfig();

   for( int address=0; address < RFM_CONFIG_SIZE; address++)
   {
      // From left to right, MSB First
      // 0 :   Stopbit(0)
      // 1 :   1=read; 0=write
      // 2..6: Address
      // 7 :   Stop(0)
      wData[0]= RFM_WRITE_FLAG | ( address << 1 ) | 0;
      wData[1]= config[address];

      m_spi.writeReadData(wData, rData, 2);
   }

   setCsNone();
}


int CRfm64w::setConfig( int address, int bitPos, int bitSize, int value)
{
   uint32_t mask=(((uint32_t)-1)>>( (sizeof(uint32_t)*8) - bitSize)) << bitPos;
   config[address] = ( config[address] & (~mask)) | ( (value << bitPos) & mask );
   return( config[address] );
}


int CRfm64w::getConfig( int address, int bitPos, int bitSize)
{
   uint32_t mask=(((uint32_t)-1)>>( (sizeof(uint32_t)*8) - bitSize)) << bitPos;
   uint32_t value=( config[address] & mask) >> bitPos;
   return( value );
}


void CRfm64w::dumpConfig( )
{
   //lHint << "Fifo_overrun_clr: " << canbridge->readConfig(eRegisterFifoOverronClr);
   if(!configValid)
      return;
   lInfo("Dumping config:");
   unsigned int eRegister=0;
   for( eRegister=0; eRegister<eRegisterEnd; eRegister++ ){
      lInfo("   %s: %d", bitFieldDescriptors[eRegister].name
             , getConfig((ERegister)eRegister) );
   }
}

int CRfm64w::initConfig()
{
   setConfig( eRegisterModuleMode, 1);     // Mode: 1, Standby
   setConfig( eRegisterDataMode, 2);       // Data_mode: "Packet mode"
   #ifdef RX_MODE
   setConfig( eRegisterRxStbyIrq0, 2);
   setConfig( eRegisterRxStbyIrq1, 0);
   #else
   setConfig( eRegisterTxStartIrq0, 1);    // Tx_start_irq_0: 1; /Fifoempty
   setConfig( eRegisterTxIrq1, 1);         // Tx_irq_1: 1  IRQ_1 <= Tx_done
   #endif
   setConfig( eRegisterPayloadLength, PAYLOAD_SIZE);  // Payload_length: 8 Byte
   setConfig( eRegisterPllLockEnable, 0 );

   #ifdef RX_MODE
      setConfig( eRegisterFifoStbyAccess, 1); // Fifo_stby_access = 1: Read
   #else
      setConfig( eRegisterFifoStbyAccess, 0); // Fifo_stby_access = 0: Write
   #endif

   setConfig( eRegisterManchasterOn, 0);        // Wastes a lot of time
   setConfig( eRegisterWhiteningOn, 0);
   setConfig( eRegisterPacketFormat, 0);        // 0: fixed
   setConfig( eRegisterCrcOn, 1);
   setConfig( eRegisterFifoSize, 3);            // 0:16B, 3:64B

   setConfig( eRegisterSyncOn, 1);
   setConfig( eRegisterSyncSize, 3);            // 3: 32Bits; 1: 16Bit
   setConfig( eRegisterSyncTolerance, 0);
   setConfig( eRegisterSync0, 0x03);
   setConfig( eRegisterSync1, 0x0C);
   setConfig( eRegisterSync2, 0x30);
   setConfig( eRegisterSync3, 0xC0);

   setConfig( eRegisterFskOokControl, 2);       // 2: FSK,

   setConfig( eRegisterAddressFilter, 3);       // 3: Node + 0 + 0xFF
   setConfig( eRegisterNodeAddress, 0x10);

   writeConfig();

   return(0);
}

int CRfm64w::setTxMode()
{
   setConfig( eRegisterTxStartIrq0, 1);    // Tx_start_irq_0: 1; /Fifoempty
   setConfig( eRegisterTxIrq1, 1);         // Tx_irq_1: 1  IRQ_1 <= Tx_done

   setConfig( eRegisterRxStbyIrq0, 0);
   setConfig( eRegisterRxStbyIrq1, 0);

   //setConfig( eRegisterFifoStbyAccess, 0); // Fifo_stby_access = 0: Write
   setConfig( eRegisterFifoStbyAccess, 1); // Fifo_stby_access = 1: Read
   writeConfig();

   handleInterrupt=true;
   state=eRfmStateTransmiting;

   setWriteConfig( eRegisterModuleMode, 4);     // Mode: 4, TX

   return(0);
}


int CRfm64w::setRxMode()
{
   setConfig( eRegisterRxStbyIrq0, 2);
   setConfig( eRegisterRxStbyIrq1, 0);

   setConfig( eRegisterTxStartIrq0, 0);    // Tx_start_irq_0: 1; /Fifoempty
   setConfig( eRegisterTxIrq1, 0);         // Tx_irq_1: 1  IRQ_1 <= Tx_done

   setConfig( eRegisterFifoStbyAccess, 1); // Fifo_stby_access = 1: Read
   writeConfig();

   handleInterrupt=true;
   state=eRfmStateReceiving;

   setWriteConfig( eRegisterModuleMode, 3);     // Mode: 3, RX

   return(0);
}


int CRfm64w::setStbyMode()
{
   state=eRfmStateStandby;
   setWriteConfig( eRegisterModuleMode, 1);     // Mode: 1, Stdby
   return(0);
}


int CRfm64w::sendPackage(int data)
{
   static SPacket packet;
   static  uint32_t sendCounter=0;

   uint8_t *wData=(uint8_t *)&packet;

   setStbyMode();
   setWriteConfig( eRegisterFifoStbyAccess, 0); // Fifo_stby_access = 0: Write

   /*
   for(int i1=0; i1 < PAYLOAD_SIZE ; i1++)
   {
      wData[i1]=i1;
   }
   */
   memcpy(packet.data, &data, sizeof(data));

   packet.addr=0x10;
   packet.counter=sendCounter;
   packet.magic=0x12345678;

   setCsData();

   for(int i1=0; i1 < PAYLOAD_SIZE ; i1++)
   {
      m_spi.writeData((uint8_t *)&wData[i1], 0x1);
   }

   //m_spi.writeData((char*)wData, PAYLOAD_SIZE);
   setCsNone();

   sendCounter++;
   setTxMode();

   return(0);
}


// \brief      Irq1 TX_done in TX mode
void CRfm64w::interrupt( bool value ) // EInterrupt eInterrupt, int iData, void* pData) /*virtual*/
{
   static SPacket packet;
   static int lastPackageCount=0;
   //static int &packageCounter=(*(int *)rData);

   uint8_t *packetData=(uint8_t *)&packet;
   //exception("Yeaaa", 0);

   if(!handleInterrupt)
      return;

   if( startTimer == LRTIMER_INVAL)
      startTimer=getLrTimerValue();

   //memset(data, 0, PAYLOAD_SIZE);
   packet.magic=0;

   if(trafficLed)
      trafficLed->switchOn();
   setStbyMode();

   if(trafficLed)
      trafficLed->switchOff();

   if(state==eRfmStateTransmiting)
   {
      //readConfig();
      //dumpConfig();

      //usleep(USEC_PER_SEC);
      sendPacketCount++;
      //sendPackage();
      //setRxMode();
      setStbyMode();
   }
   else
   {
      setWriteConfig(eRegisterFifoStbyAccess, 1);

      packet.magic=0xaffe;

      #if 1
         for(int i1=0; i1<PAYLOAD_SIZE / 1; i1++)
         {
            setCsData();
            m_spi.readData(&packetData[i1*1], 1);
            setCsNone();
         }
      #else
         setCsData();
         /* (uint8_t *)&packet */
         m_spi.readData( data, PAYLOAD_SIZE);
         setCsNone();
      #endif

      if( packet.magic != 0x12345678 )
      {
         errorPacketCount++;
      }
      else
      {
         receivePacketCount++;
      }

      if( ( lastPackageCount ) && ( lastPackageCount+1 != packet.counter) )
      {
         lostPacketCount++;
      }
      else
      {
         // Nothing to do
      }
      lastPackageCount = packet.counter;
      setRxMode();

      #if 0
      lHint << "";
      uint8_t *rData=data;
      for(int i1=0; i1<PAYLOAD_SIZE/4; i1++)
         lHint << "Data: " << rData[(i1*4)+0] << "/"
                           << rData[(i1*4)+1] << "/"
                           << rData[(i1*4)+2] << "/"
                           << rData[(i1*4)+3] << "/";
      #endif

      //int *data=(int *)packet.data;
      data=(char *)packet.data;

      //lHint << "Received Package: " << *data << " Magic: " << packet.magic;
      //lHint << "   Err: " << errorPacketCount;

      //exception("Foo", 0);
   }

   //sleepMode();

   return;
}


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