#ifndef _RFM64W_H_
#define _RFM64W_H_
//----------------------------------------------------------------------------
///
/// \file   rfm69cw.h
///
/// \brief  See implementation for further implementation
///
/// \date   20231008
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


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

#include <lepto/debug.h>
#include <biwak/input.hpp>
#include <biwak/spi.hpp>
#include <biwak/output.hpp>
#include <lepto/regConfig.hpp>
#include <lepto/ring.h>

#if defined(MCU_PLATFORM_STM32)
   #include <lepto/ring.h>
   #include <lepto/mockQt.hpp>
   #include <biwak/stm32/rfm69cw.hpp>
#else
   #include <QQueue>
   #include <biwak/linux/rfm69cw.hpp>
#endif


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


// Active low
#define NSS_ACTIVE               false
#define NSS_INACTIVE             true
#define RFM69_CONFIG_SIZE        0x70

#define RFM69_READ_FLAG          ( 0 << 7 )
#define RFM69_WRITE_FLAG         ( 1 << 7 )

#define RFM69_CS_ACTIVE          0
#define RFM69_CS_INACTIVE        1

#define RFM69_RESET_ACTIVE       1
#define RFM69_RESET_INACTIVE     0

// max 255 without AES; or 64 (65 with address byte)
#define PAYLOAD_SIZE             (0x40)
//#define PAYLOAD_SIZE             (0x10+4)

#define CONFIG_RFM69CW_USE_STATIC_CONFIG     1


//----------------------------------------------------------------------------


class CLed;
enum ERegister: int;
enum EBitField: int;
enum EBitFieldValues: int;
enum ERegs: int;

enum ERfmState: unsigned int
{
   eRfmStateNone,
   eRfmStateReceiving,
   eRfmStateTransmiting,
   eRfmStateStandby,
};

/*
enum EPacketType: uint8_t
{
   ePacketTypeTransmit,
   ePacketTypeWaitForAcknowledge,
   ePacketTypeAcknowledge,
   ePacketTypeNotAcknowledge,
   ePacketTypeAcknowledged,
   ePacketTypeNotAcknowledged,
   ePacketTypeRetransmit,
};
*/
    
/*
struct SPacket
{
   int32_t counter;
   uint32_t magic;
   uint32_t nodeId;
       
   uint8_t targetNetId;
   //EPacketType type;
   uint8_t reserved[2];
   
   char data[ PAYLOAD_SIZE - ( 4 * 4 ) ];
};
*/

//static_assert( sizeof(SPacket::data) >= 8, "Payload to small" );

#define RFM69CW_MAX_PAYLOAD      ( 12 + 8 + 4 )  // Canbridge-header + ID + CAN-Data

class CRfm69cw
{
   public:
   
      struct SRawPacket
      {
         char data[ RFM69CW_MAX_PAYLOAD ];
         int payloadLength;
         int target;
      }__attribute__(( packed ));
      
      typedef uint8_t magic_t;
      static constexpr int F_STEP=61;
      static constexpr magic_t PRE_MAGIC=0xD2;
      static constexpr magic_t POST_MAGIC=0x2D;
      
  private:
      
      bool configValid;
      int receivePacketCount=0;
      int sendPacketCount=0;
      int lostPacketCount=0;
      int errorPacketCount=0;
      CSpi &m_spi;
      COutput m_outputCs;
      CInput m_gpioDIO0, m_gpioDIO1, m_gpioDIO2, m_gpioDIO3;
      CGpio m_gpioDIO5;
      COutput m_outputReset;
      CLed *trafficLed;
      ERfmState state;
      char *data;
      CRing<SRawPacket> m_receiveBuffer;
      CRing<SRawPacket> m_transmitBuffer;
      lrtimer_t m_receiveTimer;
      bool m_receiveInterrupt=false;
      
      hrtimer_t m_hrSenStartTime;
      CRegConfig<uint8_t> m_config;
      
   public:
      static constexpr uint8_t TARGET_ALL=0x00;    // broadcast target section
       
      //uint8_t config[RFM69_CONFIG_SIZE];

      CRfm69cw(CSpi &_spi, SRfmConfig config, CLed *_trafficLed = nullptr);
      void activateCs();
      void deactivateCs();

      void setTxMode();
      void setRxMode();
      void setStbyMode();
      void listenMode();
      void leaveListenMode();

      void readConfig();
      uint8_t readConfig( int address);
      //void writeConfig( int address, int value);
      void writeConfig( int address, uint8_t value );
      
      void writeConfig();
      void writeConfig( ERegs reg );
      //int setConfig( int address, int bitPos, int bitSize, int value);
      //int getConfig( int address, int bitPos, int bitSize);
      int updatedGetConfig( const SRegEntry& regEntry );
      int getConfig( const SRegEntry& regEntry );
      uint8_t setConfig( const SRegEntry& regEntry, uint8_t value );
      void setWriteConfig( const SRegEntry& regEntry, uint8_t value );
      void dumpConfig( );
      //void rawDump( );
      void dumpStaticConfig( );

      int initConfig();
      void setAddress(int address);
      
      int sendPackage(int targetId, /*EPacketType type,*/ int len, const void *data);
      int receivePackage( );

      int getReceivePacketCount()
      {
         return(receivePacketCount);
      };
      int getSendPacketCount()
      {
         return(sendPacketCount);
      };
      int getLostPacketCount()
      {
         return(lostPacketCount);
      }
      int getErrorPacketCount()
      {
         return(errorPacketCount);
      }
      ERfmState getState() const
      {
         return(state);
      }
      char *getData()
      {
         return(data);
      }
      void int0( bool value );
      void int1( bool value );
      void int2( bool value );
      void int3( bool value );
      void int4( bool value );
      void int5( bool value );
      CRing<SRawPacket>& receiveBuffer()
      {
         return(m_receiveBuffer);
      }
      
      void eventLoop();
      bool receiveInterrupt()
      {
         return ( m_receiveInterrupt );
      }
      bool getPllLock();
      bool canSend() const;
      bool getDio2Value() const
      {
         return( m_gpioDIO2.getValue() );
      }
};


//---fin----------------------------------------------------------------------
#endif // ? ! _RFM64W_H_
