/* -----------------------------------------------------------------------------
 * Copyright (c) 2013-2018 Arm Limited
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software. Permission is granted to anyone to use this
 * software for any purpose, including commercial applications, and to alter
 * it and redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software in
 *    a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source distribution.
 *
 *
 * $Date:        11. September 2018
 * $Revision:    V1.9
 *
 * Driver:       Driver_CAN1/2
 * Configured:   via RTE_Device.h configuration file
 * Project:      CAN Driver for ST STM32F1xx
 * --------------------------------------------------------------------------
 * Use the following configuration settings in the middleware component
 * to connect to this driver.
 *
 *   Configuration Setting                 Value   CAN Interface
 *   ---------------------                 -----   -------------
 *   Connect to hardware via Driver_CAN# = 1       use CAN1
 *   Connect to hardware via Driver_CAN# = 2       use CAN2
 * --------------------------------------------------------------------------
 * Defines used for driver configuration (at compile time):
 *
 *   CAN_CLOCK_TOLERANCE:  defines maximum allowed clock tolerance in 1/1024 steps
 *     - default value:    15 (approx. 1.5 %)
 *   CAN1_FILTER_BANK_NUM: defines maximum number of Filter Banks used for CAN1 controller (0..28)
 *                         (sum of maximum number of Filter Banks used for CAN1 and CAN2 must not exceed 28)
 *     - default value:    14
 *   CAN2_FILTER_BANK_NUM: defines maximum number of Filter Banks used for CAN2 controller (0..28)
 *                         (sum of maximum number of Filter Banks used for CAN1 and CAN2 must not exceed 28)
 *     - default value:    14
 * -------------------------------------------------------------------------- */

/* History:
 *  Version 1.9
 *    Corrected MessageSend function to only access required data for sending
 *  Version 1.8
 *    Corrected abort message send functionality (IRQ deadloop)
 *  Version 1.7
 *    Corrected SetBitrate function
 *  Version 1.6
 *    Corrected filter setting for adding/removing maskable Standard ID
 *  Version 1.5
 *    Corrected clearing of overrun flag in interrupt routine
 *  Version 1.4
 *    Corrected CAN2 initialization was disabling CAN1 filters
 *  Version 1.3
 *    Corrected receive overrun signaling
 *  Version 1.2
 *    Corrected functionality when NULL pointer is provided for one or both 
 *    signal callbacks in Initialize function call
 *  Version 1.1
 *    Corrected functionality when only one CAN controller is used
 *    Corrected pin remap configuration for CAN2 port pins
 *  Version 1.0
 *    Initial release
 */


#include "CAN_STM32F10x.h"


// Externally overridable configuration definitions

// Maximum allowed clock tolerance in 1/1024 steps
#ifndef CAN_CLOCK_TOLERANCE
#define CAN_CLOCK_TOLERANCE             (15U)   // 15/1024 approx. 1.5 %
#endif

// Maximum number of Message Objects used for CAN1 controller
#ifndef CAN1_FILTER_BANK_NUM
#define CAN1_FILTER_BANK_NUM            (14UL)
#endif
// Maximum number of Message Objects used for CAN2 controller
#ifndef CAN2_FILTER_BANK_NUM
#define CAN2_FILTER_BANK_NUM            (14UL)
#endif

#if   ((CAN1_FILTER_BANK_NUM + CAN2_FILTER_BANK_NUM) > 28U)
#error  Too many Filter Banks defined, maximum sum of Filter Banks for both CAN1 and CAN2 is 28 !!!
#endif

#define CAN_RX_OBJ_NUM                  (2U)          // Number of receive objects
#define CAN_TX_OBJ_NUM                  (3U)          // Number of transmit objects
#define CAN_TOT_OBJ_NUM                 (CAN_RX_OBJ_NUM + CAN_TX_OBJ_NUM)


// CAN Driver ******************************************************************

#define ARM_CAN_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,9)         // CAN driver version

// Driver Version
static const ARM_DRIVER_VERSION can_driver_version = { ARM_CAN_API_VERSION, ARM_CAN_DRV_VERSION };

// Driver Capabilities
static const ARM_CAN_CAPABILITIES can_driver_capabilities = {
  CAN_TOT_OBJ_NUM,      // Number of CAN Objects available
  1U,                   // Supports reentrant calls to ARM_CAN_MessageSend, ARM_CAN_MessageRead, ARM_CAN_ObjectConfigure and abort message sending used by ARM_CAN_Control.
  0U,                   // Does not support CAN with flexible data-rate mode (CAN_FD)
  0U,                   // Does not support restricted operation mode
  1U,                   // Supports bus monitoring mode
  1U,                   // Supports internal loopback mode
  1U                    // Supports external loopback mode
#if (defined(ARM_CAN_API_VERSION) && (ARM_CAN_API_VERSION >= 0x101U))
, 0U                    // Reserved bits
#endif
};

// Object Capabilities
static const ARM_CAN_OBJ_CAPABILITIES can_object_capabilities_rx = {
  0U,                   // Object does not support transmission
  1U,                   // Object supports reception
  0U,                   // Object does not support RTR reception and automatic Data transmission
  0U,                   // Object does not support RTR transmission and automatic Data reception
  1U,                   // Object allows assignment of multiple filters to it
  1U,                   // Object supports exact identifier filtering
  0U,                   // Object does not support range identifier filtering
  1U,                   // Object supports mask identifier filtering
  3U                    // Object can buffer 3 messages
#if (defined(ARM_CAN_API_VERSION) && (ARM_CAN_API_VERSION >= 0x101U))
, 0U                    // Reserved bits
#endif
};
static const ARM_CAN_OBJ_CAPABILITIES can_object_capabilities_tx = {
  1U,                   // Object supports transmission
  0U,                   // Object does not support reception
  0U,                   // Object does not support RTR reception and automatic Data transmission
  0U,                   // Object does not support RTR transmission and automatic Data reception
  0U,                   // Object does not allow assignment of multiple filters to it
  0U,                   // Object does not support exact identifier filtering
  0U,                   // Object does not support range identifier filtering
  0U,                   // Object does not support mask identifier filtering
  1U                    // Object can only buffer 1 message
#if (defined(ARM_CAN_API_VERSION) && (ARM_CAN_API_VERSION >= 0x101U))
, 0U                    // Reserved bits
#endif
};

#define CAN_FRx_32BIT_IDE               ((uint32_t)1U <<  2)
#define CAN_FRx_32BIT_RTR               ((uint32_t)1U <<  1)
#define CAN_FRx_16BIT_L_IDE             ((uint32_t)1U <<  3)
#define CAN_FRx_16BIT_L_RTR             ((uint32_t)1U <<  4)
#define CAN_FRx_16BIT_H_IDE             ((uint32_t)1U << 19)
#define CAN_FRx_16BIT_H_RTR             ((uint32_t)1U << 20)

typedef enum _CAN_FILTER_TYPE {
  CAN_FILTER_TYPE_EXACT_ID    = 0U,
  CAN_FILTER_TYPE_MASKABLE_ID = 1U
} CAN_FILTER_TYPE;

static CAN_TypeDef * const ptr_CANx[2] = { (CAN_TypeDef *)CAN1, (CAN_TypeDef *)CAN2 };

// Local variables and structures
static uint8_t                     can_driver_powered    [CAN_CTRL_NUM];
static uint8_t                     can_driver_initialized[CAN_CTRL_NUM];
static uint8_t                     can_obj_cfg           [CAN_CTRL_NUM][CAN_TOT_OBJ_NUM];
static ARM_CAN_SignalUnitEvent_t   CAN_SignalUnitEvent   [CAN_CTRL_NUM];
static ARM_CAN_SignalObjectEvent_t CAN_SignalObjectEvent [CAN_CTRL_NUM];


// Helper Functions

/**
  \fn          int32_t CANx_AddFilter (uint32_t obj_idx, CAN_FILTER_TYPE filter_type, uint32_t id, uint32_t mask, uint8_t x)
  \brief       Add receive filter for specified id or id with mask.
  \param[in]   obj_idx      Receive object index assignment
  \param[in]   filter_type  Type of filter to add
                 - CAN_FILTER_TYPE_EXACT_ID:    exact id filter (id only)
                 - CAN_FILTER_TYPE_MASKABLE_ID: maskable filter (id and mask)
  \param[in]   id           Identifier
  \param[in]   mask         Identifier Mask
  \param[in]   x            Controller number (0..1)
  \return      execution status
*/
static int32_t CANx_AddFilter (uint32_t obj_idx, CAN_FILTER_TYPE filter_type, uint32_t id, uint32_t mask, uint8_t x) {
  uint32_t     fa1r, frx, fry, msk;
  uint8_t      bank, bank_end;
  int32_t      status;

  if (x >= CAN_CTRL_NUM)         { return ARM_DRIVER_ERROR;           }
  if (obj_idx >= CAN_RX_OBJ_NUM) { return ARM_DRIVER_ERROR_PARAMETER; }
  if (x == 1U)                   { bank = CAN1_FILTER_BANK_NUM; bank_end = CAN1_FILTER_BANK_NUM + CAN2_FILTER_BANK_NUM; }
  else                           { bank = 0U;                   bank_end = CAN1_FILTER_BANK_NUM;                        }
  if (bank >= bank_end)          { return ARM_DRIVER_ERROR;           }

  status = ARM_DRIVER_OK;
  CAN1->FMR |= CAN_FMR_FINIT;                                           // Enter filter initialization mode

  fa1r = CAN1->FA1R;
  msk  = (uint32_t)1U << bank;

  if ((id & ARM_CAN_ID_IDE_Msk) != 0U) {                                // Extended Identifier
    frx = (id << 3) | CAN_FRx_32BIT_IDE;                                // id + IDE
    switch (filter_type) {
      case CAN_FILTER_TYPE_EXACT_ID:
        fry = (id << 3) | CAN_FRx_32BIT_IDE | CAN_FRx_32BIT_RTR;        // id + IDE + RTR
        while (bank <= bank_end) {                                      // Find empty place for id
          if (bank == bank_end) {                                       // If no free found exit
            status = ARM_DRIVER_ERROR;
            break;
          }
          if ((fa1r & msk) == 0U) {                                     // If filter is not active
            CAN1->FM1R |=  msk;                                         // Select identifier list mode
            CAN1->FS1R |=  msk;                                         // Select single 32-bit scale configuration
            if (obj_idx & 1U) {
              CAN1->FFA1R |=  msk;                                      // Assign to FIFO1
            } else {
              CAN1->FFA1R &= ~msk;                                      // Assign to FIFO0
            }
            CAN1->sFilterRegister[bank].FR1 = frx;                      // id + IDE
            CAN1->sFilterRegister[bank].FR2 = fry;                      // id + IDE + RTR
            break;
          }
          msk <<= 1U;
          bank++;
        }
        break;
      case CAN_FILTER_TYPE_MASKABLE_ID:
        fry = (mask << 3) | CAN_FRx_32BIT_IDE;                          // mask + IDE
        while (bank <= bank_end) {                                      // Find empty place for id
          if (bank == bank_end) {                                       // If no free found exit
            status = ARM_DRIVER_ERROR;
            break;
          }
          if ((fa1r & msk) == 0U) {                                     // If filter is not active
            CAN1->FM1R &= ~msk;                                         // Select identifier mask mode
            CAN1->FS1R |=  msk;                                         // Select single 32-bit scale configuration
            if (obj_idx & 1U) {
              CAN1->FFA1R |=  msk;                                      // Assign to FIFO1
            } else {
              CAN1->FFA1R &= ~msk;                                      // Assign to FIFO0
            }
            CAN1->sFilterRegister[bank].FR1 = frx;                      // id + IDE
            CAN1->sFilterRegister[bank].FR2 = fry;                      // mask + IDE
            break;
          }
          msk <<= 1U;
          bank++;
        }
        break;
      default:
        status = ARM_DRIVER_ERROR_PARAMETER;
        break;
    }
  } else {                                                              // Standard Identifier
    switch (filter_type) {
      case CAN_FILTER_TYPE_EXACT_ID:
        frx = ((id & 0xFFFFU) <<  5) |                                  // Low 16 bits = id
              ((id & 0xFFFFU) << 21) | CAN_FRx_16BIT_H_RTR;             // High 16 bits = id + RTR
        while (bank <= bank_end) {                                      // Find empty place for id
          if (bank == bank_end) {                                       // If no free found exit
            status = ARM_DRIVER_ERROR;
            break;
          }
          if ((fa1r & msk) == 0U) {                                     // If filter is not active
            CAN1->FM1R |=  msk;                                         // Select identifier list mode
            CAN1->FS1R &= ~msk;                                         // Select dual 16-bit scale configuration
            if (obj_idx & 1U) {
              CAN1->FFA1R |=  msk;                                      // Assign to FIFO1
            } else {
              CAN1->FFA1R &= ~msk;                                      // Assign to FIFO0
            }
            CAN1->sFilterRegister[bank].FR1 = frx;
            CAN1->sFilterRegister[bank].FR2 = 0xFFFFFFFFU;              // Disable unused slots
            break;
          } else if  (((CAN1->FM1R & msk) != 0U) &&                     // If identifier list mode
                      ((CAN1->FS1R & msk) == 0U) &&                     // If dual 16-bit scale configuration
                     (((CAN1->FFA1R >> bank) & 1U) == obj_idx)) {       // If bank has same FIFO assignment as requested
            if         (CAN1->sFilterRegister[bank].FR1==0xFFFFFFFFU) { // If n and n+1 entry are not used
              CAN1->FA1R &= ~msk;                                       // Put filter in inactive mode
              CAN1->sFilterRegister[bank].FR1 = frx;                    // id and id + RTR
              break;
            } else if  (CAN1->sFilterRegister[bank].FR2==0xFFFFFFFFU) { // If n+2 and n+3 entry are not used
              CAN1->FA1R &= ~msk;                                       // Put filter in inactive mode
              CAN1->sFilterRegister[bank].FR2 = frx;                    // id and id + RTR
              break;
            }
          }
          msk <<= 1U;
          bank++;
        }
        break;
      case CAN_FILTER_TYPE_MASKABLE_ID:
        frx = ((id   & 0xFFFFU) <<  5) |                                // Low 16 bits = id
              ((mask & 0xFFFFU) << 21) ;                                // High 16 bits = mask
        if ((mask & ARM_CAN_ID_IDE_Msk) != 0U) {                        // If IDE masking enabled
          frx |= CAN_FRx_16BIT_H_RTR;                                   // High 16 bits = mask + IDE
        }
        while (bank <= bank_end) {                                      // Find empty place for id
          if (bank == bank_end) {                                       // If no free found exit
            status = ARM_DRIVER_ERROR;
            break;
          }
          if ((fa1r & msk) == 0U) {                                     // If filter is not active
            CAN1->FM1R &= ~msk;                                         // Select identifier mask mode
            CAN1->FS1R &= ~msk;                                         // Select dual 16-bit scale configuration
            if (obj_idx & 1U) {
              CAN1->FFA1R |=  msk;                                      // Assign to FIFO1
            } else {
              CAN1->FFA1R &= ~msk;                                      // Assign to FIFO0
            }
            CAN1->sFilterRegister[bank].FR1 = frx;
            CAN1->sFilterRegister[bank].FR2 = 0xFFFFFFFFU;              // Disable unused slots
            break;
          } else if ((((CAN1->FM1R | CAN1->FS1R) & msk) == 0U) &&       // If identifier mask mode and dual 16-bit scale configuration
                     (((CAN1->FFA1R >> bank) & 1U) == obj_idx))  {      // If bank has same FIFO assignment as requested
            if         (CAN1->sFilterRegister[bank].FR1==0xFFFFFFFFU) { // If n entry is not used
              CAN1->FA1R &= ~msk;                                       // Put filter in inactive mode
              CAN1->sFilterRegister[bank].FR1 = frx;                    // id and mask
              break;
            } else if  (CAN1->sFilterRegister[bank].FR2==0xFFFFFFFFU) { // If n+1 entry is not used
              CAN1->FA1R &= ~msk;                                       // Put filter in inactive mode
              CAN1->sFilterRegister[bank].FR2 = frx;                    // id and mask
              break;
            }
          }
          msk <<= 1U;
          bank++;
        }
        break;
      default:
        status = ARM_DRIVER_ERROR_PARAMETER;
        break;
    }
  }

  if (status == ARM_DRIVER_OK) {
    CAN1->FA1R |= msk;                                                  // Put filter in active mode
  }
  CAN1->FMR  &= ~CAN_FMR_FINIT;                                         // Exit filter initialization mode

  return status;
}

/**
  \fn          int32_t CANx_RemoveFilter (uint32_t obj_idx, CAN_FILTER_TYPE filter_type, uint32_t id, uint32_t mask, uint8_t x)
  \brief       Remove receive filter for specified id or id with mask.
  \param[in]   obj_idx      Receive object index assignment
  \param[in]   filter_type  Type of filter to remove
                 - CAN_FILTER_TYPE_EXACT_ID:    exact id filter (id only)
                 - CAN_FILTER_TYPE_MASKABLE_ID: maskable filter (id and mask)
  \param[in]   id           Identifier
  \param[in]   mask         Identifier Mask
  \param[in]   x            Controller number (0..1)
  \return      execution status
*/
static int32_t CANx_RemoveFilter (uint32_t obj_idx, CAN_FILTER_TYPE filter_type, uint32_t id, uint32_t mask, uint8_t x) {
  uint32_t     fa1r, frx, fry, msk;
  int32_t      status;
  uint8_t      bank, bank_end;

  if (x >= CAN_CTRL_NUM)         { return ARM_DRIVER_ERROR;           }
  if (obj_idx >= CAN_RX_OBJ_NUM) { return ARM_DRIVER_ERROR_PARAMETER; }
  if (x == 1U)                   { bank = CAN1_FILTER_BANK_NUM; bank_end = CAN1_FILTER_BANK_NUM + CAN2_FILTER_BANK_NUM; }
  else                           { bank = 0U;                   bank_end = CAN1_FILTER_BANK_NUM;                        }
  if (bank >= bank_end)          { return ARM_DRIVER_ERROR;           }

  status = ARM_DRIVER_OK;
  CAN1->FMR |= CAN_FMR_FINIT;                                           // Enter filter initialization mode

  fa1r = CAN1->FA1R;
  msk  = (uint32_t)1U << bank;

  if ((id & ARM_CAN_ID_IDE_Msk) != 0U) {                                // Extended Identifier
    frx = (id << 3) | CAN_FRx_32BIT_IDE;                                // id + IDE
    switch (filter_type) {
      case CAN_FILTER_TYPE_EXACT_ID:
        fry = (id << 3) | CAN_FRx_32BIT_IDE | CAN_FRx_32BIT_RTR;        // id + IDE + RTR
        while (bank <= bank_end) {                                      // Find empty place for id
          if (bank == bank_end) {                                       // If no free found exit
            status = ARM_DRIVER_ERROR;
            break;
          }
          if (((fa1r & msk) != 0U) &&                                   // If filter is active
             (((CAN1->FM1R & CAN1->FS1R) & msk) != 0U) &&               // If identifier list mode and single 32-bit scale configuration
             (((CAN1->FFA1R >> bank) & 1U) == obj_idx) &&               // If bank has same FIFO assignment as requested
             (CAN1->sFilterRegister[bank].FR1 == frx) &&
             (CAN1->sFilterRegister[bank].FR2 == fry)) {
            CAN1->FA1R &= ~msk;                                         // Put filter in inactive mode
            CAN1->sFilterRegister[bank].FR1 = 0xFFFFFFFFU;
            CAN1->sFilterRegister[bank].FR2 = 0xFFFFFFFFU;
            break;
          }
          msk <<= 1U;
          bank++;
       }
        break;
      case CAN_FILTER_TYPE_MASKABLE_ID:
        fry = (mask << 3) | CAN_FRx_32BIT_IDE;                          // mask + IDE
        while (bank <= bank_end) {                                      // Find empty place for id
          if (bank == bank_end) {                                       // If no free found exit
            status = ARM_DRIVER_ERROR;
            break;
          }
          if (((fa1r & msk) != 0U) &&                                   // If filter is active
              ((CAN1->FM1R & msk) == 0U) &&                             // If identifier mask mode
              ((CAN1->FS1R & msk) != 0U) &&                             // If single 32-bit scale configuration
             (((CAN1->FFA1R >> bank) & 1U) == obj_idx)  &&              // If bank has same FIFO assignment as requested
             (CAN1->sFilterRegister[bank].FR1 == frx) &&
             (CAN1->sFilterRegister[bank].FR2 == fry)) {
            CAN1->FA1R &= ~msk;                                         // Put filter in inactive mode
            CAN1->sFilterRegister[bank].FR1 = 0xFFFFFFFFU;
            CAN1->sFilterRegister[bank].FR2 = 0xFFFFFFFFU;
            break;
          }
          msk <<= 1U;
          bank++;
        }
        break;
      default:
        status = ARM_DRIVER_ERROR_PARAMETER;
        break;
    }
  } else {                                                              // Standard Identifier
    switch (filter_type) {
      case CAN_FILTER_TYPE_EXACT_ID:
        frx = ((id & 0xFFFFU) <<  5) |                                  // Low 16 bits = id
              ((id & 0xFFFFU) << 21) | CAN_FRx_16BIT_H_RTR;             // High 16 bits = id + RTR
        while (bank <= bank_end) {                                      // Find empty place for id
          if (bank == bank_end) {                                       // If no free found exit
            status = ARM_DRIVER_ERROR;
            break;
          }
          if (((fa1r & msk) != 0U)&&                                    // If filter is active
              ((CAN1->FM1R & msk) != 0U) &&                             // If identifier list mode
              ((CAN1->FS1R & msk) == 0U) &&                             // If dual 16-bit scale configuration
             (((CAN1->FFA1R >> bank) & 1U) == obj_idx)) {               // If bank has same FIFO assignment as requested
            if        (CAN1->sFilterRegister[bank].FR1 == frx) {
              CAN1->FA1R &= ~msk;                                       // Put filter in inactive mode
              CAN1->sFilterRegister[bank].FR1 = 0xFFFFFFFFU;
              break;
            } else if (CAN1->sFilterRegister[bank].FR2 == frx) {
              CAN1->FA1R &= ~msk;                                       // Put filter in inactive mode
              CAN1->sFilterRegister[bank].FR2 = 0xFFFFFFFFU;
              break;
            }
          }
          msk <<= 1U;
          bank++;
        }
        break;
      case CAN_FILTER_TYPE_MASKABLE_ID:
        frx = ((id   & 0xFFFFU) <<  5) |                                // Low 16 bits = id
              ((mask & 0xFFFFU) << 21) ;                                // High 16 bits = mask
        if ((mask & ARM_CAN_ID_IDE_Msk) != 0U) {                        // If IDE masking enabled
          frx |= CAN_FRx_16BIT_H_IDE;                                   // High 16 bits = mask + IDE
        }
        while (bank <= bank_end) {                                      // Find empty place for id
          if (bank == bank_end) {                                       // If no free found exit
            status = ARM_DRIVER_ERROR;
            break;
          }
          if (((fa1r & msk) != 0U) &&                                   // If filter is active
             (((CAN1->FM1R | CAN1->FS1R) & msk) == 0U) &&               // If identifier mask mode and dual 16-bit scale configuration
             (((CAN1->FFA1R >> bank) & 1U) == obj_idx)) {               // If bank has same FIFO assignment as requested
            if        (CAN1->sFilterRegister[bank].FR1 == frx) {
              CAN1->FA1R &= ~msk;                                       // Put filter in inactive mode
              CAN1->sFilterRegister[bank].FR1 = 0xFFFFFFFFU;
              break;
            } else if (CAN1->sFilterRegister[bank].FR2 == frx) {
              CAN1->FA1R &= ~msk;                                       // Put filter in inactive mode
              CAN1->sFilterRegister[bank].FR2 = 0xFFFFFFFFU;
              break;
            }
          }
          msk <<= 1U;
          bank++;
        }
        break;
      default:
        status = ARM_DRIVER_ERROR_PARAMETER;
        break;
    }
  }

  if ((status == ARM_DRIVER_OK)                         && 
     ((CAN1->sFilterRegister[bank].FR1 != 0xFFFFFFFFU)  || 
      (CAN1->sFilterRegister[bank].FR2 != 0xFFFFFFFFU))) {
    CAN1->FA1R |= msk;                                                  // Put filter in active mode
  }
  CAN1->FMR  &= ~CAN_FMR_FINIT;                                         // Exit filter initialization mode

  return status;
}

// CAN Driver Functions

/**
  \fn          ARM_DRIVER_VERSION CAN_GetVersion (void)
  \brief       Get driver version.
  \return      ARM_DRIVER_VERSION
*/
static ARM_DRIVER_VERSION CAN_GetVersion (void) { return can_driver_version; }

/**
  \fn          ARM_CAN_CAPABILITIES CAN_GetCapabilities (void)
  \brief       Get driver capabilities.
  \return      ARM_CAN_CAPABILITIES
*/
static ARM_CAN_CAPABILITIES CAN_GetCapabilities (void) { return can_driver_capabilities; }

/**
  \fn          int32_t CANx_Initialize (ARM_CAN_SignalUnitEvent_t   cb_unit_event,
                                        ARM_CAN_SignalObjectEvent_t cb_object_event,
                                        uint8_t                     x)
  \brief       Initialize CAN interface and register signal (callback) functions.
  \param[in]   cb_unit_event   Pointer to ARM_CAN_SignalUnitEvent callback function
  \param[in]   cb_object_event Pointer to ARM_CAN_SignalObjectEvent callback function
  \param[in]   x               Controller number (0..1)
  \return      execution status
*/
static int32_t CANx_Initialize (ARM_CAN_SignalUnitEvent_t   cb_unit_event,
                                ARM_CAN_SignalObjectEvent_t cb_object_event,
                                uint8_t                     x) {

  if (x >= CAN_CTRL_NUM)               { return ARM_DRIVER_ERROR; }
  if (can_driver_initialized[x] != 0U) { return ARM_DRIVER_OK;    }

  CAN_SignalUnitEvent  [x] = cb_unit_event;
  CAN_SignalObjectEvent[x] = cb_object_event;

#if (MX_CAN1 == 1U)
  if (x == 0U) {
#if defined (MX_CAN1_RX_Pin)
    GPIO_PortClock    (MX_CAN1_RX_GPIOx, true);
    GPIO_AFConfigure  (MX_CAN1_RX_GPIO_AF);
    GPIO_PinConfigure (MX_CAN1_RX_GPIOx, MX_CAN1_RX_GPIO_Pin, MX_CAN1_RX_GPIO_Conf, MX_CAN1_RX_GPIO_Mode);
#endif
#if defined (MX_CAN1_TX_Pin)
    GPIO_PortClock    (MX_CAN1_TX_GPIOx, true);
    GPIO_AFConfigure  (MX_CAN1_TX_GPIO_AF);
    GPIO_PinConfigure (MX_CAN1_TX_GPIOx, MX_CAN1_TX_GPIO_Pin, MX_CAN1_TX_GPIO_Conf, MX_CAN1_TX_GPIO_Mode);
#endif
  }
#endif
#if (MX_CAN2 == 1U)
  if (x == 1U) {
#if defined (MX_CAN2_RX_Pin)
    GPIO_PortClock    (MX_CAN2_RX_GPIOx, true);
    GPIO_AFConfigure  (MX_CAN2_RX_GPIO_AF);
    GPIO_PinConfigure (MX_CAN2_RX_GPIOx, MX_CAN2_RX_GPIO_Pin, MX_CAN2_RX_GPIO_Conf, MX_CAN2_RX_GPIO_Mode);
#endif
#if defined (MX_CAN2_TX_Pin)
    GPIO_PortClock    (MX_CAN2_TX_GPIOx, true);
    GPIO_AFConfigure  (MX_CAN2_TX_GPIO_AF);
    GPIO_PinConfigure (MX_CAN2_TX_GPIOx, MX_CAN2_TX_GPIO_Pin, MX_CAN2_TX_GPIO_Conf, MX_CAN2_TX_GPIO_Mode);
#endif
  }
#endif

  can_driver_initialized[x] = 1U;

  return ARM_DRIVER_OK;
}
#if (MX_CAN1 == 1U)
static int32_t CAN1_Initialize (ARM_CAN_SignalUnitEvent_t cb_unit_event, ARM_CAN_SignalObjectEvent_t cb_object_event) { return CANx_Initialize (cb_unit_event, cb_object_event, 0U); }
#endif
#if (MX_CAN2 == 1U)
static int32_t CAN2_Initialize (ARM_CAN_SignalUnitEvent_t cb_unit_event, ARM_CAN_SignalObjectEvent_t cb_object_event) { return CANx_Initialize (cb_unit_event, cb_object_event, 1U); }
#endif

/**
  \fn          int32_t CANx_Uninitialize (uint8_t x)
  \brief       De-initialize CAN interface.
  \param[in]   x      Controller number (0..1)
  \return      execution status
*/
static int32_t CANx_Uninitialize (uint8_t x) {

  if (x >= CAN_CTRL_NUM) { return ARM_DRIVER_ERROR; }

#if (MX_CAN1 == 1U)
  if (x == 0U) {
#if defined (MX_CAN1_RX_Pin)
    GPIO_PinConfigure (MX_CAN1_RX_GPIOx, MX_CAN1_RX_GPIO_Pin, GPIO_IN_FLOATING, GPIO_MODE_INPUT);
    GPIO_AFConfigure  (AFIO_CAN_PA11_PA12);
#endif
#if defined (MX_CAN1_TX_Pin)
    GPIO_PinConfigure (MX_CAN1_TX_GPIOx, MX_CAN1_TX_GPIO_Pin, GPIO_IN_FLOATING, GPIO_MODE_INPUT);
    GPIO_AFConfigure  (AFIO_CAN_PA11_PA12);
#endif
  }
#endif
#if (MX_CAN2 == 1U)
  if (x == 1U) {
#if defined (MX_CAN2_RX_Pin)
    GPIO_PinConfigure (MX_CAN2_RX_GPIOx, MX_CAN2_RX_GPIO_Pin, GPIO_IN_FLOATING, GPIO_MODE_INPUT);
    GPIO_AFConfigure  (AFIO_CAN2_NO_REMAP);
#endif
#if defined (MX_CAN2_TX_Pin)
    GPIO_PinConfigure (MX_CAN2_TX_GPIOx, MX_CAN2_TX_GPIO_Pin, GPIO_IN_FLOATING, GPIO_MODE_INPUT);
    GPIO_AFConfigure  (AFIO_CAN2_NO_REMAP);
#endif
  }
#endif

  can_driver_initialized[x] = 0U;

  return ARM_DRIVER_OK;
}
#if (MX_CAN1 == 1U)
static int32_t CAN1_Uninitialize (void) { return CANx_Uninitialize (0U); }
#endif
#if (MX_CAN2 == 1U)
static int32_t CAN2_Uninitialize (void) { return CANx_Uninitialize (1U); }
#endif

/**
  \fn          int32_t CANx_PowerControl (ARM_POWER_STATE state, uint8_t x)
  \brief       Control CAN interface power.
  \param[in]   state  Power state
                 - ARM_POWER_OFF :  power off: no operation possible
                 - ARM_POWER_LOW :  low power mode: retain state, detect and signal wake-up events
                 - ARM_POWER_FULL : power on: full operation at maximum performance
  \param[in]   x      Controller number (0..1)
  \return      execution status
*/
static int32_t CANx_PowerControl (ARM_POWER_STATE state, uint8_t x) {
  CAN_TypeDef *ptr_CAN;
  uint32_t     msk;
  uint8_t      bank, bank_end;

  if (x >= CAN_CTRL_NUM) { return ARM_DRIVER_ERROR; }
  if (x == 1U)           { bank = CAN1_FILTER_BANK_NUM; bank_end = CAN1_FILTER_BANK_NUM + CAN2_FILTER_BANK_NUM; }
  else                   { bank = 0U;                   bank_end = CAN1_FILTER_BANK_NUM;                        }
  if (bank >= bank_end)  { return ARM_DRIVER_ERROR; }

  ptr_CAN = ptr_CANx[x];

  switch (state) {
    case ARM_POWER_OFF:
      can_driver_powered[x] = 0U;
#if (MX_CAN1 == 1U)
      if (x == 0U) {
        NVIC_DisableIRQ (CAN1_TX_IRQn);
        NVIC_DisableIRQ (CAN1_RX0_IRQn);
        NVIC_DisableIRQ (CAN1_RX1_IRQn);
        NVIC_DisableIRQ (CAN1_SCE_IRQn);
      }
#endif
#if (MX_CAN2 == 1U)
      if (x == 1U) {
        NVIC_DisableIRQ (CAN2_TX_IRQn);
        NVIC_DisableIRQ (CAN2_RX0_IRQn);
        NVIC_DisableIRQ (CAN2_RX1_IRQn);
        NVIC_DisableIRQ (CAN2_SCE_IRQn);
      }
#endif

#if (MX_CAN1 == 1U)
      if (x == 0U) {
        // Enable clock for CAN1 peripheral
        RCC->APB1ENR  |=  RCC_APB1ENR_CAN1EN;
      }
#endif
#if (MX_CAN2 == 1U)
      if (x == 1U) {
        // Enable clock for CAN1 and CAN2 peripheral
        RCC->APB1ENR  |=  RCC_APB1ENR_CAN1EN;
        RCC->APB1ENR  |=  RCC_APB1ENR_CAN2EN;
      }
#endif

      ptr_CAN->IER = 0U;                        // Disable Interrupts

      ptr_CAN->MCR = CAN_MCR_RESET;             // Reset CAN controller
      while ((ptr_CAN->MCR & CAN_MCR_RESET) != 0U);

      memset((void *)&can_obj_cfg[x][0], 0, CAN_TOT_OBJ_NUM);

#if (MX_CAN1 == 1U)
      if (x == 0U) {
        RCC->APB1RSTR |=  RCC_APB1RSTR_CAN1RST;
        __NOP(); __NOP(); __NOP(); __NOP(); 
        RCC->APB1ENR  &= ~RCC_APB1ENR_CAN1EN;
      }
#endif
#if (MX_CAN2 == 1U)
      if (x == 1U) {
        RCC->APB1RSTR |=  RCC_APB1RSTR_CAN2RST;
        __NOP(); __NOP(); __NOP(); __NOP(); 
        RCC->APB1ENR  &= ~RCC_APB1ENR_CAN2EN;
#if (MX_CAN1 == 0U)
        RCC->APB1RSTR |=  RCC_APB1RSTR_CAN1RST;
        __NOP(); __NOP(); __NOP(); __NOP(); 
        RCC->APB1ENR  &= ~RCC_APB1ENR_CAN1EN;
#endif
      }
#endif
      break;

    case ARM_POWER_FULL:
      if (can_driver_initialized[x] == 0U) { return ARM_DRIVER_ERROR; }
      if (can_driver_powered[x]     != 0U) { return ARM_DRIVER_OK;    }

#if (MX_CAN1 == 1U)
      if (x == 0U) {
        RCC->APB1ENR  |=  RCC_APB1ENR_CAN1EN;
        RCC->APB1RSTR |=  RCC_APB1RSTR_CAN1RST;
        __NOP(); __NOP(); __NOP(); __NOP(); 
        RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN1RST;
      }
#endif
#if (MX_CAN2 == 1U)
      if (x == 1U) {
        RCC->APB1ENR  |=  RCC_APB1ENR_CAN2EN;
        RCC->APB1RSTR |=  RCC_APB1RSTR_CAN2RST;
        __NOP(); __NOP(); __NOP(); __NOP(); 
        RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN2RST;
        if ((RCC->APB1ENR & RCC_APB1ENR_CAN1EN) == 0U) {
          // If CAN1 (master) clock is not enabled, enable it as it is necessary for filter operation
          RCC->APB1ENR  |=  RCC_APB1ENR_CAN1EN;
          RCC->APB1RSTR |=  RCC_APB1RSTR_CAN1RST;
          __NOP(); __NOP(); __NOP(); __NOP(); 
          RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN1RST;
        }
      }
#endif

      ptr_CAN->MCR = CAN_MCR_RESET;             // Reset CAN controller
      while ((ptr_CAN->MCR & CAN_MCR_RESET) != 0U);

      // Initialize filter banks
      CAN1->FMR   =  CAN_FMR_FINIT | (CAN1_FILTER_BANK_NUM << 8);
      msk         =  ((uint32_t)1U << bank_end) - ((uint32_t)1U << bank);
      CAN1->FMR  |=  CAN_FMR_FINIT;             // Enter filter initialization mode
      CAN1->FA1R &= ~msk;                       // Put all filters in inactive mode
      CAN1->FM1R &= ~msk;                       // Initialize all filters mode
      CAN1->FS1R &= ~msk;                       // Initialize all filters scale configuration
      while (bank <= bank_end) {                // Go through all banks
        if (bank == bank_end) { break; }
        CAN1->sFilterRegister[bank].FR1 = 0U;
        CAN1->sFilterRegister[bank].FR2 = 0U;
        bank++;
      }

      memset((void *)&can_obj_cfg[x][0], 0, CAN_TOT_OBJ_NUM);

      ptr_CAN->IER =   CAN_IER_TMEIE  |         // Enable Interrupts
                       CAN_IER_FMPIE0 |
                       CAN_IER_FOVIE0 |
                       CAN_IER_FMPIE1 |
                       CAN_IER_FOVIE1 |
                       CAN_IER_EWGIE  |
                       CAN_IER_EPVIE  |
                       CAN_IER_BOFIE  |
                       CAN_IER_ERRIE  ;

      can_driver_powered[x] = 1U;

#if (MX_CAN1 == 1U)
      if (x == 0U) {
        if ((CAN_SignalUnitEvent[0] != NULL) || (CAN_SignalObjectEvent[0] != NULL)) {
          NVIC_ClearPendingIRQ (CAN1_TX_IRQn);
          NVIC_EnableIRQ       (CAN1_TX_IRQn);
          NVIC_ClearPendingIRQ (CAN1_RX0_IRQn);
          NVIC_EnableIRQ       (CAN1_RX0_IRQn);
          NVIC_ClearPendingIRQ (CAN1_RX1_IRQn);
          NVIC_EnableIRQ       (CAN1_RX1_IRQn);
        }
        if (CAN_SignalUnitEvent[0] != NULL) {
          NVIC_ClearPendingIRQ (CAN1_SCE_IRQn);
          NVIC_EnableIRQ       (CAN1_SCE_IRQn);
        }
      }
#endif
#if (MX_CAN2 == 1U)
      if (x == 1U) {
        if ((CAN_SignalUnitEvent[1] != NULL) || (CAN_SignalObjectEvent[1] != NULL)) {
          NVIC_ClearPendingIRQ (CAN2_TX_IRQn);
          NVIC_EnableIRQ       (CAN2_TX_IRQn);
          NVIC_ClearPendingIRQ (CAN2_RX0_IRQn);
          NVIC_EnableIRQ       (CAN2_RX0_IRQn);
          NVIC_ClearPendingIRQ (CAN2_RX1_IRQn);
          NVIC_EnableIRQ       (CAN2_RX1_IRQn);
        }
        if (CAN_SignalUnitEvent[1] != NULL) {
          NVIC_ClearPendingIRQ (CAN2_SCE_IRQn);
          NVIC_EnableIRQ       (CAN2_SCE_IRQn);
        }
      }
#endif
      break;

    default:
      return ARM_DRIVER_ERROR_UNSUPPORTED;
  }

  return ARM_DRIVER_OK;
}
#if (MX_CAN1 == 1U)
static int32_t CAN1_PowerControl (ARM_POWER_STATE state) { return CANx_PowerControl (state, 0U); }
#endif
#if (MX_CAN2 == 1U)
static int32_t CAN2_PowerControl (ARM_POWER_STATE state) { return CANx_PowerControl (state, 1U); }
#endif

/**
  \fn          uint32_t CAN_GetClock (void)
  \brief       Retrieve CAN base clock frequency.
  \return      base clock frequency
*/
uint32_t CAN_GetClock (void) {
  return RTE_PCLK1;
}

/**
  \fn          int32_t CANx_SetBitrate (ARM_CAN_BITRATE_SELECT select, uint32_t bitrate, uint32_t bit_segments, uint8_t x)
  \brief       Set bitrate for CAN interface.
  \param[in]   select       Bitrate selection
                 - ARM_CAN_BITRATE_NOMINAL : nominal (flexible data-rate arbitration) bitrate
                 - ARM_CAN_BITRATE_FD_DATA : flexible data-rate data bitrate
  \param[in]   bitrate      Bitrate
  \param[in]   bit_segments Bit segments settings
  \param[in]   x            Controller number (0..1)
  \return      execution status
*/
static int32_t CANx_SetBitrate (ARM_CAN_BITRATE_SELECT select, uint32_t bitrate, uint32_t bit_segments, uint8_t x) {
  CAN_TypeDef *ptr_CAN;
  uint32_t     mcr, sjw, prop_seg, phase_seg1, phase_seg2, pclk, brp, tq_num;

  if (x >= CAN_CTRL_NUM)                 { return ARM_DRIVER_ERROR;               }
  if (select != ARM_CAN_BITRATE_NOMINAL) { return ARM_CAN_INVALID_BITRATE_SELECT; }
  if (can_driver_powered[x] == 0U)       { return ARM_DRIVER_ERROR;               }

  prop_seg   = (bit_segments & ARM_CAN_BIT_PROP_SEG_Msk  ) >> ARM_CAN_BIT_PROP_SEG_Pos;
  phase_seg1 = (bit_segments & ARM_CAN_BIT_PHASE_SEG1_Msk) >> ARM_CAN_BIT_PHASE_SEG1_Pos;
  phase_seg2 = (bit_segments & ARM_CAN_BIT_PHASE_SEG2_Msk) >> ARM_CAN_BIT_PHASE_SEG2_Pos;
  sjw        = (bit_segments & ARM_CAN_BIT_SJW_Msk       ) >> ARM_CAN_BIT_SJW_Pos;

  if (((prop_seg + phase_seg1) < 1U) || ((prop_seg + phase_seg1) > 16U)) { return ARM_CAN_INVALID_BIT_PROP_SEG;   }
  if (( phase_seg2             < 1U) || ( phase_seg2             >  8U)) { return ARM_CAN_INVALID_BIT_PHASE_SEG2; }
  if (( sjw                    < 1U) || ( sjw                    >  4U)) { return ARM_CAN_INVALID_BIT_SJW;        }

  ptr_CAN = ptr_CANx[x];

  tq_num = 1U + prop_seg + phase_seg1 + phase_seg2;
  pclk   = CAN_GetClock ();           if (pclk == 0U)  { return ARM_DRIVER_ERROR;        }
  brp    = pclk / (tq_num * bitrate); if (brp > 1024U) { return ARM_CAN_INVALID_BITRATE; }
  if (pclk > (brp * tq_num * bitrate)) {
    if ((((pclk - (brp * tq_num * bitrate)) * 1024U) / pclk) > CAN_CLOCK_TOLERANCE) { return ARM_CAN_INVALID_BITRATE; }
  } else if (pclk < (brp * tq_num * bitrate)) {
    if (((((brp * tq_num * bitrate) - pclk) * 1024U) / pclk) > CAN_CLOCK_TOLERANCE) { return ARM_CAN_INVALID_BITRATE; }
  }

  mcr = ptr_CAN->MCR;
  ptr_CAN->MCR = CAN_MCR_INRQ;                  // Activate initialization mode
  while ((ptr_CAN->MSR&CAN_MSR_INAK) == 0U);    // Wait to enter initialization mode

  ptr_CAN->BTR = ((brp - 1U) & CAN_BTR_BRP) | ((sjw - 1U) << 24) | ((phase_seg2 - 1U) << 20) | ((prop_seg + phase_seg1 - 1U) << 16);
  ptr_CAN->MCR =  mcr;                          // Return to previous mode

  return ARM_DRIVER_OK;
}
#if (MX_CAN1 == 1U)
static int32_t CAN1_SetBitrate (ARM_CAN_BITRATE_SELECT select, uint32_t bitrate, uint32_t bit_segments) { return CANx_SetBitrate (select, bitrate, bit_segments, 0U); }
#endif
#if (MX_CAN2 == 1U)
static int32_t CAN2_SetBitrate (ARM_CAN_BITRATE_SELECT select, uint32_t bitrate, uint32_t bit_segments) { return CANx_SetBitrate (select, bitrate, bit_segments, 1U); }
#endif

/**
  \fn          int32_t CANx_SetMode (ARM_CAN_MODE mode, uint8_t x)
  \brief       Set operating mode for CAN interface.
  \param[in]   mode   Operating mode
                 - ARM_CAN_MODE_INITIALIZATION :    initialization mode
                 - ARM_CAN_MODE_NORMAL :            normal operation mode
                 - ARM_CAN_MODE_RESTRICTED :        restricted operation mode
                 - ARM_CAN_MODE_MONITOR :           bus monitoring mode
                 - ARM_CAN_MODE_LOOPBACK_INTERNAL : loopback internal mode
                 - ARM_CAN_MODE_LOOPBACK_EXTERNAL : loopback external mode
  \param[in]   x      Controller number (0..1)
  \return      execution status
*/
static int32_t CANx_SetMode (ARM_CAN_MODE mode, uint8_t x) {
  CAN_TypeDef *ptr_CAN;
  uint32_t     event;

  if (x >= CAN_CTRL_NUM) { return ARM_DRIVER_ERROR; }

  ptr_CAN = ptr_CANx[x];

  event = 0U;
  switch (mode) {
    case ARM_CAN_MODE_INITIALIZATION:
      CAN1->FMR    |=  CAN_FMR_FINIT;           // Filter initialization mode
      ptr_CAN->MCR  =  CAN_MCR_INRQ;            // Enter initialization mode
      while ((ptr_CAN->MSR&CAN_MSR_INAK)==0U);  // Wait to enter initialization mode
      event = ARM_CAN_EVENT_UNIT_BUS_OFF;
      break;
    case ARM_CAN_MODE_NORMAL:
      ptr_CAN->BTR &=~(CAN_BTR_LBKM | CAN_BTR_SILM);
      ptr_CAN->MCR  =  CAN_MCR_ABOM |           // Activate automatic bus-off
                       CAN_MCR_AWUM ;           // Enable automatic wakeup mode
      while ((ptr_CAN->MSR&CAN_MSR_INAK)!=0U);  // Wait to exit initialization mode
      CAN1->FMR    &= ~CAN_FMR_FINIT;           // Filter active mode
      event = ARM_CAN_EVENT_UNIT_ACTIVE;
      break;
    case ARM_CAN_MODE_RESTRICTED:
      return ARM_DRIVER_ERROR_UNSUPPORTED;
    case ARM_CAN_MODE_MONITOR:
      ptr_CAN->MCR |=  CAN_MCR_INRQ;            // Enter initialization mode
      while ((ptr_CAN->MSR&CAN_MSR_INAK)==0U);  // Wait to enter initialization mode
      ptr_CAN->BTR &= ~CAN_BTR_LBKM;            // Deactivate loopback
      ptr_CAN->BTR |=  CAN_BTR_SILM;            // Activate silent
      ptr_CAN->MCR &= ~CAN_MCR_INRQ;            // Deactivate initialization mode
      while ((ptr_CAN->MSR&CAN_MSR_INAK)!=0U);  // Wait to exit initialization mode
      event = ARM_CAN_EVENT_UNIT_PASSIVE;
      break;
    case ARM_CAN_MODE_LOOPBACK_INTERNAL:
      ptr_CAN->MCR |=  CAN_MCR_INRQ;            // Enter initialization mode
      while ((ptr_CAN->MSR&CAN_MSR_INAK)==0U);  // Wait to enter initialization mode
      ptr_CAN->BTR |=  CAN_BTR_LBKM;            // Activate loopback
      ptr_CAN->BTR |=  CAN_BTR_SILM;            // Activate silent
      ptr_CAN->MCR &= ~CAN_MCR_INRQ;            // Deactivate initialization mode
      while ((ptr_CAN->MSR&CAN_MSR_INAK)!=0U);  // Wait to exit initialization mode
      event = ARM_CAN_EVENT_UNIT_PASSIVE;
      break;
    case ARM_CAN_MODE_LOOPBACK_EXTERNAL:
      ptr_CAN->MCR |=  CAN_MCR_INRQ;            // Enter initialization mode
      while ((ptr_CAN->MSR&CAN_MSR_INAK)==0U);  // Wait to enter initialization mode
      ptr_CAN->BTR &= ~CAN_BTR_SILM;            // Deactivate silent
      ptr_CAN->BTR |=  CAN_BTR_LBKM;            // Activate loopback
      ptr_CAN->MCR &= ~CAN_MCR_INRQ;            // Deactivate initialization mode
      while ((ptr_CAN->MSR&CAN_MSR_INAK)!=0U);  // Wait to exit initialization mode
      event = ARM_CAN_EVENT_UNIT_ACTIVE;
      break;
    default:
      return ARM_DRIVER_ERROR_PARAMETER;
  }
  if ((CAN_SignalUnitEvent[x] != NULL) && (event != 0U)) { CAN_SignalUnitEvent[x](event); }

  return ARM_DRIVER_OK;
}
#if (MX_CAN1 == 1U)
static int32_t CAN1_SetMode (ARM_CAN_MODE mode) { return CANx_SetMode (mode, 0U); }
#endif
#if (MX_CAN2 == 1U)
static int32_t CAN2_SetMode (ARM_CAN_MODE mode) { return CANx_SetMode (mode, 1U); }
#endif

/**
  \fn          ARM_CAN_OBJ_CAPABILITIES CANx_ObjectGetCapabilities (uint32_t obj_idx, uint8_t x)
  \brief       Retrieve capabilities of an object.
  \param[in]   obj_idx  Object index
  \param[in]   x        Controller number (0..1)
  \return      ARM_CAN_OBJ_CAPABILITIES
*/
ARM_CAN_OBJ_CAPABILITIES CANx_ObjectGetCapabilities (uint32_t obj_idx, uint8_t x) {
  ARM_CAN_OBJ_CAPABILITIES obj_cap_null;

  if ((x >= CAN_CTRL_NUM) || (obj_idx >= CAN_TOT_OBJ_NUM)) {
    memset ((void *)&obj_cap_null, 0, sizeof(ARM_CAN_OBJ_CAPABILITIES));
    return obj_cap_null;
  }

  if (obj_idx >= CAN_RX_OBJ_NUM) {
    return can_object_capabilities_tx;
  } else {
    return can_object_capabilities_rx;
  }
}
#if (MX_CAN1 == 1U)
ARM_CAN_OBJ_CAPABILITIES CAN1_ObjectGetCapabilities (uint32_t obj_idx) { return CANx_ObjectGetCapabilities (obj_idx, 0U); }
#endif
#if (MX_CAN2 == 1U)
ARM_CAN_OBJ_CAPABILITIES CAN2_ObjectGetCapabilities (uint32_t obj_idx) { return CANx_ObjectGetCapabilities (obj_idx, 1U); }
#endif

/**
  \fn          int32_t CANx_ObjectSetFilter (uint32_t obj_idx, ARM_CAN_FILTER_OPERATION operation, uint32_t id, uint32_t arg, uint8_t x)
  \brief       Add or remove filter for message reception.
  \param[in]   obj_idx      Object index of object that filter should be or is assigned to
  \param[in]   operation    Operation on filter
                 - ARM_CAN_FILTER_ID_EXACT_ADD :       add    exact id filter
                 - ARM_CAN_FILTER_ID_EXACT_REMOVE :    remove exact id filter
                 - ARM_CAN_FILTER_ID_RANGE_ADD :       add    range id filter
                 - ARM_CAN_FILTER_ID_RANGE_REMOVE :    remove range id filter
                 - ARM_CAN_FILTER_ID_MASKABLE_ADD :    add    maskable id filter
                 - ARM_CAN_FILTER_ID_MASKABLE_REMOVE : remove maskable id filter
  \param[in]   id           ID or start of ID range (depending on filter type)
  \param[in]   arg          Mask or end of ID range (depending on filter type)
  \param[in]   x            Controller number (0..1)
  \return      execution status
*/
static int32_t CANx_ObjectSetFilter (uint32_t obj_idx, ARM_CAN_FILTER_OPERATION operation, uint32_t id, uint32_t arg, uint8_t x) {
  int32_t status;

  if (x >= CAN_CTRL_NUM)           { return ARM_DRIVER_ERROR;           }
  if (obj_idx >= CAN_RX_OBJ_NUM)   { return ARM_DRIVER_ERROR_PARAMETER; }
  if (can_driver_powered[x] == 0U) { return ARM_DRIVER_ERROR;           }

  CAN1->FMR |=  CAN_FMR_FINIT;          // Filter initialization mode

  switch (operation) {
    case ARM_CAN_FILTER_ID_EXACT_ADD:
      status = CANx_AddFilter   (obj_idx, CAN_FILTER_TYPE_EXACT_ID,    id,  0U, x);
      break;
    case ARM_CAN_FILTER_ID_MASKABLE_ADD:
      status = CANx_AddFilter   (obj_idx, CAN_FILTER_TYPE_MASKABLE_ID, id, arg, x);
      break;
    case ARM_CAN_FILTER_ID_EXACT_REMOVE:
      status = CANx_RemoveFilter(obj_idx, CAN_FILTER_TYPE_EXACT_ID,    id,  0U, x);
      break;
    case ARM_CAN_FILTER_ID_MASKABLE_REMOVE:
      status = CANx_RemoveFilter(obj_idx, CAN_FILTER_TYPE_MASKABLE_ID, id, arg, x);
      break;
    case ARM_CAN_FILTER_ID_RANGE_ADD:
    case ARM_CAN_FILTER_ID_RANGE_REMOVE:
    default:
      status = ARM_DRIVER_ERROR_UNSUPPORTED;
      break;
  }
  CAN1->FMR &= ~CAN_FMR_FINIT;          // Filter active mode

  return status;
}
#if (MX_CAN1 == 1U)
static int32_t CAN1_ObjectSetFilter (uint32_t obj_idx, ARM_CAN_FILTER_OPERATION operation, uint32_t id, uint32_t arg) { return CANx_ObjectSetFilter (obj_idx, operation, id, arg, 0U); }
#endif
#if (MX_CAN2 == 1U)
static int32_t CAN2_ObjectSetFilter (uint32_t obj_idx, ARM_CAN_FILTER_OPERATION operation, uint32_t id, uint32_t arg) { return CANx_ObjectSetFilter (obj_idx, operation, id, arg, 1U); }
#endif

/**
  \fn          int32_t CANx_ObjectConfigure (uint32_t obj_idx, ARM_CAN_OBJ_CONFIG obj_cfg, uint8_t x)
  \brief       Configure object.
  \param[in]   obj_idx  Object index
  \param[in]   obj_cfg  Object configuration state
                 - ARM_CAN_OBJ_INACTIVE :       deactivate object
                 - ARM_CAN_OBJ_RX :             configure object for reception
                 - ARM_CAN_OBJ_TX :             configure object for transmission
                 - ARM_CAN_OBJ_RX_RTR_TX_DATA : configure object that on RTR reception automatically transmits Data Frame
                 - ARM_CAN_OBJ_TX_RTR_RX_DATA : configure object that transmits RTR and automatically receives Data Frame
  \param[in]   x        Controller number (0..1)
  \return      execution status
*/
static int32_t CANx_ObjectConfigure (uint32_t obj_idx, ARM_CAN_OBJ_CONFIG obj_cfg, uint8_t x) {

  if (x >= CAN_CTRL_NUM)           { return ARM_DRIVER_ERROR;           }
  if (obj_idx >= CAN_TOT_OBJ_NUM)  { return ARM_DRIVER_ERROR_PARAMETER; }
  if (can_driver_powered[x] == 0U) { return ARM_DRIVER_ERROR;           }

  switch (obj_cfg) {
    case ARM_CAN_OBJ_INACTIVE:
      can_obj_cfg[x][obj_idx] = ARM_CAN_OBJ_INACTIVE;
      break;
    case ARM_CAN_OBJ_RX_RTR_TX_DATA:
    case ARM_CAN_OBJ_TX_RTR_RX_DATA:
      can_obj_cfg[x][obj_idx] = ARM_CAN_OBJ_INACTIVE;
      return ARM_DRIVER_ERROR_UNSUPPORTED;
    case ARM_CAN_OBJ_TX:
      if (obj_idx < CAN_RX_OBJ_NUM)  { return ARM_DRIVER_ERROR_PARAMETER; }
      can_obj_cfg[x][obj_idx] = ARM_CAN_OBJ_TX;
      break;
    case ARM_CAN_OBJ_RX:
      if (obj_idx >= CAN_RX_OBJ_NUM) { return ARM_DRIVER_ERROR_PARAMETER; }
      can_obj_cfg[x][obj_idx] = ARM_CAN_OBJ_RX;
      break;
    default:
      return ARM_DRIVER_ERROR;
  }

  return ARM_DRIVER_OK;
}
#if (MX_CAN1 == 1U)
static int32_t CAN1_ObjectConfigure (uint32_t obj_idx, ARM_CAN_OBJ_CONFIG obj_cfg) { return CANx_ObjectConfigure (obj_idx, obj_cfg, 0U); }
#endif
#if (MX_CAN2 == 1U)
static int32_t CAN2_ObjectConfigure (uint32_t obj_idx, ARM_CAN_OBJ_CONFIG obj_cfg) { return CANx_ObjectConfigure (obj_idx, obj_cfg, 1U); }
#endif

/**
  \fn          int32_t CANx_MessageSend (uint32_t obj_idx, ARM_CAN_MSG_INFO *msg_info, const uint8_t *data, uint8_t size, uint8_t x)
  \brief       Send message on CAN bus.
  \param[in]   obj_idx  Object index
  \param[in]   msg_info Pointer to CAN message information
  \param[in]   data     Pointer to data buffer
  \param[in]   size     Number of data bytes to send
  \param[in]   x        Controller number (0..1)
  \return      value >= 0  number of data bytes accepted to send
  \return      value < 0   execution status
*/
static int32_t CANx_MessageSend (uint32_t obj_idx, ARM_CAN_MSG_INFO *msg_info, const uint8_t *data, uint8_t size, uint8_t x) {
  CAN_TypeDef *ptr_CAN;
  uint32_t     data_tx[2];
  uint32_t     tir;

  if (x >= CAN_CTRL_NUM)                                          { return ARM_DRIVER_ERROR;           }
  if ((obj_idx < CAN_RX_OBJ_NUM) || (obj_idx >= CAN_TOT_OBJ_NUM)) { return ARM_DRIVER_ERROR_PARAMETER; }
  if (can_driver_powered[x] == 0U)                                { return ARM_DRIVER_ERROR;           }
  if (can_obj_cfg[x][obj_idx] != ARM_CAN_OBJ_TX)                  { return ARM_DRIVER_ERROR;           }

  obj_idx -= CAN_RX_OBJ_NUM;                            // obj_idx origin to 0

  ptr_CAN  = ptr_CANx[x];

  if ((ptr_CAN->sTxMailBox[obj_idx].TIR & CAN_TI0R_TXRQ) != 0U) { return ARM_DRIVER_ERROR_BUSY; }

  if ((msg_info->id & ARM_CAN_ID_IDE_Msk) != 0U) {      // Extended Identifier
    tir = (msg_info->id <<  3) | CAN_TI0R_IDE;
  } else {                                              // Standard Identifier
    tir = (msg_info->id << 21);
  }

  if (size > 8U) { size = 8U; }

  if (msg_info->rtr != 0U) {                            // If send RTR requested
    size = 0U;
    tir |= CAN_TI0R_RTR;

    ptr_CAN->sTxMailBox[obj_idx].TDTR &= ~CAN_TDT0R_DLC;
    ptr_CAN->sTxMailBox[obj_idx].TDTR |=  msg_info->dlc & CAN_TDT0R_DLC;
  } else {
    if (size != 8U) {
      data_tx[0] = 0U;
      data_tx[1] = 0U;
    }
    memcpy((uint8_t *)(&data_tx[0]), data, size);

    ptr_CAN->sTxMailBox[obj_idx].TDLR = data_tx[0];
    ptr_CAN->sTxMailBox[obj_idx].TDHR = data_tx[1];

    ptr_CAN->sTxMailBox[obj_idx].TDTR &= ~CAN_TDT0R_DLC;
    ptr_CAN->sTxMailBox[obj_idx].TDTR |=  size & CAN_TDT0R_DLC;
  }

  ptr_CAN->sTxMailBox[obj_idx].TIR   =  tir | CAN_TI0R_TXRQ;    // Activate transmit

  return ((int32_t)size);
}
#if (MX_CAN1 == 1U)
static int32_t CAN1_MessageSend (uint32_t obj_idx, ARM_CAN_MSG_INFO *msg_info, const uint8_t *data, uint8_t size) { return CANx_MessageSend (obj_idx, msg_info, data, size, 0U); }
#endif
#if (MX_CAN2 == 1U)
static int32_t CAN2_MessageSend (uint32_t obj_idx, ARM_CAN_MSG_INFO *msg_info, const uint8_t *data, uint8_t size) { return CANx_MessageSend (obj_idx, msg_info, data, size, 1U); }
#endif

/**
  \fn          int32_t CANx_MessageRead (uint32_t obj_idx, ARM_CAN_MSG_INFO *msg_info, uint8_t *data, uint8_t size, uint8_t x)
  \brief       Read message received on CAN bus.
  \param[in]   obj_idx  Object index
  \param[out]  msg_info Pointer to read CAN message information
  \param[out]  data     Pointer to data buffer for read data
  \param[in]   size     Maximum number of data bytes to read
  \param[in]   x        Controller number (0..1)
  \return      value >= 0  number of data bytes read
  \return      value < 0   execution status
*/
static int32_t CANx_MessageRead (uint32_t obj_idx, ARM_CAN_MSG_INFO *msg_info, uint8_t *data, uint8_t size, uint8_t x) {
  CAN_TypeDef *ptr_CAN;
  uint32_t     data_rx[2][2];

  if (x >= CAN_CTRL_NUM)                         { return ARM_DRIVER_ERROR;           }
  if (obj_idx >= CAN_RX_OBJ_NUM)                 { return ARM_DRIVER_ERROR_PARAMETER; }
  if (can_driver_powered[x] == 0U)               { return ARM_DRIVER_ERROR;           }
  if (can_obj_cfg[x][obj_idx] != ARM_CAN_OBJ_RX) { return ARM_DRIVER_ERROR;           }

  ptr_CAN = ptr_CANx[x];

  if (size > 8U) { size = 8U; }

  if ((ptr_CAN->sFIFOMailBox[obj_idx].RIR & CAN_RI0R_IDE) != 0U) {      // Extended Identifier
    msg_info->id = (0x1FFFFFFFUL & (ptr_CAN->sFIFOMailBox[obj_idx].RIR >>  3)) | ARM_CAN_ID_IDE_Msk;
  } else {                                              // Standard Identifier
    msg_info->id = (    0x07FFUL & (ptr_CAN->sFIFOMailBox[obj_idx].RIR >> 21));
  }

  if ((ptr_CAN->sFIFOMailBox[obj_idx].RIR & CAN_RI0R_RTR) != 0U) {
    msg_info->rtr = 1U;
    size          = 0U;
  } else {
    msg_info->rtr = 0U;
  }

  msg_info->dlc = ptr_CAN->sFIFOMailBox[obj_idx].RDTR & CAN_RDT0R_DLC;

  if (size > 0U) {
    data_rx[x][0] = ptr_CAN->sFIFOMailBox[obj_idx].RDLR;
    data_rx[x][1] = ptr_CAN->sFIFOMailBox[obj_idx].RDHR;

    memcpy(data, (uint8_t *)(&data_rx[x][0]), size);
  }

  if (obj_idx == 1U) {
    ptr_CAN->RF1R = CAN_RF1R_RFOM1;                     // Release FIFO 1 output mailbox
  } else {
    ptr_CAN->RF0R = CAN_RF0R_RFOM0;                     // Release FIFO 0 output mailbox
  }

  return ((int32_t)size);
}
#if (MX_CAN1 == 1U)
static int32_t CAN1_MessageRead (uint32_t obj_idx, ARM_CAN_MSG_INFO *msg_info, uint8_t *data, uint8_t size) { return CANx_MessageRead (obj_idx, msg_info, data, size, 0U); }
#endif
#if (MX_CAN2 == 1U)
static int32_t CAN2_MessageRead (uint32_t obj_idx, ARM_CAN_MSG_INFO *msg_info, uint8_t *data, uint8_t size) { return CANx_MessageRead (obj_idx, msg_info, data, size, 1U); }
#endif

/**
  \fn          int32_t CANx_Control (uint32_t control, uint32_t arg, uint8_t x)
  \brief       Control CAN interface.
  \param[in]   control  Operation
                 - ARM_CAN_SET_FD_MODE :            set FD operation mode
                 - ARM_CAN_ABORT_MESSAGE_SEND :     abort sending of CAN message
                 - ARM_CAN_CONTROL_RETRANSMISSION : enable/disable automatic retransmission
                 - ARM_CAN_SET_TRANSCEIVER_DELAY :  set transceiver delay
  \param[in]   arg      Argument of operation
  \param[in]   x        Controller number (0..1)
  \return      execution status
*/
static int32_t CANx_Control (uint32_t control, uint32_t arg, uint8_t x) {
  CAN_TypeDef *ptr_CAN;

  if (x >= CAN_CTRL_NUM)           { return ARM_DRIVER_ERROR; }
  if (can_driver_powered[x] == 0U) { return ARM_DRIVER_ERROR; }

  ptr_CAN = ptr_CANx[x];

  switch (control & ARM_CAN_CONTROL_Msk) {
    case ARM_CAN_ABORT_MESSAGE_SEND:
      if ((arg < CAN_RX_OBJ_NUM) || (arg >= CAN_TOT_OBJ_NUM)) { return ARM_DRIVER_ERROR_PARAMETER; }
      arg -= CAN_RX_OBJ_NUM;
      switch (arg) {
        case 0:
          ptr_CAN->TSR = CAN_TSR_ABRQ0;
          break;
        case 1:
          ptr_CAN->TSR = CAN_TSR_ABRQ1;
          break;
        case 2:
          ptr_CAN->TSR = CAN_TSR_ABRQ2;
          break;
        default:
          return ARM_DRIVER_ERROR_PARAMETER;
      }
      break;
    case ARM_CAN_CONTROL_RETRANSMISSION:
      switch (arg) {
        case 0:
          ptr_CAN->MCR |=  CAN_MCR_NART;
          break;
        case 1:
          ptr_CAN->MCR &= ~CAN_MCR_NART;
          break;
        default:
          return ARM_DRIVER_ERROR_PARAMETER;
      }
      break;
    case ARM_CAN_SET_FD_MODE:
    case ARM_CAN_SET_TRANSCEIVER_DELAY:
    default:
      return ARM_DRIVER_ERROR_UNSUPPORTED;
  }

  return ARM_DRIVER_OK;
}
#if (MX_CAN1 == 1U)
static int32_t CAN1_Control (uint32_t control, uint32_t arg) { return CANx_Control (control, arg, 0U); }
#endif
#if (MX_CAN2 == 1U)
static int32_t CAN2_Control (uint32_t control, uint32_t arg) { return CANx_Control (control, arg, 1U); }
#endif

/**
  \fn          ARM_CAN_STATUS CANx_GetStatus (uint8_t x)
  \brief       Get CAN status.
  \param[in]   x      Controller number (0..1)
  \return      CAN status ARM_CAN_STATUS
*/
static ARM_CAN_STATUS CANx_GetStatus (uint8_t x) {
  CAN_TypeDef    *ptr_CAN;
  ARM_CAN_STATUS  can_status;
  uint32_t        esr;

  ptr_CAN      = ptr_CANx[x];
  esr          = ptr_CAN->ESR;
  ptr_CAN->ESR = CAN_ESR_LEC;           // Software set last error code to unused value

  if       ((ptr_CAN->MSR & CAN_MSR_INAK) != 0U)  { can_status.unit_state = ARM_CAN_UNIT_STATE_INACTIVE; }
  else if (((ptr_CAN->BTR & CAN_BTR_LBKM) != 0U) ||
           ((ptr_CAN->BTR & CAN_BTR_SILM) != 0U)) { can_status.unit_state = ARM_CAN_UNIT_STATE_PASSIVE;  }
  else if ((esr & CAN_ESR_BOFF) != 0U)            { can_status.unit_state = ARM_CAN_UNIT_STATE_INACTIVE; }
  else if ((esr & CAN_ESR_EPVF) != 0U)            { can_status.unit_state = ARM_CAN_UNIT_STATE_PASSIVE;  }
  else                                            { can_status.unit_state = ARM_CAN_UNIT_STATE_ACTIVE;   }

  switch ((esr & CAN_ESR_LEC) >> 4) {
    case 0:
      can_status.last_error_code = ARM_CAN_LEC_NO_ERROR;
      break;
    case 1:
      can_status.last_error_code = ARM_CAN_LEC_STUFF_ERROR;
      break;
    case 2:
      can_status.last_error_code = ARM_CAN_LEC_FORM_ERROR;
      break;
    case 3:
      can_status.last_error_code = ARM_CAN_LEC_ACK_ERROR;
      break;
    case 4:
    case 5:
      can_status.last_error_code = ARM_CAN_LEC_BIT_ERROR;
      break;
    case 6:
      can_status.last_error_code = ARM_CAN_LEC_CRC_ERROR;
      break;
    case 7:
      can_status.last_error_code = ARM_CAN_LEC_NO_ERROR;
      break;
  }

  can_status.tx_error_count = (uint8_t)((esr & CAN_ESR_TEC) >> 16);
  can_status.rx_error_count = (uint8_t)((esr & CAN_ESR_REC) >> 24);

  return can_status;
}
#if (MX_CAN1 == 1U)
static ARM_CAN_STATUS CAN1_GetStatus (void) { return CANx_GetStatus (0); }
#endif
#if (MX_CAN2 == 1U)
static ARM_CAN_STATUS CAN2_GetStatus (void) { return CANx_GetStatus (1); }
#endif


#if (MX_CAN1 == 1U)
/**
  \fn          void CAN1_TX_IRQHandler (void)
  \brief       CAN1 Transmit Interrupt Routine (IRQ).
*/
#ifdef  STM32F10X_CL
void CAN1_TX_IRQHandler (void) {
#else
void USB_HP_CAN1_TX_IRQHandler (void) {
#endif
  uint32_t esr, ier;

  if ((CAN1->TSR & CAN_TSR_RQCP0) != 0U) {
    if ((CAN1->TSR & CAN_TSR_TXOK0) != 0U) {
      if (can_obj_cfg[0][CAN_RX_OBJ_NUM] == ARM_CAN_OBJ_TX) {
        if (CAN_SignalObjectEvent[0] != NULL) { CAN_SignalObjectEvent[0](CAN_RX_OBJ_NUM, ARM_CAN_EVENT_SEND_COMPLETE); }
      }
    }
    CAN1->TSR = CAN_TSR_RQCP0;          // Request completed on transmit mailbox 0
  }
  if ((CAN1->TSR & CAN_TSR_RQCP1) != 0U) {
    if ((CAN1->TSR & CAN_TSR_TXOK1) != 0U) {
      if (can_obj_cfg[0][CAN_RX_OBJ_NUM+1U] == ARM_CAN_OBJ_TX) {
        if (CAN_SignalObjectEvent[0] != NULL) { CAN_SignalObjectEvent[0](CAN_RX_OBJ_NUM+1U, ARM_CAN_EVENT_SEND_COMPLETE); }
      }
    }
    CAN1->TSR = CAN_TSR_RQCP1;          // Request completed on transmit mailbox 1
  }
  if ((CAN1->TSR & CAN_TSR_RQCP2) != 0U) {
    if ((CAN1->TSR & CAN_TSR_TXOK2) != 0U) {
      if (can_obj_cfg[0][CAN_RX_OBJ_NUM+2U] == ARM_CAN_OBJ_TX) {
        if (CAN_SignalObjectEvent[0] != NULL) { CAN_SignalObjectEvent[0](CAN_RX_OBJ_NUM+2U, ARM_CAN_EVENT_SEND_COMPLETE); }
      }
    }
    CAN1->TSR = CAN_TSR_RQCP2;          // Request completed on transmit mailbox 2
  }

  // Handle transition from from 'bus off', ' error active' state, or re-enable warning interrupt
  esr = CAN1->ESR;
  ier = CAN1->IER;
  if (((esr & CAN_ESR_BOFF) == 0U) && ((ier & CAN_IER_BOFIE) == 0U)) { 
    CAN1->IER |= CAN_IER_BOFIE;
    if (CAN_SignalUnitEvent[0] != NULL) { CAN_SignalUnitEvent[0](ARM_CAN_EVENT_UNIT_PASSIVE); }
  }
  if (((esr & CAN_ESR_EPVF) == 0U) && ((ier & CAN_IER_EPVIE) == 0U)) {
    CAN1->IER |= CAN_IER_EPVIE;
    if (CAN_SignalUnitEvent[0] != NULL) { CAN_SignalUnitEvent[0](ARM_CAN_EVENT_UNIT_ACTIVE); }
  }
  if (((esr & CAN_ESR_EWGF) == 0U) && ((ier & CAN_IER_EWGIE) == 0U) && (((esr & CAN_ESR_TEC) >> 16) == 95U) && (((esr & CAN_ESR_REC) >> 24) < 95U)) {
    CAN1->IER |= CAN_IER_EWGIE;
  }
}

/**
  \fn          void CAN1_RX0_IRQHandler (void)
  \brief       CAN1 Receive on FIFO0 Interrupt Routine (IRQ).
*/
#ifdef  STM32F10X_CL
void CAN1_RX0_IRQHandler (void) {
#else
void USB_LP_CAN1_RX0_IRQHandler (void) {
#endif
  uint32_t esr, ier;

  if (can_obj_cfg[0][0] == ARM_CAN_OBJ_RX) {
    if ((CAN1->RF0R & CAN_RF0R_FOVR0) != 0U) {
      CAN1->RF0R = CAN_RF0R_FOVR0;      // Clear overrun flag
      if (CAN_SignalObjectEvent[0] != NULL) { CAN_SignalObjectEvent[0](0U, ARM_CAN_EVENT_RECEIVE | ARM_CAN_EVENT_RECEIVE_OVERRUN); }
    } else if ((CAN1->RF0R & CAN_RF0R_FMP0) != 0U) {
      if (CAN_SignalObjectEvent[0] != NULL) { CAN_SignalObjectEvent[0](0U, ARM_CAN_EVENT_RECEIVE); }
    }
  } else {
    CAN1->RF0R = CAN_RF0R_RFOM0;        // Release FIFO 0 output mailbox if object not enabled for reception
  }

  // Handle transition from from 'bus off', ' error active' state, or re-enable warning interrupt
  esr = CAN1->ESR;
  ier = CAN1->IER;
  if (((esr & CAN_ESR_BOFF) == 0U) && ((ier & CAN_IER_BOFIE) == 0U)) { 
    CAN1->IER |= CAN_IER_BOFIE;
    if (CAN_SignalUnitEvent[0] != NULL) { CAN_SignalUnitEvent[0](ARM_CAN_EVENT_UNIT_PASSIVE); }
  }
  if (((esr & CAN_ESR_EPVF) == 0U) && ((ier & CAN_IER_EPVIE) == 0U)) {
    CAN1->IER |= CAN_IER_EPVIE;
    if (CAN_SignalUnitEvent[0] != NULL) { CAN_SignalUnitEvent[0](ARM_CAN_EVENT_UNIT_ACTIVE); }
  }
  if (((esr & CAN_ESR_EWGF) == 0U) && ((ier & CAN_IER_EWGIE) == 0U) && (((esr & CAN_ESR_TEC) >> 16) < 95U) && (((esr & CAN_ESR_REC) >> 24) == 95U)) {
    CAN1->IER |= CAN_IER_EWGIE;
  }
}

/**
  \fn          void CAN1_RX1_IRQHandler (void)
  \brief       CAN1 Receive on FIFO1 Interrupt Routine (IRQ).
*/
void CAN1_RX1_IRQHandler (void) {
  uint32_t esr, ier;

  if (can_obj_cfg[0][1] == ARM_CAN_OBJ_RX) {
    if ((CAN1->RF1R & CAN_RF1R_FOVR1) != 0U) {
      CAN1->RF1R = CAN_RF1R_FOVR1;      // Clear overrun flag
      if (CAN_SignalObjectEvent[0] != NULL) { CAN_SignalObjectEvent[0](1U, ARM_CAN_EVENT_RECEIVE | ARM_CAN_EVENT_RECEIVE_OVERRUN); }
    } else if ((CAN1->RF1R & CAN_RF1R_FMP1) != 0U) {
      if (CAN_SignalObjectEvent[0] != NULL) { CAN_SignalObjectEvent[0](1U, ARM_CAN_EVENT_RECEIVE); }
    }
  } else {
    CAN1->RF1R = CAN_RF1R_RFOM1;        // Release FIFO 1 output mailbox if object not enabled for reception
  }

  // Handle transition from from 'bus off', ' error active' state, or re-enable warning interrupt
  esr = CAN1->ESR;
  ier = CAN1->IER;
  if (((esr & CAN_ESR_BOFF) == 0U) && ((ier & CAN_IER_BOFIE) == 0U)) { 
    CAN1->IER |= CAN_IER_BOFIE;
    if (CAN_SignalUnitEvent[0] != NULL) { CAN_SignalUnitEvent[0](ARM_CAN_EVENT_UNIT_PASSIVE); }
  }
  if (((esr & CAN_ESR_EPVF) == 0U) && ((ier & CAN_IER_EPVIE) == 0U)) {
    CAN1->IER |= CAN_IER_EPVIE;
    if (CAN_SignalUnitEvent[0] != NULL) { CAN_SignalUnitEvent[0](ARM_CAN_EVENT_UNIT_ACTIVE); }
  }
  if (((esr & CAN_ESR_EWGF) == 0U) && ((ier & CAN_IER_EWGIE) == 0U) && (((esr & CAN_ESR_TEC) >> 16) < 95U) && (((esr & CAN_ESR_REC) >> 24) == 95U)) {
    CAN1->IER |= CAN_IER_EWGIE;
  }
}

/**
  \fn          void CAN1_SCE_IRQHandler (void)
  \brief       CAN1 Error and Status Change Interrupt Routine (IRQ).
*/
void CAN1_SCE_IRQHandler (void) {
  uint32_t esr, ier;

  if (CAN_SignalUnitEvent[0] != NULL) {
    esr = CAN1->ESR;
    ier = CAN1->IER;
    CAN1->MSR = CAN_MSR_ERRI;             // Clear error interrupt
    if      (((esr & CAN_ESR_BOFF) != 0U) && ((ier & CAN_IER_BOFIE) != 0U)) { CAN1->IER &= ~CAN_IER_BOFIE; CAN_SignalUnitEvent[0](ARM_CAN_EVENT_UNIT_BUS_OFF); }
    else if (((esr & CAN_ESR_EPVF) != 0U) && ((ier & CAN_IER_EPVIE) != 0U)) { CAN1->IER &= ~CAN_IER_EPVIE; CAN_SignalUnitEvent[0](ARM_CAN_EVENT_UNIT_PASSIVE); }
    else if (((esr & CAN_ESR_EWGF) != 0U) && ((ier & CAN_IER_EWGIE) != 0U)) { CAN1->IER &= ~CAN_IER_EWGIE; CAN_SignalUnitEvent[0](ARM_CAN_EVENT_UNIT_WARNING); }
  }
}
#endif

#if (MX_CAN2 == 1U)
/**
  \fn          void CAN2_TX_IRQHandler (void)
  \brief       CAN2 Transmit Interrupt Routine (IRQ).
*/
void CAN2_TX_IRQHandler (void) {
  uint32_t esr, ier;

  if ((CAN2->TSR & CAN_TSR_TXOK0) != 0U) {
    if (can_obj_cfg[1][CAN_RX_OBJ_NUM] == ARM_CAN_OBJ_TX) {
      if (CAN_SignalObjectEvent[1] != NULL) { CAN_SignalObjectEvent[1](CAN_RX_OBJ_NUM, ARM_CAN_EVENT_SEND_COMPLETE); }
    }
    CAN2->TSR = CAN_TSR_RQCP0;          // Request completed on transmit mailbox 0
  }
  if ((CAN2->TSR & CAN_TSR_TXOK1) != 0U) {
    if (can_obj_cfg[1][CAN_RX_OBJ_NUM+1U] == ARM_CAN_OBJ_TX) {
      if (CAN_SignalObjectEvent[1] != NULL) { CAN_SignalObjectEvent[1](CAN_RX_OBJ_NUM+1U, ARM_CAN_EVENT_SEND_COMPLETE); }
    }
    CAN2->TSR = CAN_TSR_RQCP1;          // Request completed on transmit mailbox 1
  }
  if ((CAN2->TSR & CAN_TSR_TXOK2) != 0U) {
    if (can_obj_cfg[1][CAN_RX_OBJ_NUM+2U] == ARM_CAN_OBJ_TX) {
      if (CAN_SignalObjectEvent[1] != NULL) { CAN_SignalObjectEvent[1](CAN_RX_OBJ_NUM+2U, ARM_CAN_EVENT_SEND_COMPLETE); }
    }
    CAN2->TSR = CAN_TSR_RQCP2;          // Request completed on transmit mailbox 2
  }

  // Handle transition from from 'bus off', ' error active' state, or re-enable warning interrupt
  esr = CAN2->ESR;
  ier = CAN2->IER;
  if (((esr & CAN_ESR_BOFF) == 0U) && ((ier & CAN_IER_BOFIE) == 0U)) { 
    CAN2->IER |= CAN_IER_BOFIE;
    if (CAN_SignalUnitEvent[1] != NULL) { CAN_SignalUnitEvent[1](ARM_CAN_EVENT_UNIT_PASSIVE); }
  }
  if (((esr & CAN_ESR_EPVF) == 0U) && ((ier & CAN_IER_EPVIE) == 0U)) {
    CAN2->IER |= CAN_IER_EPVIE;
    if (CAN_SignalUnitEvent[1] != NULL) { CAN_SignalUnitEvent[1](ARM_CAN_EVENT_UNIT_ACTIVE); }
  }
  if (((esr & CAN_ESR_EWGF) == 0U) && ((ier & CAN_IER_EWGIE) == 0U) && (((esr & CAN_ESR_TEC) >> 16) == 95U) && (((esr & CAN_ESR_REC) >> 24) < 95U)) {
    CAN2->IER |= CAN_IER_EWGIE;
  }
}

/**
  \fn          void CAN2_RX0_IRQHandler (void)
  \brief       CAN2 Receive on FIFO0 Interrupt Routine (IRQ).
*/
void CAN2_RX0_IRQHandler (void) {
  uint32_t esr, ier;

  if (can_obj_cfg[1][0] == ARM_CAN_OBJ_RX) {
    if ((CAN2->RF0R & CAN_RF0R_FOVR0) != 0U) {
      CAN2->RF0R = CAN_RF0R_FOVR0;      // Clear overrun flag
      if (CAN_SignalObjectEvent[1] != NULL) { CAN_SignalObjectEvent[1](0U, ARM_CAN_EVENT_RECEIVE | ARM_CAN_EVENT_RECEIVE_OVERRUN); }
    } else if ((CAN2->RF0R & CAN_RF0R_FMP0) != 0U) {
      if (CAN_SignalObjectEvent[1] != NULL) { CAN_SignalObjectEvent[1](0U, ARM_CAN_EVENT_RECEIVE); }
    }
  } else {
    CAN2->RF0R = CAN_RF0R_RFOM0;        // Release FIFO 0 output mailbox if object not enabled for reception
  }

  // Handle transition from from 'bus off', ' error active' state, or re-enable warning interrupt
  esr = CAN2->ESR;
  ier = CAN2->IER;
  if (((esr & CAN_ESR_BOFF) == 0U) && ((ier & CAN_IER_BOFIE) == 0U)) { 
    CAN2->IER |= CAN_IER_BOFIE;
    if (CAN_SignalUnitEvent[1] != NULL) { CAN_SignalUnitEvent[1](ARM_CAN_EVENT_UNIT_PASSIVE); }
  }
  if (((esr & CAN_ESR_EPVF) == 0U) && ((ier & CAN_IER_EPVIE) == 0U)) {
    CAN2->IER |= CAN_IER_EPVIE;
    if (CAN_SignalUnitEvent[1] != NULL) { CAN_SignalUnitEvent[1](ARM_CAN_EVENT_UNIT_ACTIVE); }
  }
  if (((esr & CAN_ESR_EWGF) == 0U) && ((ier & CAN_IER_EWGIE) == 0U) && (((esr & CAN_ESR_TEC) >> 16) < 95U) && (((esr & CAN_ESR_REC) >> 24) == 95U)) {
    CAN2->IER |= CAN_IER_EWGIE;
  }
}

/**
  \fn          void CAN2_RX1_IRQHandler (void)
  \brief       CAN2 Receive on FIFO1 Interrupt Routine (IRQ).
*/
void CAN2_RX1_IRQHandler (void) {
  uint32_t esr, ier;

  if (can_obj_cfg[1][1] == ARM_CAN_OBJ_RX) {
    if ((CAN2->RF1R & CAN_RF1R_FOVR1) != 0U) {
      CAN2->RF1R = CAN_RF1R_FOVR1;      // Clear overrun flag
      if (CAN_SignalObjectEvent[1] != NULL) { CAN_SignalObjectEvent[1](1U, ARM_CAN_EVENT_RECEIVE | ARM_CAN_EVENT_RECEIVE_OVERRUN); }
    } else if ((CAN2->RF1R & CAN_RF1R_FMP1) != 0U) {
      if (CAN_SignalObjectEvent[1] != NULL) { CAN_SignalObjectEvent[1](1U, ARM_CAN_EVENT_RECEIVE); }
    }
  } else {
    CAN2->RF1R = CAN_RF1R_RFOM1;        // Release FIFO 1 output mailbox if object not enabled for reception
  }

  // Handle transition from from 'bus off', ' error active' state, or re-enable warning interrupt
  esr = CAN2->ESR;
  ier = CAN2->IER;
  if (((esr & CAN_ESR_BOFF) == 0U) && ((ier & CAN_IER_BOFIE) == 0U)) { 
    CAN2->IER |= CAN_IER_BOFIE;
    if (CAN_SignalUnitEvent[1] != NULL) { CAN_SignalUnitEvent[1](ARM_CAN_EVENT_UNIT_PASSIVE); }
  }
  if (((esr & CAN_ESR_EPVF) == 0U) && ((ier & CAN_IER_EPVIE) == 0U)) {
    CAN2->IER |= CAN_IER_EPVIE;
    if (CAN_SignalUnitEvent[1] != NULL) { CAN_SignalUnitEvent[1](ARM_CAN_EVENT_UNIT_ACTIVE); }
  }
  if (((esr & CAN_ESR_EWGF) == 0U) && ((ier & CAN_IER_EWGIE) == 0U) && (((esr & CAN_ESR_TEC) >> 16) < 95U) && (((esr & CAN_ESR_REC) >> 24) == 95U)) {
    CAN2->IER |= CAN_IER_EWGIE;
  }
}

/**
  \fn          void CAN2_SCE_IRQHandler (void)
  \brief       CAN2 Error and Status Change Interrupt Routine (IRQ).
*/
void CAN2_SCE_IRQHandler (void) {
  uint32_t esr, ier;

  if (CAN_SignalUnitEvent[1] != NULL) {
    esr = CAN2->ESR;
    ier = CAN2->IER;
    CAN2->MSR = CAN_MSR_ERRI;             // Clear error interrupt
    if      (((esr & CAN_ESR_BOFF) != 0U) && ((ier & CAN_IER_BOFIE) != 0U)) { CAN2->IER &= ~CAN_IER_BOFIE; CAN_SignalUnitEvent[1](ARM_CAN_EVENT_UNIT_BUS_OFF); }
    else if (((esr & CAN_ESR_EPVF) != 0U) && ((ier & CAN_IER_EPVIE) != 0U)) { CAN2->IER &= ~CAN_IER_EPVIE; CAN_SignalUnitEvent[1](ARM_CAN_EVENT_UNIT_PASSIVE); }
    else if (((esr & CAN_ESR_EWGF) != 0U) && ((ier & CAN_IER_EWGIE) != 0U)) { CAN2->IER &= ~CAN_IER_EWGIE; CAN_SignalUnitEvent[1](ARM_CAN_EVENT_UNIT_WARNING); }
  }
}
#endif


#if (MX_CAN1 == 1U)
ARM_DRIVER_CAN Driver_CAN1 = {
  CAN_GetVersion,
  CAN_GetCapabilities,
  CAN1_Initialize,
  CAN1_Uninitialize,
  CAN1_PowerControl,
  CAN_GetClock,
  CAN1_SetBitrate,
  CAN1_SetMode,
  CAN1_ObjectGetCapabilities,
  CAN1_ObjectSetFilter,
  CAN1_ObjectConfigure,
  CAN1_MessageSend,
  CAN1_MessageRead,
  CAN1_Control,
  CAN1_GetStatus
};
#endif

#if (MX_CAN2 == 1U)
ARM_DRIVER_CAN Driver_CAN2 = {
  CAN_GetVersion,
  CAN_GetCapabilities,
  CAN2_Initialize,
  CAN2_Uninitialize,
  CAN2_PowerControl,
  CAN_GetClock,
  CAN2_SetBitrate,
  CAN2_SetMode,
  CAN2_ObjectGetCapabilities,
  CAN2_ObjectSetFilter,
  CAN2_ObjectConfigure,
  CAN2_MessageSend,
  CAN2_MessageRead,
  CAN2_Control,
  CAN2_GetStatus
};
#endif

/*! \endcond */
