]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lib.git/blobdiff - rpp/src/rpp/can.c
Make the RPP layer thread safe
[pes-rpp/rpp-lib.git] / rpp / src / rpp / can.c
index f1845698b539db29634923f324c9cb2b2ce82910..ef86da43fed5819e4d536e677f06cf709df7821a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 Czech Technical University in Prague
+/* Copyright (C) 2013-2015 Czech Technical University in Prague
  *
  * Authors:
  *     - Carlos Jenkins <carlos@jenkins.co.cr>
 
 #include "rpp/rpp.h"
 #include <math.h>
+#include "sys/ti_drv_dmm.h"
+#include "rpp/mutex.h"
 
-#if rppCONFIG_INCLUDE_CAN == 1
+RPP_MUTEX_DEFINE(mutex_can);
 
 static const struct rpp_can_config *can_config = NULL;
 
-
-
-typedef volatile struct CANBase
-{
-    uint32_t      CTL;          /**< 0x0000: Control Register                       */
-    uint32_t      ES;           /**< 0x0004: Error and Status Register              */
-    uint32_t      EERC;         /**< 0x0008: Error Counter Register                 */
-    uint32_t      BTR;          /**< 0x000C: Bit Timing Register                    */
-    uint32_t      INT;          /**< 0x0010: Interrupt Register                     */
-    uint32_t      TEST;         /**< 0x0014: Test Register                          */
-    uint32_t      : 32U;        /**< 0x0018: Reserved                               */
-    uint32_t      PERR;         /**< 0x001C: Parity/SECDED Error Code Register      */
-    uint32_t      REL;          /**< 0x0020: Core Release Register                  */
-    uint32_t      ECCDIAG;      /**< 0x0024: ECC Diagnostic Register                */
-    uint32_t      ECCDIADSTAT;  /**< 0x0028: ECC Diagnostic Status Register         */
-    uint32_t      : 32U;        /**< 0x002C: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0030: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0034: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0038: Reserved                               */
-    uint32_t      : 32U;        /**< 0x003C: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0040: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0044: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0048: Reserved                               */
-    uint32_t      : 32U;        /**< 0x004C: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0050: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0054: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0058: Reserved                               */
-    uint32_t      : 32U;        /**< 0x005C: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0060: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0064: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0068: Reserved                               */
-    uint32_t      : 32U;        /**< 0x006C: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0070: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0074: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0078: Reserved                               */
-    uint32_t      : 32U;        /**< 0x007C: Reserved                               */
-    uint32_t      ABOTR;        /**< 0x0080: Auto Bus On Time Register              */
-    uint32_t      TXRQX;        /**< 0x0084: Transmission Request X Register        */
-    uint32_t      TXRQx[4U];    /**< 0x0088-0x0094: Transmission Request Registers  */
-    uint32_t      NWDATX;       /**< 0x0098: New Data X Register                    */
-    uint32_t      NWDATx[4U];   /**< 0x009C-0x00A8: New Data Registers              */
-    uint32_t      INTPNDX;      /**< 0x00AC: Interrupt Pending X Register           */
-    uint32_t      INTPNDx[4U];  /**< 0x00B0-0x00BC: Interrupt Pending Registers     */
-    uint32_t      MSGVALX;      /**< 0x00C0: Message Valid X Register               */
-    uint32_t      MSGVALx[4U];  /**< 0x00C4-0x00D0: Message Valid Registers         */
-    uint32_t      : 32U;        /**< 0x00D4: Reserved                               */
-    uint32_t      INTMUXx[4U];  /**< 0x00D8-0x00E4: Interrupt Multiplexer Registers */
-    uint32_t      : 32U;        /**< 0x00E8: Reserved                               */
-    uint32_t      : 32U;        /**< 0x00EC: Reserved                               */
-    uint32_t      : 32U;        /**< 0x00F0: Reserved                               */
-    uint32_t      : 32U;        /**< 0x00F4: Reserved                               */
-    uint32_t      : 32U;        /**< 0x00F8: Reserved                               */
-    uint32_t      : 32U;        /**< 0x00FC: Reserved                               */
+typedef volatile struct CANBase {
+       uint32_t CTL;               /**< 0x0000: Control Register                       */
+       uint32_t ES;                /**< 0x0004: Error and Status Register              */
+       uint32_t EERC;              /**< 0x0008: Error Counter Register                 */
+       uint32_t BTR;               /**< 0x000C: Bit Timing Register                    */
+       uint32_t INT;               /**< 0x0010: Interrupt Register                     */
+       uint32_t TEST;              /**< 0x0014: Test Register                          */
+       uint32_t      : 32U;        /**< 0x0018: Reserved                               */
+       uint32_t PERR;              /**< 0x001C: Parity/SECDED Error Code Register      */
+       uint32_t REL;               /**< 0x0020: Core Release Register                  */
+       uint32_t ECCDIAG;           /**< 0x0024: ECC Diagnostic Register                */
+       uint32_t ECCDIADSTAT;       /**< 0x0028: ECC Diagnostic Status Register         */
+       uint32_t      : 32U;        /**< 0x002C: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0030: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0034: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0038: Reserved                               */
+       uint32_t      : 32U;        /**< 0x003C: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0040: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0044: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0048: Reserved                               */
+       uint32_t      : 32U;        /**< 0x004C: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0050: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0054: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0058: Reserved                               */
+       uint32_t      : 32U;        /**< 0x005C: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0060: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0064: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0068: Reserved                               */
+       uint32_t      : 32U;        /**< 0x006C: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0070: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0074: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0078: Reserved                               */
+       uint32_t      : 32U;        /**< 0x007C: Reserved                               */
+       uint32_t ABOTR;             /**< 0x0080: Auto Bus On Time Register              */
+       uint32_t TXRQX;             /**< 0x0084: Transmission Request X Register        */
+       uint32_t TXRQx[4U];         /**< 0x0088-0x0094: Transmission Request Registers  */
+       uint32_t NWDATX;            /**< 0x0098: New Data X Register                    */
+       uint32_t NWDATx[4U];        /**< 0x009C-0x00A8: New Data Registers              */
+       uint32_t INTPNDX;           /**< 0x00AC: Interrupt Pending X Register           */
+       uint32_t INTPNDx[4U];       /**< 0x00B0-0x00BC: Interrupt Pending Registers     */
+       uint32_t MSGVALX;           /**< 0x00C0: Message Valid X Register               */
+       uint32_t MSGVALx[4U];       /**< 0x00C4-0x00D0: Message Valid Registers         */
+       uint32_t      : 32U;        /**< 0x00D4: Reserved                               */
+       uint32_t INTMUXx[4U];       /**< 0x00D8-0x00E4: Interrupt Multiplexer Registers */
+       uint32_t      : 32U;        /**< 0x00E8: Reserved                               */
+       uint32_t      : 32U;        /**< 0x00EC: Reserved                               */
+       uint32_t      : 32U;        /**< 0x00F0: Reserved                               */
+       uint32_t      : 32U;        /**< 0x00F4: Reserved                               */
+       uint32_t      : 32U;        /**< 0x00F8: Reserved                               */
+       uint32_t      : 32U;        /**< 0x00FC: Reserved                               */
 #if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
-    uint8_t IF1NO;              /**< 0x0100: IF1 Command Register, Msg Number       */
-    uint8_t IF1STAT;            /**< 0x0100: IF1 Command Register, Status           */
-    uint8_t IF1CMD;             /**< 0x0100: IF1 Command Register, Command          */
-    uint32_t      : 8U;         /**< 0x0100: IF1 Command Register, Reserved         */
+       uint8_t IF1NO;              /**< 0x0100: IF1 Command Register, Msg Number       */
+       uint8_t IF1STAT;            /**< 0x0100: IF1 Command Register, Status           */
+       uint8_t IF1CMD;             /**< 0x0100: IF1 Command Register, Command          */
+       uint32_t      : 8U;         /**< 0x0100: IF1 Command Register, Reserved         */
 #else
-    uint32_t      : 8U;         /**< 0x0100: IF1 Command Register, Reserved         */
-    uint8_t IF1CMD;             /**< 0x0100: IF1 Command Register, Command          */
-    uint8_t IF1STAT;            /**< 0x0100: IF1 Command Register, Status           */
-    uint8_t IF1NO;              /**< 0x0100: IF1 Command Register, Msg Number       */
+       uint32_t      : 8U;         /**< 0x0100: IF1 Command Register, Reserved         */
+       uint8_t IF1CMD;             /**< 0x0100: IF1 Command Register, Command          */
+       uint8_t IF1STAT;            /**< 0x0100: IF1 Command Register, Status           */
+       uint8_t IF1NO;              /**< 0x0100: IF1 Command Register, Msg Number       */
 #endif
-    uint32_t      IF1MSK;       /**< 0x0104: IF1 Mask Register                      */
-    uint32_t      IF1ARB;       /**< 0x0108: IF1 Arbitration Register               */
-    uint32_t      IF1MCTL;      /**< 0x010C: IF1 Message Control Register           */
-    uint8_t IF1DATx[8U];        /**< 0x0110-0x0114: IF1 Data A and B Registers      */
-    uint32_t      : 32U;        /**< 0x0118: Reserved                               */
-    uint32_t      : 32U;        /**< 0x011C: Reserved                               */
+       uint32_t IF1MSK;            /**< 0x0104: IF1 Mask Register                      */
+       uint32_t IF1ARB;            /**< 0x0108: IF1 Arbitration Register               */
+       uint32_t IF1MCTL;           /**< 0x010C: IF1 Message Control Register           */
+       uint8_t IF1DATx[8U];        /**< 0x0110-0x0114: IF1 Data A and B Registers      */
+       uint32_t      : 32U;        /**< 0x0118: Reserved                               */
+       uint32_t      : 32U;        /**< 0x011C: Reserved                               */
 #if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
-    uint8_t IF2NO;              /**< 0x0120: IF2 Command Register, Msg No           */
-    uint8_t IF2STAT;            /**< 0x0120: IF2 Command Register, Status           */
-    uint8_t IF2CMD;             /**< 0x0120: IF2 Command Register, Command          */
-    uint32_t      : 8U;         /**< 0x0120: IF2 Command Register, Reserved         */
+       uint8_t IF2NO;              /**< 0x0120: IF2 Command Register, Msg No           */
+       uint8_t IF2STAT;            /**< 0x0120: IF2 Command Register, Status           */
+       uint8_t IF2CMD;             /**< 0x0120: IF2 Command Register, Command          */
+       uint32_t      : 8U;         /**< 0x0120: IF2 Command Register, Reserved         */
 #else
-    uint32_t      : 8U;         /**< 0x0120: IF2 Command Register, Reserved         */
-    uint8_t IF2CMD;             /**< 0x0120: IF2 Command Register, Command          */
-    uint8_t IF2STAT;            /**< 0x0120: IF2 Command Register, Status           */
-    uint8_t IF2NO;              /**< 0x0120: IF2 Command Register, Msg Number       */
+       uint32_t      : 8U;         /**< 0x0120: IF2 Command Register, Reserved         */
+       uint8_t IF2CMD;             /**< 0x0120: IF2 Command Register, Command          */
+       uint8_t IF2STAT;            /**< 0x0120: IF2 Command Register, Status           */
+       uint8_t IF2NO;              /**< 0x0120: IF2 Command Register, Msg Number       */
 #endif
-    uint32_t      IF2MSK;       /**< 0x0124: IF2 Mask Register                      */
-    uint32_t      IF2ARB;       /**< 0x0128: IF2 Arbitration Register               */
-    uint32_t      IF2MCTL;      /**< 0x012C: IF2 Message Control Register           */
-    uint8_t IF2DATx[8U];        /**< 0x0130-0x0134: IF2 Data A and B Registers      */
-    uint32_t      : 32U;        /**< 0x0138: Reserved                               */
-    uint32_t      : 32U;        /**< 0x013C: Reserved                               */
-    uint32_t      IF3OBS;       /**< 0x0140: IF3 Observation Register               */
-    uint32_t      IF3MSK;       /**< 0x0144: IF3 Mask Register                      */
-    uint32_t      IF3ARB;       /**< 0x0148: IF3 Arbitration Register               */
-    uint32_t      IF3MCTL;      /**< 0x014C: IF3 Message Control Register           */
-    uint8_t IF3DATx[8U];        /**< 0x0150-0x0154: IF3 Data A and B Registers      */
-    uint32_t      : 32U;        /**< 0x0158: Reserved                               */
-    uint32_t      : 32U;        /**< 0x015C: Reserved                               */
-    uint32_t      IF3UEy[4U];   /**< 0x0160-0x016C: IF3 Update Enable Registers     */
-    uint32_t      : 32U;        /**< 0x0170: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0174: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0178: Reserved                               */
-    uint32_t      : 32U;        /**< 0x017C: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0180: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0184: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0188: Reserved                               */
-    uint32_t      : 32U;        /**< 0x018C: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0190: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0194: Reserved                               */
-    uint32_t      : 32U;        /**< 0x0198: Reserved                               */
-    uint32_t      : 32U;        /**< 0x019C: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01A0: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01A4: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01A8: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01AC: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01B0: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01B4: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01B8: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01BC: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01C0: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01C4: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01C8: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01CC: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01D0: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01D4: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01D8: Reserved                               */
-    uint32_t      : 32U;        /**< 0x01DC: Reserved                               */
-    uint32_t      TIOC;         /**< 0x01E0: TX IO Control Register                 */
-    uint32_t      RIOC;         /**< 0x01E4: RX IO Control Register                 */
+       uint32_t IF2MSK;            /**< 0x0124: IF2 Mask Register                      */
+       uint32_t IF2ARB;            /**< 0x0128: IF2 Arbitration Register               */
+       uint32_t IF2MCTL;           /**< 0x012C: IF2 Message Control Register           */
+       uint8_t IF2DATx[8U];        /**< 0x0130-0x0134: IF2 Data A and B Registers      */
+       uint32_t      : 32U;        /**< 0x0138: Reserved                               */
+       uint32_t      : 32U;        /**< 0x013C: Reserved                               */
+       uint32_t IF3OBS;            /**< 0x0140: IF3 Observation Register               */
+       uint32_t IF3MSK;            /**< 0x0144: IF3 Mask Register                      */
+       uint32_t IF3ARB;            /**< 0x0148: IF3 Arbitration Register               */
+       uint32_t IF3MCTL;           /**< 0x014C: IF3 Message Control Register           */
+       uint8_t IF3DATx[8U];        /**< 0x0150-0x0154: IF3 Data A and B Registers      */
+       uint32_t      : 32U;        /**< 0x0158: Reserved                               */
+       uint32_t      : 32U;        /**< 0x015C: Reserved                               */
+       uint32_t IF3UEy[4U];        /**< 0x0160-0x016C: IF3 Update Enable Registers     */
+       uint32_t      : 32U;        /**< 0x0170: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0174: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0178: Reserved                               */
+       uint32_t      : 32U;        /**< 0x017C: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0180: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0184: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0188: Reserved                               */
+       uint32_t      : 32U;        /**< 0x018C: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0190: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0194: Reserved                               */
+       uint32_t      : 32U;        /**< 0x0198: Reserved                               */
+       uint32_t      : 32U;        /**< 0x019C: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01A0: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01A4: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01A8: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01AC: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01B0: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01B4: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01B8: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01BC: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01C0: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01C4: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01C8: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01CC: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01D0: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01D4: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01D8: Reserved                               */
+       uint32_t      : 32U;        /**< 0x01DC: Reserved                               */
+       uint32_t TIOC;              /**< 0x01E0: TX IO Control Register                 */
+       uint32_t RIOC;              /**< 0x01E4: RX IO Control Register                 */
 } canBASE_t;
 
-#define canREG1 ((canBASE_t *) 0xFFF7DC00U)
-#define canREG2 ((canBASE_t *) 0xFFF7DE00U)
-#define canREG3 ((canBASE_t *) 0xFFF7E000U)
+#define canREG1 ((canBASE_t *)0xFFF7DC00U)
+#define canREG2 ((canBASE_t *)0xFFF7DE00U)
+#define canREG3 ((canBASE_t *)0xFFF7E000U)
 
 #ifndef __little_endian__
-    static const uint32_t s_can_byte_order[] = {3, 2, 1, 0, 7, 6, 5, 4};
+static const uint32_t s_can_byte_order[] = {3, 2, 1, 0, 7, 6, 5, 4};
 #endif
 
 static canBASE_t *can_base[3] = { canREG1, canREG2, canREG3 };
 
-static inline canBASE_t * map_controller(uint8_t controller)
+static inline canBASE_t *map_controller(uint8_t controller)
 {
        if (controller < 1 || controller > 3)
                return NULL;
@@ -173,514 +172,587 @@ static inline canBASE_t * map_controller(uint8_t controller)
 
 static int8_t init_tx_box(struct rpp_can_tx_config cfg)
 {
-    canBASE_t *controller;
-
-    if (!(controller = map_controller(cfg.controller)))
-        return FAILURE;
-
-    // Wait until IF1 is ready to use
-    while (controller->IF1STAT & (1U << 7));
-
-    /**
-    * 31 Set whether use of std/ext ID should have effect on acceptance filtering
-    */
-    switch (cfg.type) {
-               case RPP_CAN_STANDARD:
-                       controller->IF1MSK = 0 << 31;
-                       break;
-               case RPP_CAN_MIXED:
-                       controller->IF1MSK = 1 << 31;
-                       break;
-               case RPP_CAN_EXTENDED:
-                       controller->IF1MSK = 1 << 31;
-                       break;
-    }
-
-    /**
-    * 31 Message object is valid
-    * 30 Set whether to use extented identifier
-    * 29 Set direction as transmit
-    */
-    controller->IF1ARB = (1U << 31)
-                          | ((cfg.type == RPP_CAN_STANDARD ? 0 : 1) << 30)
-                          | (1 << 29);
-
-    /**
-    *  7 End of buffer
-    * 4-1 Data length code
-    */
-    controller->IF1MCTL = (1 << 7)
-                           | 8;
-
-    /**
-    * Note that IF1CMD does not refer to whole CMD register
-    * (it refers to bits 23-16 of that register)
-    *  7 Transfer from IF to message object
-    *  5 Transfer arbitration bits
-    *  4 Transfer control bits
-    */
-    controller->IF1CMD = (1U << 7)
-                          | (1 << 5)
-                          | (1 << 4);
-
-    // Write MSG object number and enable transfer
-    controller->IF1NO = cfg.msg_obj;
-
-    return SUCCESS;
+       canBASE_t *controller;
+
+       if (!(controller = map_controller(cfg.controller)))
+               return FAILURE;
+
+       // Wait until IF1 is ready to use
+       while (controller->IF1STAT & (1U << 7)) ;
+
+       /**
+        * 31 Set whether use of std/ext ID should have effect on acceptance filtering
+        */
+       switch (cfg.type) {
+       case RPP_CAN_STANDARD:
+               controller->IF1MSK = 0U << 31;
+               break;
+       case RPP_CAN_MIXED:
+               controller->IF1MSK = 1U << 31;
+               break;
+       case RPP_CAN_EXTENDED:
+               controller->IF1MSK = 1U << 31;
+               break;
+       }
+
+       /**
+        * 31 Message object is valid
+        * 30 Set whether to use extented identifier
+        * 29 Set direction as transmit
+        */
+       controller->IF1ARB = (1U << 31)
+                                                | ((cfg.type == RPP_CAN_STANDARD ? 0 : 1) << 30)
+                                                | (1 << 29);
+
+       /**
+        *  7 End of buffer
+        * 4-1 Data length code
+        */
+       controller->IF1MCTL = (1 << 7)
+                                                 | 8;
+
+       /**
+        * Note that IF1CMD does not refer to whole CMD register
+        * (it refers to bits 23-16 of that register)
+        *  7 Transfer from IF to message object
+        *  5 Transfer arbitration bits
+        *  4 Transfer control bits
+        */
+       controller->IF1CMD = (1U << 7)
+                                                | (1 << 5)
+                                                | (1 << 4);
+
+       // Write MSG object number and enable transfer
+       controller->IF1NO = cfg.msg_obj;
+
+       return SUCCESS;
 }
 
 static int8_t init_rx_box(struct rpp_can_rx_config cfg)
 {
-    canBASE_t *controller;
-
-    if (!(controller = map_controller(cfg.controller)))
-        return FAILURE;
-
-    // Wait until IF2 is ready to use
-    while (controller->IF2STAT & (1U << 7));
-
-    /**
-    * 31 Set whether use of std/ext ID should have effect on acceptance filtering
-    * 28-1 Set mask
-    */
-    switch (cfg.type) {
-               case RPP_CAN_STANDARD:
-                       controller->IF2MSK = (1 << 31) | (cfg.mask << 18);
-                       break;
-               case RPP_CAN_MIXED:
-                       controller->IF2MSK = (0 << 31) | cfg.mask;
-                       break;
-               case RPP_CAN_EXTENDED:
-                       controller->IF2MSK = (1 << 31) | cfg.mask;
-                       break;
-    }
-
-    /**
-    * 31 Message object is valid
-    * 30 Set whether extended ID should be used
-    * 29 Direction is read
-    * 28-18 / 28-1 Object ID
-    */
-    controller->IF2ARB = (1U << 31)    // MsgVal
-                          | ((cfg.type == RPP_CAN_STANDARD ? 0 : 1) << 30)
-                          | (0 << 29)  // Dir
-                          | cfg.id << (cfg.type == RPP_CAN_STANDARD ? 18 : 0);
-    /**
-    * 12 Use mask for filtering
-    *  7 End of buffer
-    * 4-1 Data length code
-    */
-    controller->IF2MCTL = (1 << 12)
-                           | (1 << 7)
-                           | 8;
-
-    /**
-    * Note that IF2CMD does not refer to whole CMD register
-    * (it refers to bits 23-16 of that register)
-    *  7 Transfer from IF to message object
-    *  6 Transfer mask bits
-    *  5 Transfer arbitration bits
-    *  4 Transfer control bits
-    */
-    controller->IF2CMD = (1 << 7)
-                          | (1 << 6)
-                          | (1 << 5)
-                          | (1 << 4);
-
-    // Write MSG object number and enable transfer
-    controller->IF2NO = cfg.msg_obj;
-
-    return SUCCESS;
+       canBASE_t *controller;
+
+       if (!(controller = map_controller(cfg.controller)))
+               return FAILURE;
+
+       // Wait until IF2 is ready to use
+       while (controller->IF2STAT & (1U << 7)) ;
+
+       /**
+        * 31 Set whether use of std/ext ID should have effect on acceptance filtering
+        * 28-1 Set mask
+        */
+       switch (cfg.type) {
+       case RPP_CAN_STANDARD:
+               controller->IF2MSK = (1U << 31) | (cfg.mask << 18);
+               break;
+       case RPP_CAN_MIXED:
+               controller->IF2MSK = (0U << 31) | cfg.mask;
+               break;
+       case RPP_CAN_EXTENDED:
+               controller->IF2MSK = (1U << 31) | cfg.mask;
+               break;
+       }
+
+       /**
+        * 31 Message object is valid
+        * 30 Set whether extended ID should be used
+        * 29 Direction is read
+        * 28-18 / 28-1 Object ID
+        */
+       controller->IF2ARB = (1U << 31) // MsgVal
+                                                | ((cfg.type == RPP_CAN_STANDARD ? 0 : 1) << 30)
+                                                | (0 << 29)    // Dir
+                                                | cfg.id << (cfg.type == RPP_CAN_STANDARD ? 18 : 0);
+       /**
+        * 12 Use mask for filtering
+        *  7 End of buffer
+        * 4-1 Data length code
+        */
+       controller->IF2MCTL = (1 << 12)
+                                                 | (1 << 7)
+                                                 | 8;
+
+       /**
+        * Note that IF2CMD does not refer to whole CMD register
+        * (it refers to bits 23-16 of that register)
+        *  7 Transfer from IF to message object
+        *  6 Transfer mask bits
+        *  5 Transfer arbitration bits
+        *  4 Transfer control bits
+        */
+       controller->IF2CMD = (1 << 7)
+                                                | (1 << 6)
+                                                | (1 << 5)
+                                                | (1 << 4);
+
+       // Write MSG object number and enable transfer
+       controller->IF2NO = cfg.msg_obj;
+
+       return SUCCESS;
 }
 
 
 
 static int8_t can_reset(canBASE_t *controller)
 {
-    /**
-    * 6 Request write access to config registers
-    * 0 Enter initialization mode
-    */
-    controller->CTL = 0
-                       | (1 << 6)
-                       | (1 << 0);
+       /**
+        * 6 Request write access to config registers
+        * 0 Enter initialization mode
+        */
+       controller->CTL = 0
+                                         | (1 << 6)
+                                         | (1 << 0);
+
+       controller->ES;
+       controller->ABOTR = 0;
+
+       controller->TIOC = (0 << 0);
+       controller->RIOC = (0 << 0);
+
+       return SUCCESS;
+}
 
-    controller->ES;
-    controller->ABOTR = 0;
+static int8_t can_set_timing(canBASE_t *controller, const struct rpp_can_timing_cfg cfg)
+{
+       controller->BTR = (((cfg.brp-1) >> 6) << 16)
+                                         | ((cfg.phase_seg2-1) << 12)
+                                         | (((cfg.phase_seg1+cfg.prop_seg)-1) << 8)
+                                         | ((cfg.sjw-1) << 6)
+                                         | ((cfg.brp-1) & 63);
+       return SUCCESS;
+}
 
-    controller->TIOC = (0 << 0);
-    controller->RIOC = (0 << 0);
+/* This code has been taken from can-calc-bit-timing.c */
+/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
+ *
+ * Derived from:
+ *   can_baud.c - CAN baudrate calculation
+ *   Code based on LinCAN sources and H8S2638 project
+ *   Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
+ *   Copyright 2005      Stanislav Marek
+ *   email:pisa@cmp.felk.cvut.cz
+ *
+ *   With permission from Pavel Pisa to distribute the code and
+ *   software under other license than GPL.
+ */
+static int can_update_spt(int phase_seg2_min, int phase_seg2_max, int prop_seg_max, int phase_seg1_max,
+                                                 int sampl_pt, int tseg, int *tseg1, int *tseg2)
+{
+       *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000;
+       if (*tseg2 < phase_seg2_min)
+               *tseg2 = phase_seg2_min;
+       if (*tseg2 > phase_seg2_max)
+               *tseg2 = phase_seg2_max;
+       *tseg1 = tseg - *tseg2;
+       if (*tseg1 > prop_seg_max + phase_seg1_max) {
+               *tseg1 = prop_seg_max + phase_seg1_max;
+               *tseg2 = tseg - *tseg1;
+       }
+       return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
+}
 
-    return SUCCESS;
+/* This code has been taken from can-calc-bit-timing.c */
+/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
+ *
+ * Derived from:
+ *   can_baud.c - CAN baudrate calculation
+ *   Code based on LinCAN sources and H8S2638 project
+ *   Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
+ *   Copyright 2005      Stanislav Marek
+ *   email:pisa@cmp.felk.cvut.cz
+ *
+ *   With permission from Pavel Pisa to distribute the code and
+ *   software under other license than GPL.
+ */
+static int8_t can_calculate_timing(const struct rpp_can_ctrl_config cfg, struct rpp_can_calculated_timing *timing)
+{
+       static const int prop_seg_min = 1;
+       static const int prop_seg_max = 8;
+       static const int phase_seg1_min = 1;
+       static const int phase_seg1_max = 8;
+       static const int phase_seg2_min = 1;
+       static const int phase_seg2_max = 8;
+       static const int brp_min = 1;
+       static const int brp_max = 64;
+       static const int brp_inc = 1;
+
+       if (timing == NULL)
+               return FAILURE;
+
+       int sampl_pt;
+       long best_error = 1000000000, error;
+       int best_tseg = 0, best_brp = 0, brp = 0;
+       int spt_error = 1000, spt = 0;
+       long rate = 0;
+       int tseg = 0, tseg1 = 0, tseg2 = 0;
+       uint64_t v64;
+
+       /* Use CIA recommended sample points */
+       if (cfg.baudrate > 800000)
+               sampl_pt = 750;
+       else if (cfg.baudrate > 500000)
+               sampl_pt = 800;
+       else
+               sampl_pt = 875;
+
+       /* tseg even = round down, odd = round up */
+       for (tseg = (prop_seg_max + phase_seg1_max + phase_seg2_max) * 2 + 1;
+                tseg >= (prop_seg_min + phase_seg1_min + phase_seg2_min) * 2;
+                tseg--) {
+               /* Compute all posibilities of tseg choices (tseg=tseg1+tseg2) */
+               brp = cfg.clk / ((1 + tseg / 2) * cfg.baudrate) + tseg % 2;
+               /* chose brp step which is possible in system */
+               brp = (brp / brp_inc) * brp_inc;
+               if ((brp < brp_min) || (brp > brp_max))
+                       continue;
+               rate = cfg.clk / (brp * (1 + tseg / 2));
+               error = cfg.baudrate - rate;
+               /* tseg brp biterror */
+
+               if (error < 0)
+                       error = -error;
+               if (error > best_error)
+                       continue;
+               best_error = error;
+               if (error == 0) {
+                       spt = can_update_spt(phase_seg2_min, phase_seg2_max, prop_seg_max, phase_seg1_max, sampl_pt, tseg / 2, &tseg1, &tseg2);
+                       error = sampl_pt - spt;
+                       if (error < 0)
+                               error = -error;
+                       if (error > spt_error)
+                               continue;
+                       spt_error = error;
+               }
+               best_tseg = tseg / 2;
+               best_brp = brp;
+               if (error == 0)
+                       break;
+       }
+
+       if (best_error && (cfg.baudrate / best_error < 10))
+               return -1;
+
+       tseg2 = best_tseg + 1 - (sampl_pt * (best_tseg + 1)) / 1000;
+       spt = can_update_spt(phase_seg2_min, phase_seg2_max, prop_seg_max, phase_seg1_max, sampl_pt, best_tseg, &tseg1, &tseg2);
+
+       if (tseg2 > tseg1)
+               /* sample point < 50% */
+               timing->timing_base_cfg.phase_seg1 = tseg1 / 2;
+       else
+               /* keep phase_seg{1,2} equal around the sample point */
+               timing->timing_base_cfg.phase_seg1 = tseg2;
+       timing->timing_base_cfg.prop_seg = tseg1 - timing->timing_base_cfg.phase_seg1;
+       /* Check prop_seg range if necessary */
+       if (prop_seg_min || prop_seg_max) {
+               if (timing->timing_base_cfg.prop_seg < prop_seg_min)
+                       timing->timing_base_cfg.prop_seg = prop_seg_min;
+               else if (timing->timing_base_cfg.prop_seg > prop_seg_max)
+                       timing->timing_base_cfg.prop_seg = prop_seg_max;
+               timing->timing_base_cfg.phase_seg1 = tseg1 - timing->timing_base_cfg.prop_seg;
+       }
+       timing->timing_base_cfg.phase_seg2 = tseg2;
+       timing->timing_base_cfg.sjw = 1;
+       timing->timing_base_cfg.brp = best_brp;
+       timing->timing_info.error = best_error;
+       timing->timing_info.sampl_pt = spt;
+       v64 = (uint64_t)timing->timing_base_cfg.brp * 1000000000UL;
+       v64 /= cfg.clk;
+       timing->timing_info.tq = (int)v64;
+
+       return SUCCESS;
 }
 
 static int8_t can_configure(canBASE_t *controller, const struct rpp_can_ctrl_config cfg)
 {
-    const uint32_t FREQ = 80000000;
-
-    // Minimal propagation time
-    // NOTE: The time is just guessed from working code
-    const double PROP_MIN = 0.00000075;
-
-    double bit_time, prop_part;
-    uint32_t prescaler, ts, ts1, ts2, prop;
-    uint32_t n;
-    double check;
-
-    /**
-    * Refer to TMS570LS3137 manual (spnu499a) for more information
-    * about calculation of bit timing parameters
-    */
-
-    bit_time = 1.0/cfg.baudrate;
-
-    // We shall abort if bit time isn't integer multiple of CAN clock
-    /**
-    * Some tolerance is needed due to the inaccuracy of binary representation
-    * Feel free to replace those few lines with more elegant solution
-    */
-    check = bit_time * FREQ;
-    if (fabs(check - nearbyint(check)) >= 0.001)
-    {
-       return FAILURE;
-    }
-
-
-    /**
-    * If baudrate is low enough, we set
-    * Prop_Seg = 1, Phase_Seg1 = Phase_Seg2 = SJW = 4
-    * which should be optimal.
-    */
-    if (cfg.baudrate <= 250000)
-    {
-        // 10 stands for 10 time quanta of bit time
-        prescaler = FREQ*bit_time / 10;
-
-        ts2 = ts1 = 4;
-        prop = 1;
-    }
-
-    else
-    {
-        prop_part = PROP_MIN / bit_time;
-
-        if (prop_part <= 0.5)
-        {
-            n = 10;
-            prop = (int) (prop_part / 0.1) + 1;
-        }
-        else
-        {
-            n = 20;
-            prop = (int) (prop_part / 0.05) + 1;
-        }
-
-        ts = n - 1 - prop;
-        ts1 = ts / 2;
-        ts2 = (ts % 2 ? ts1 + 1 : ts1);
-
-        prescaler = FREQ*bit_time / n;
-    }
-
-    /**
-    * We make TSeg2 equal SJW since our calculation guarantees
-    * that TSeg1 >= TSeg2 AND Tseg2 <= 4
-    */
-    // All actual values are by 1 higher than those programmed
-    controller->BTR = (((prescaler-1) >> 6) << 16)
-                      | ((ts2-1) << 12)
-                      | (((ts1+prop)-1) << 8)
-                      | ((ts2-1) << 6)
-                      | ((prescaler-1) & 63);
-
-    return SUCCESS;
+       if (cfg.timing_calc_method == RPP_CAN_TIMING_CALC_AUTO) {
+               struct rpp_can_calculated_timing timing_cfg;
+               if (can_calculate_timing(cfg, &timing_cfg) == SUCCESS)
+                       return can_set_timing(controller, timing_cfg.timing_base_cfg);
+               else
+                       return FAILURE;
+       }
+       else if (cfg.timing_calc_method == RPP_CAN_TIMING_CALC_MANUAL && cfg.timing_config != NULL)
+               return can_set_timing(controller, *cfg.timing_config);
+       else
+               return FAILURE;
 }
 
-static inline can_leave_init(canBASE_t *controller)
+static inline void can_leave_init(canBASE_t *controller)
 {
-    controller->CTL &= ~( (1 << 6) | (1 << 0) );
+       controller->CTL &= ~( (1 << 6) | (1 << 0) );
+
 }
 
 static int8_t reset_box(canBASE_t *controller, uint32_t msg_obj)
 {
-    // Wait until IF1 is ready
-    while (controller->IF1STAT & (1U << 7));
-
-    controller->IF1MSK = 0;
-    controller->IF1ARB = 0;
-    controller->IF1MCTL = (1 << 7) | 8;
-    controller->IF1CMD = (1 << 7)
-                          | (1 << 6)
-                          | (1 << 5)
-                          | (1 << 4);
-    controller->IF1NO = msg_obj;
-
-    return SUCCESS;
+       // Wait until IF1 is ready
+       while (controller->IF1STAT & (1U << 7)) ;
+
+       controller->IF1MSK = 0;
+       controller->IF1ARB = 0;
+       controller->IF1MCTL = (1 << 7) | 8;
+       controller->IF1CMD = (1 << 7)
+                                                | (1 << 6)
+                                                | (1 << 5)
+                                                | (1 << 4);
+       controller->IF1NO = msg_obj;
+
+       return SUCCESS;
 }
 
 static int8_t reset_boxes(void)
 {
-    uint32_t i;
+       uint32_t i;
 
-    for (i=1; i<=64; i++)
-    {
-        reset_box(canREG1, i);
-    }
+       for (i = 1; i <= 64; i++) {
+               reset_box(canREG1, i);
+       }
 
-    for (i=1; i<=64; i++)
-    {
-        reset_box(canREG2, i);
-    }
+       for (i = 1; i <= 64; i++) {
+               reset_box(canREG2, i);
+       }
 
-    for (i=1; i<=32; i++)
-    {
-        reset_box(canREG3, i);
-    }
+       for (i = 1; i <= 32; i++) {
+               reset_box(canREG3, i);
+       }
 
-    return SUCCESS;
+       return SUCCESS;
 }
 
 int8_t can_setup_IF(canBASE_t *controller)
 {
-    // Wait until IF1 is ready
-    while (controller->IF1STAT & (1U << 7));
-
-    /**
-    * 7 Transfer from IF to message object
-    * 5 Transfer arbitration bits
-    * 4 Transfer control bits
-    * 2 Set TxRqst bit
-    * 1 Access data bytes 7-4
-    * 0 Access data bytes 3-0
-    */
-    controller->IF1CMD = (1 << 7)
-                          | (1 << 5)
-                          | (1 << 4)
-                          | (1 << 2)
-                          | (1 << 1)
-                          | (1 << 0);
-
-    // Wait until IF2 is ready
-    while (controller->IF2STAT & (1U << 7));
-
-    /**
-    * 7 Transfer from message object to IF
-    * 5 Transfer arbitration bits
-    * 4 Transfer control bits
-    * 2 Clear NewDat bit
-    * 1 Access data bytes 7-4
-    * 0 Access data bytes 3-0
-    */
-    controller->IF2CMD = (0 << 7)
-                          | (1 << 5)
-                          | (1 << 4)
-                          | (1 << 2)
-                          | (1 << 1)
-                          | (1 << 0);
-
-    return SUCCESS;
+       // Wait until IF1 is ready
+       while (controller->IF1STAT & (1U << 7)) ;
+
+       /**
+        * 7 Transfer from IF to message object
+        * 5 Transfer arbitration bits
+        * 4 Transfer control bits
+        * 2 Set TxRqst bit
+        * 1 Access data bytes 7-4
+        * 0 Access data bytes 3-0
+        */
+       controller->IF1CMD = (1 << 7)
+                                                | (1 << 5)
+                                                | (1 << 4)
+                                                | (1 << 2)
+                                                | (1 << 1)
+                                                | (1 << 0);
+
+       // Wait until IF2 is ready
+       while (controller->IF2STAT & (1U << 7)) ;
+
+       /**
+        * 7 Transfer from message object to IF
+        * 5 Transfer arbitration bits
+        * 4 Transfer control bits
+        * 2 Clear NewDat bit
+        * 1 Access data bytes 7-4
+        * 0 Access data bytes 3-0
+        */
+       controller->IF2CMD = (0 << 7)
+                                                | (1 << 5)
+                                                | (1 << 4)
+                                                | (1 << 2)
+                                                | (1 << 1)
+                                                | (1 << 0);
+
+       return SUCCESS;
 }
 
 int8_t rpp_can_init(const struct rpp_can_config *config)
 {
-    uint16_t i;
-
-    can_config = config;
-
-    if (can_reset(canREG1) == FAILURE)
-       return FAILURE;
-    if (can_reset(canREG2) == FAILURE)
-       return FAILURE;
-    if (can_reset(canREG3) == FAILURE)
-       return FAILURE;
-
-    if (reset_boxes() == FAILURE)
-       return FAILURE;
-
-    for (i=0; i<config->num_tx_obj; i++)
-    {
-        if (init_tx_box(config->tx_config[i]) == FAILURE)
-           return FAILURE;
-    }
-
-    for (i=0; i<config->num_rx_obj; i++)
-    {
-        if (init_rx_box(config->rx_config[i]) == FAILURE)
-           return FAILURE;
-    }
-
-    if (can_setup_IF(canREG1) == FAILURE)
-        return FAILURE;
-    if (can_setup_IF(canREG2) == FAILURE)
-        return FAILURE;
-    if (can_setup_IF(canREG3) == FAILURE)
-        return FAILURE;
-
-    if (can_configure(canREG1, config->ctrl[0]) == FAILURE)
-        return FAILURE;
-    if (can_configure(canREG2, config->ctrl[1]) == FAILURE)
-        return FAILURE;
-    if (can_configure(canREG3, config->ctrl[2]) == FAILURE)
-        return FAILURE;
-
-    if (can_leave_init(canREG1) == FAILURE)
-        return FAILURE;
-    if (can_leave_init(canREG2) == FAILURE)
-        return FAILURE;
-    if (can_leave_init(canREG3) == FAILURE)
-        return FAILURE;
-
-    return SUCCESS;
-}
+       uint16_t i;
+
+       if (!RPP_MUTEX_INIT(mutex_can))
+               return FAILURE;
+
+#ifdef TARGET_TMS570_RPP
+       dmmInit();
+
+       /*
+        * Reset the bus drivers to NORMAL MODE. CAN bus drivers control
+        * voltage regulators for big part of the board and NORMAL MODE
+        * prevents the board from going to sleep mode. Refer TJA1041A
+        * reference for more details about the states of the driver.
+        */
+       dmmREG->PC4 = 1<<13; // set CAN_NSTB
+       dmmREG->PC5 = 1<<15; // clr CAN_EN
+       dmmREG->PC5 = 1<<13; // clr CAN_NSTB
+       dmmREG->PC4 = 1<<13; // set CAN_NSTB
+       dmmREG->PC4 = 1<<15; // set CAN_EN
+#endif
 
+       can_config = config;
+
+       if (can_reset(canREG1) == FAILURE)
+               return FAILURE;
+       if (can_reset(canREG2) == FAILURE)
+               return FAILURE;
+       if (can_reset(canREG3) == FAILURE)
+               return FAILURE;
+
+       if (reset_boxes() == FAILURE)
+               return FAILURE;
+
+       for (i = 0; i < config->num_tx_obj; i++) {
+               if (init_tx_box(config->tx_config[i]) == FAILURE)
+                       return FAILURE;
+       }
+
+       for (i = 0; i < config->num_rx_obj; i++) {
+               if (init_rx_box(config->rx_config[i]) == FAILURE)
+                       return FAILURE;
+       }
+
+       if (can_setup_IF(canREG1) == FAILURE)
+               return FAILURE;
+       if (can_setup_IF(canREG2) == FAILURE)
+               return FAILURE;
+       if (can_setup_IF(canREG3) == FAILURE)
+               return FAILURE;
+
+       if (can_configure(canREG1, config->ctrl[0]) == FAILURE)
+               return FAILURE;
+       if (can_configure(canREG2, config->ctrl[1]) == FAILURE)
+               return FAILURE;
+       if (can_configure(canREG3, config->ctrl[2]) == FAILURE)
+               return FAILURE;
+
+       can_leave_init(canREG1);
+       can_leave_init(canREG2);
+       can_leave_init(canREG3);
+
+       return SUCCESS;
+}
 
 int8_t rpp_can_write(rpp_can_hw_obj hw_obj, const struct rpp_can_pdu *pdu)
 {
-    uint32_t reg_index, bit_index;
-    uint8_t i;
-    canBASE_t *controller;
-    struct rpp_can_tx_config *tx_cfg = &can_config->tx_config[hw_obj];
-
-    if (!(controller = map_controller(tx_cfg->controller)))
-    {
-        return FAILURE;
-    }
-
-    reg_index = (tx_cfg->msg_obj - 1) >> 5;
-    bit_index = 1 << ((tx_cfg->msg_obj - 1) & 0x1FU);
-
-    // FIXME: Check whether sending should be aborted or message overwritten
-    if (controller->TXRQx[reg_index] & bit_index)
-    {
-        return FAILURE;
-    }
-
-
-    // Wait until IF1 is ready to use
-    while (controller->IF1STAT & (1U << 7));
-
-    // Reset data length code
-    controller->IF1MCTL &= ~15;
-    controller->IF1MCTL |= pdu->dlc & 0xF;
-
-    /**
-    * 31 Message is valid
-    * 30 Whether std/ext ID should be used
-    * 29 Direction is transmit
-    * 28-18 / 28-0 Message ID
-    */
-    controller->IF1ARB = (1 << 31)
-                          | ((tx_cfg->type == RPP_CAN_STANDARD ? 0 : 1) << 30)
-                          | (1 << 29)
-                          | (pdu->id << (tx_cfg->type == RPP_CAN_STANDARD ? 18 : 0));
-
-    for (i=0; i<pdu->dlc; i++)
-    {
+       uint8_t i;
+       canBASE_t *controller;
+       struct rpp_can_tx_config *tx_cfg = &can_config->tx_config[hw_obj];
+
+       if (!(controller = map_controller(tx_cfg->controller)))
+               return -RPP_EINVAL;
+
+       RPP_MUTEX_LOCK(mutex_can);
+
+       // Wait until IF1 is ready to use
+       while (controller->IF1STAT & (1U << 7)) ;
+
+       // Reset data length code
+       controller->IF1MCTL &= ~15;
+       controller->IF1MCTL |= pdu->dlc & 0xF;
+
+       /**
+        * 31 Message is valid
+        * 30 Whether std/ext ID should be used
+        * 29 Direction is transmit
+        * 28-18 / 28-0 Message ID
+        */
+       controller->IF1ARB = (1 << 31)
+                                                | ((tx_cfg->type == RPP_CAN_STANDARD ? 0 : 1) << 30)
+                                                | (1 << 29)
+                                                | (pdu->id << (tx_cfg->type == RPP_CAN_STANDARD ? 18 : 0));
+
+       for (i = 0; i < pdu->dlc; i++) {
 #ifdef __little_endian__
-        controller->IF1DATx[i] = pdu->data[i];
+               controller->IF1DATx[i] = pdu->data[i];
 #else
-        controller->IF1DATx[s_can_byte_order[i]] = pdu->data[i];
+               controller->IF1DATx[s_can_byte_order[i]] = pdu->data[i];
 #endif
-    }
+       }
 
-    // Copy TX data into message box
-    controller->IF1NO = tx_cfg->msg_obj;
+       // Copy TX data into message box
+       controller->IF1NO = tx_cfg->msg_obj;
 
-    return SUCCESS;
+       RPP_MUTEX_UNLOCK(mutex_can);
+
+       return SUCCESS;
 }
 
 
-int8_t rpp_can_check_tx_con(rpp_can_hw_obj hw_obj, bool *tx_con)
+int8_t rpp_can_check_tx_pend(rpp_can_hw_obj hw_obj, bool *tx_pend)
 {
-    uint32_t reg_index, bit_index;
-    canBASE_t *controller;
+       uint32_t reg_index, bit_mask;
+       canBASE_t *controller;
 
-    if (!(controller = map_controller(can_config->tx_config[hw_obj].controller)))
-    {
-        return FAILURE;
-    }
+       if (!(controller = map_controller(can_config->tx_config[hw_obj].controller)))
+               return FAILURE;
 
-    reg_index = can_config->tx_config[hw_obj].msg_obj >> 5;
-    bit_index = 1 << ((can_config->tx_config[hw_obj].msg_obj - 1) & 0x1FU);
+       reg_index = can_config->tx_config[hw_obj].msg_obj >> 5;
+       bit_mask = 1 << ((can_config->tx_config[hw_obj].msg_obj - 1) & 0x1FU);
 
-    *tx_con = controller->TXRQx[reg_index] & bit_index;
+       *tx_pend = controller->TXRQx[reg_index] & bit_mask;
 
-    return SUCCESS;
+       return SUCCESS;
 }
 
 int8_t rpp_can_read(rpp_can_hw_obj hw_obj, struct rpp_can_pdu *pdu)
 {
-    uint32_t reg_index, bit_index;
-    uint32_t i;
-    canBASE_t *controller;
-
-    if (!(controller = map_controller(can_config->rx_config[hw_obj].controller)))
-    {
-        return FAILURE;
-    }
-
-    reg_index = (can_config->rx_config[hw_obj].msg_obj - 1) >> 5;
-    bit_index = 1 << ((can_config->rx_config[hw_obj].msg_obj - 1) & 0x1FU);
-
-    // FIXME: Check whether to abort if there are no new data
-    if (!(controller->NWDATx[reg_index] & bit_index))
-    {
-        return FAILURE;
-    }
-
-    // Wait until IF2 is ready to use
-    while (controller->IF2STAT & (1U << 7));
-
-    // Copy data into IF2
-    controller->IF2NO = can_config->rx_config[hw_obj].msg_obj;
-
-    // Wait until IF2 is ready to use
-    while (controller->IF2STAT & (1U << 7));
-
-    // Get length of data received
-    pdu->dlc = controller->IF2MCTL & 0xFU;
-
-    // Get message ID
-    if (controller->IF2ARB & (1 << 30))
-    {
-        pdu->id = (controller->IF2ARB & 0x1FFFFFFF) | CAN_EFF_FLAG;
-    }
-    else
-    {
-        pdu->id = (controller->IF2ARB & (0x7FF << 18)) >> 18;
-    }
-
-    // Copy RX data into pdu
-    for (i=0; i<pdu->dlc; i++)
-    {
+       uint32_t reg_index, bit_mask;
+       uint32_t i;
+       canBASE_t *controller;
+
+       if (!(controller = map_controller(can_config->rx_config[hw_obj].controller)))
+               return -RPP_EINVAL;
+
+       reg_index = (can_config->rx_config[hw_obj].msg_obj - 1) >> 5;
+       bit_mask = 1 << ((can_config->rx_config[hw_obj].msg_obj - 1) & 0x1FU);
+
+       RPP_MUTEX_LOCK(mutex_can);
+
+       // FIXME: Check whether to abort if there are no new data
+       if (!(controller->NWDATx[reg_index] & bit_mask)) {
+               RPP_MUTEX_UNLOCK(mutex_can);
+               return -RPP_ENODATA;
+       }
+
+       // Wait until IF2 is ready to use
+       while (controller->IF2STAT & (1U << 7)) ;
+
+       // Copy data into IF2
+       controller->IF2NO = can_config->rx_config[hw_obj].msg_obj;
+
+       // Wait until IF2 is ready to use
+       while (controller->IF2STAT & (1U << 7)) ;
+
+       // Get length of data received
+       pdu->dlc = controller->IF2MCTL & 0xFU;
+
+       // Get message ID
+       if (controller->IF2ARB & (1 << 30))
+               pdu->id = (controller->IF2ARB & 0x1FFFFFFF) | CAN_EFF_FLAG;
+       else
+               pdu->id = (controller->IF2ARB & (0x7FF << 18)) >> 18;
+
+       // Copy RX data into pdu
+       for (i = 0; i < pdu->dlc; i++) {
 #ifdef __little_endian__
-        pdu->data[i] = controller->IF2DATx[i];
+               pdu->data[i] = controller->IF2DATx[i];
 #else
-        pdu->data[i] = controller->IF2DATx[s_can_byte_order[i]];
+               pdu->data[i] = controller->IF2DATx[s_can_byte_order[i]];
 #endif
-    }
+       }
+
+       RPP_MUTEX_UNLOCK(mutex_can);
 
-    return SUCCESS;
+       return SUCCESS;
 }
 
 int8_t rpp_can_check_rx_ind(rpp_can_hw_obj hw_obj, bool *rx_ind)
 {
-    uint32_t reg_index, bit_index;
-    canBASE_t *controller;
+       uint32_t reg_index, bit_mask;
+       canBASE_t *controller;
 
-    if (!(controller = map_controller(can_config->rx_config[hw_obj].controller)))
-    {
-        return FAILURE;
-    }
+       if (!(controller = map_controller(can_config->rx_config[hw_obj].controller)))
+               return FAILURE;
 
-    reg_index = (can_config->rx_config[hw_obj].msg_obj - 1) >> 5;
-    bit_index = 1 << ((can_config->rx_config[hw_obj].msg_obj - 1) & 0x1FU);
+       reg_index = (can_config->rx_config[hw_obj].msg_obj - 1) >> 5;
+       bit_mask = 1 << ((can_config->rx_config[hw_obj].msg_obj - 1) & 0x1FU);
 
-    *rx_ind = controller->NWDATx[reg_index] & bit_index;
+       *rx_ind = controller->NWDATx[reg_index] & bit_mask;
 
-    return SUCCESS;
+       return SUCCESS;
 }
-
-
-
-#endif /* rppCONFIG_INCLUDE_CAN */