#ifndef BIWAK_CAN_HPP
#define BIWAK_CAN_HPP
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------


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


//#include <lepto/can_message.h>
#include <lepto/ring.h>
#include <lepto/bufferRing.hpp>
//#include <biwak/gpio.hpp>              // EGpioPeripheral
#include <biwak/canMessage.hpp>
#include <stdio.h>                     // printf
#if defined (STM32)
    #include <HALWrapper/stm32_can.h>
#endif


//---Forward declarations-----------------------------------------------------


#if defined (MCU_PLATFORM_STM32) && !defined ( STM32L1 ) && ! defined ( STM32G0 )
   //#define CAN_HANDLE_TYPE    CAN_HandleTypeDef
   #include <HALWrapper/stm32_can.h>
#else
   #define CAN_TypeDef           void
   #define CAN_HandleTypeDef     char
   #define CAN_RxHeaderTypeDef   int
   #define CAN_TxHeaderTypeDef   int
   #define CAN_FilterTypeDef     char
#endif

#if defined(FDCAN1)
   #define HAL_CAN_StateTypeDef  HAL_FDCAN_StateTypeDef
   #define CAN_TypeDef           FDCAN_GlobalTypeDef
   #define CAN_HandleTypeDef     FDCAN_HandleTypeDef
   #define CAN_FilterTypeDef     FDCAN_FilterTypeDef
   #define CAN_RxHeaderTypeDef   FDCAN_RxHeaderTypeDef
   #define CAN_TxHeaderTypeDef   FDCAN_TxHeaderTypeDef
   #define HAL_CAN_Init          HAL_FDCAN_Init
   #define HAL_CAN_DeInit        HAL_FDCAN_DeInit
   #define HAL_CAN_Start         HAL_FDCAN_Start
   #define HAL_CAN_Stop          HAL_FDCAN_Stop
   #define HAL_CAN_GetRxMessage  HAL_FDCAN_GetRxMessage
   #define HAL_CAN_AddTxMessage  HAL_FDCAN_AddMessageToTxFifoQ
   #define HAL_CAN_GetTxMailboxesFreeLevel   HAL_FDCAN_GetTxFifoFreeLevel
   #define HAL_CAN_GetState      HAL_FDCAN_GetState
   #define HAL_CAN_GetError      HAL_FDCAN_GetError
   #define HAL_CAN_ConfigFilter  HAL_FDCAN_ConfigFilter
   #define HAL_CAN_ActivateNotification HAL_FDCAN_ActivateNotification
   #define CAN_MODE_NORMAL       FDCAN_MODE_NORMAL
   #define CAN_RX_FIFO0          FDCAN_RX_FIFO0
   #define CAN_RX_FIFO1          FDCAN_RX_FIFO1
   #define CAN_TX_FIFO0          FDCAN_TX_FIFO0
   #define CAN_TX_FIFO1          FDCAN_TX_FIFO1
   #define CAN_ID_EXT            FDCAN_EXTENDED_ID
   #define CAN_ID_STD            FDCAN_STANDARD_ID
   #define CAN_IT_RX_FIFO0_MSG_PENDING   FDCAN_IT_RX_FIFO0_NEW_MESSAGE
   #define CAN_IT_RX_FIFO1_MSG_PENDING   FDCAN_IT_RX_FIFO1_NEW_MESSAGE
   #define HAL_CAN_IRQHandler    HAL_FDCAN_IRQHandler

   #define CAN_IMPLEMENTATION_FDCAN
#else
    #if defined(STM32)
        #define CAN_IMPLEMENTATION_1
    #else
        #define CAN_IMPLEMENTATION_VOID
    #endif
#endif

#if ! defined ( CONFIG_BIWAK_CAN_TX_ERROR_EVENT )
   #define CONFIG_BIWAK_CAN_TX_ERROR_EVENT               1
#endif


//---Declarations-------------------------------------------------------------


struct SCanConfig;
class CCan;

extern CCan *interruptCan1;

#define CAN_BUFFERS     48    // 24: Still problems when devices get scanned
#define CAN_MAILBOXES   12

class CCan
{
   public:
      enum EBitRate{
         // ( 1000 / EBitRate ) * 1000
         e1Mbit = 1,
         e500kbit = 2,
         e250kbit = 4,
         e125kbit = 8,
         e50kbit = 20,
         e20kbit = 50,
         e10kbit = 100,
         e5kbit = 200,
      };

   private:
      const SCanConfig &m_configData;
      CAN_HandleTypeDef *m_pHandler;

      #if ! defined ( CAN_IMPLEMENTATION_2 )
         CAN_TxHeaderTypeDef m_txHeader;
         CAN_RxHeaderTypeDef m_rxHeader;
      #endif

      #if IS_ENABLED( CONFIG_BIWAK_CAN_TX_ERROR_EVENT )
      bool m_txError=false;
      #endif

      /*
      int m_errors=0;
      bool m_newMessagesReceived=false;
      bool m_newMessagesTransmitted=false;
      */

   private:

      //CAN_FilterTypeDef sFilterConfig;
      int getBitRate(EBitRate eBitRate)
      {
         return( ( 1000 / eBitRate ) * 1000 );
      }

   public:
      CCan( const SCanConfig &_configData, EBitRate bitRate = e1Mbit );
      ~CCan();
      CRing<SCanMessage> m_rxBuffer;
      #if ! defined STM32
      CRing<SCanMessage> m_txBuffer;
      #endif

      void init(EBitRate bitRate);
      void initHeaders();
      void initFilter();
      void deinit();
      bool calculateRateValues(EBitRate eBitRate, uint32_t &prescaler,
                               uint32_t &seg1, uint32_t &seg2 );
      void putChar(const char ch) const;
      void puts(const char *str) const;

      int transmit(canId_t id, int len, const void *data);
      int transmit(const SCanMessage &message);
      //int transmit(canId_t id, int len, void *data);
      void receive();
      int receive(const SCanMessage &message)
      {
         int sta=m_rxBuffer.putEntry( message ) ? 0 : -1;
         if(sta)
         {
            lCritical("Could not store CAN message");
         }
         return( sta );
      }
      void handleTxError( bool isError );
      int getTransmitStatus(int mailBox) const;
      int getLastError(void) const;

      CAN_HandleTypeDef *getHandle()
      {
       return( m_pHandler );
      }

      void interrupt();
      /*
      int getErrors()
      {
         int errors=m_errors;
         m_errors=0;
         return(errors);
      }
      */
          
      void eventLoop()
      {
         #if 0
         CCanMessage msg;
         SCanMailBox *mailBox;
         while( mailBox = (SCanMailBox *)m_mailBox.getUsedData() )
         {
            #if defined (CAN_IMPLEMENTATION_1)
               msg.setId( (mailBox->RxHeader.IDE==CAN_ID_EXT) ? mailBox->RxHeader.ExtId : mailBox->RxHeader.StdId);
               msg.setData( mailBox->RxHeader.DLC, mailBox->RxData);
            #elif defined (CAN_IMPLEMENTATION_FDCAN)
               msg.setId( mailBox->RxHeader.Identifier );
               msg.setData( mailBox->RxHeader.DataLength, mailBox->RxData );
            #elif defined (CAN_IMPLEMENTATION_VOID)
               msg.setId( mailBox->RxHeader );
               msg.setData( 8, mailBox->RxData );
            #else
               #error Unknown CAN implementation
            #endif

            //printf( "Got CAN-Message with ID %d\n", msg.getId() );
            if ( receive( msg ) < 0 )
            {
               lWarning("CAN receive buffer full");
            }
            m_mailBox.unuseBuffer();
         }
         #endif
         return;
      }
      
      /*
      bool newMessagesReceived()
      {
         bool yes=m_newMessagesReceived;
         m_newMessagesReceived=false;
         return(yes);
      }
      bool newMessagesTransmitted()
      {
         bool yes=m_newMessagesTransmitted;
         m_newMessagesTransmitted=false;
         return(yes);
      }
      */
};


//---fin-----------------------------------------------------------------------
#endif // ? ! BIWAK_CAN_HPP
