]> rtime.felk.cvut.cz Git - pes-rpp/rpp-test-sw.git/blobdiff - rpp-test-sw/commands/cmd_can.c
candump: Ensure than controller ID is not out of range
[pes-rpp/rpp-test-sw.git] / rpp-test-sw / commands / cmd_can.c
index 2246cec02b629bb2321f46865db34263bf1fa909..f98422b50822027b9b7bdcd8430435b356ae7fab 100644 (file)
@@ -1,28 +1,20 @@
 /*
- * Copyright (C) 2012-2013 Czech Technical University in Prague
+ * Copyright (C) 2012-2014 Czech Technical University in Prague
  *
  * Created on: 28.2.2013
  *
  * Authors:
  *     - Michal Horn
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * This document contains proprietary information belonging to Czech
+ * Technical University in Prague. Passing on and copying of this
+ * document, and communication of its contents is not permitted
+ * without prior written authorization.
  *
  * File : cmd_can.c
  *
  * Abstract:
- *     This file contains commands for CAN test
+ *      This file contains commands for CAN test
  *
  */
 
 #include "sys/sys.h"
 #include <stdio.h>
 
-/** Semaphore used for blocking task until message is received */
-extern xSemaphoreHandle canMsgReceived;
-/** Semaphore used for blocking task until message is sent */
-extern xSemaphoreHandle canMsgSent;
-/** Pointer to Destination CAN registers */
-extern canBASE_t* canDst;
-/** Pointer to Source CAN registers */
-extern canBASE_t* canSrc;
-/** Can message box for received messages */
-extern uint32_t canMsgBox;
-/** Error counter for errors in sending */
-extern uint32_t canSendError;
-/** Error counter for errors in receiving */
-extern uint32_t canRecError;
-
-static void canPrintStatus(int can_num, uint32_t es)
-{
-       uint32_t errorLevel = es & 0xE0U;
-       char* levText;
-
-       switch (errorLevel) {
-       case canLEVEL_BUS_OFF:
-               levText = "Bus-Off";
-               break;
-       case canLEVEL_PASSIVE:
-               levText = "Error Passive";
-               break;
-       case canLEVEL_WARNING:
-               levText = "Warning";
-               break;
-       case canLEVEL_ACTIVE:
-               levText = "Bus-On";
-               break;
-       default:
-               levText = "Unknown";
-       }
-
-       rpp_sci_printf("CAN%d status: %s, ES: %#x\n", can_num, levText, es);
-}
-
-uint32_t canCheckForError(int can_num, uint32_t es)
-{
-       uint32_t errorLevel = es & 0xE0U;
-
-       if (errorLevel != 0) {
-               canPrintStatus(can_num, es);
-       }
-
-       return errorLevel;
-}
-
-/**
- *     @brief  Command for external CAN loopback testing.
- *
- * @param[in]  cmd_io  Pointer to IO stack
- * @param[in]  des             Pointer to command descriptor
- * @param[in]  param   Parameters of command
- * @return     0 when OK or error code
+/*
+ * Error codes definitions for RPP CAN functions tests.
  */
-int cmd_do_test_can_loopback(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
-{
-       uint32_t can_src, can_dst;
-       canBASE_t *canBases[3] = {canREG1, canREG2, canREG3};
-       uint32_t canMailBoxes[3] = {canMESSAGE_BOX1, canMESSAGE_BOX2, canMESSAGE_BOX3};
-       uint32_t txTimeOutCnt = 0;
-       uint32_t rxTimeOutCnt = 0;
-       uint32_t messagesTransmitted = 0;
-       uint32_t messagesReceived = 0;
-       uint32_t i;
-       uint8_t tx_data[8] = {'T', 'E', 'S', 'T', ' ', 'C', 'A', 'N'};
-       uint8_t rx_data[8] = {0, 0, 0, 0, 0, 0, 0, 0 };
-       char *p=param[1];
-       char spareParams;
-
-
-       dmmREG->PC4 = (1<<(13)); // set CAN_NSTB
-       vTaskDelay(50/portTICK_RATE_MS);
-       dmmREG->PC5 = (1<<(15)); // clr CAN_EN
-       vTaskDelay(50/portTICK_RATE_MS);
-       dmmREG->PC5 = (1<<(13)); // clr CAN_NSTB
-       vTaskDelay(50/portTICK_RATE_MS);
-       dmmREG->PC4 = (1<<(13)); // set CAN_NSTB
-       vTaskDelay(50/portTICK_RATE_MS);
-       dmmREG->PC4 = (1<<(15)); // set CAN_EN
-       vTaskDelay(50/portTICK_RATE_MS);
-
-
-       if (sscanf(p, "%d %d %1s", &can_src, &can_dst, &spareParams) != 2) {
-               return -CMDERR_BADPAR;
-       }
-
-       if (can_src == can_dst) {
-               rpp_sci_printf("ERROR: Destination equals source!\n");
-               return 1;
-       }
-       if (can_src < 1 | can_dst > 3) {
-               rpp_sci_printf("Parameter out of range <1;3>!\n");
-               return 1;
-       }
-       canSrc = canBases[can_src-1];
-       canDst = canBases[can_dst-1];
-       canMsgBox = canMailBoxes[can_src-1];
-       canMsgReceived = xSemaphoreCreateCounting(1, 0);
-       canMsgSent = xSemaphoreCreateCounting(1, 0);
-
-       rpp_sci_printf("Testing CAN loopback\r\n");
-       canREG1->CTL |= 1|(1<<9);
-       canREG2->CTL |= 1|(1<<9);
-       canREG3->CTL |= 1|(1<<9);
-       canRecError = 0;
-       canDst->CTL |= 1<<15;           // Reset
-       while (canDst->CTL & (1<<15)) ; // Wait for reset
-       canSendError = 0;
-       canSrc->CTL |= 1<<15;
-       while (canSrc->CTL & (1<<15)) ;
-       canInit();
-       canDst->CTL |= 1<<9;
-       canSrc->CTL |= 1<<9;
-       vTaskDelay(50/portTICK_RATE_MS);
-
-       i = canSrc->ES; // Reset error flag
-       i = canDst->ES; // Reset error flag
-       canEnableErrorNotification(canDst);
-       canEnableErrorNotification(canSrc);
-
-       for (i = 0; i < 100; i++) {             // Send 100 times the message
-               if (canCheckForError(can_src, canSendError) != canLEVEL_ACTIVE) {
-                       break;
-               }
-               canTransmit(canSrc, canMsgBox, tx_data);
-               if (xSemaphoreTake(canMsgSent, 100/portTICK_RATE_MS) == pdFALSE) {
-                       txTimeOutCnt++;
-               }
-               else {
-                       if (canCheckForError(can_src, canSendError) & canLEVEL_BUS_OFF) {
-                               break;
-                       }
-                       else {
-                               messagesTransmitted++;
-                               if (xSemaphoreTake(canMsgReceived, 100/portTICK_RATE_MS) == pdFALSE) {
-                                       rxTimeOutCnt++;
-                               }
-                               else {
-                                       if (canGetData(canDst, canMsgBox, rx_data))
-                                               messagesReceived++;
-
-                                       if (canCheckForError(can_dst, canRecError) & canLEVEL_BUS_OFF) {
-                                               break;
-                                       }
-                               }
-                       }
-               }
+#define ERR_CCT_HW_OBJ                  0x0001  /**< Wrong HW object passed to the RPP CAN function. */
+#define ERR_CCT_MSG_MISMATCH            0x0010  /**< Received message does not match to the sent message. */
+#define ERR_CCT_RX_IND_NOT_CLEARED      0x0020  /**< Message received indicator was not cleared by the rpp_can_read function.  */
+#define ERR_CCT_RX_IND_SET_NO_MSG_REC   0x0040  /**< Message received indicator is set, but no message could be retrieved by the rpp_can_read function. */
+#define ERR_CCT_RECV_TIMEOUT            0x0100  /**< Message receive timeout reached. */
+#define ERR_CCT_CLEAR_TX_PEND_TO        0x0200  /**< Timeout reached for waiting for the clearance of the transmission request flag. */
+#define ERR_CCT_SET_TX_PEND_TO          0x0400  /**< Timeout reached for waiting until the transmission request flag is set after the request is posted. */
+#define ERR_CCT_INIT                    0x1000  /**< Error while initializing the CAN bus. */
+#define ERR_CCT_SEND                    0x2000  /**< Error while sending a CAN message. */
+#define ERR_CCT_RCV                     0x4000  /**< Error while receiving a CAN message */
+#define ERR_CCT_UNEXPECTED_RETVAL       0x0008  /**< Unexpected return value has been returned from some RPP CAN function. */
+
+#define CCT_TIMEOUT         100000  /**< Timeout for RPP CAN test steps. */
 
-               rpp_sci_printf("Messages transmitted: %d/100\r\n", messagesTransmitted);
-               rpp_sci_printf("Messages received: %d/100\r\n", messagesReceived);
-               rpp_sci_printf("TX timeouts: %d\r\n", txTimeOutCnt);
-               rpp_sci_printf("RX timeouts: %d\r\n", rxTimeOutCnt);
-               rpp_sci_printf("Src TX error counter: %d\r\n", canSrc->EERC & 0xFFU);
-               rpp_sci_printf("Src RX error counter: %d\r\n", (canSrc->EERC & 0xFF00U) >> 8);
-               rpp_sci_printf("Dst TX error counter: %d\r\n", canDst->EERC & 0xFFU);
-               rpp_sci_printf("Dst RX error counter: %d\r\n", (canDst->EERC & 0xFF00U) >> 8);
-               canPrintStatus(can_src, canSendError);
-               canPrintStatus(can_dst, canRecError);
-
-               canDisableErrorNotification(canDst);
-               canDisableErrorNotification(canSrc);
-               vSemaphoreDelete(canMsgReceived);
-               vSemaphoreDelete(canMsgSent);
-               return 0;
-       }
-       return 0;
-}
+static int can_inited = 0;
 
+/* Default CAN timing set to 500kb */
+static struct rpp_can_timing_cfg can_timing[] = {
+       {
+               .brp = 10,
+               .phase_seg1 = 5,
+               .phase_seg2 = 2,
+               .prop_seg = 8,
+               .sjw = 1
+       },
+       {
+               .brp = 10,
+               .phase_seg1 = 5,
+               .phase_seg2 = 2,
+               .prop_seg = 8,
+               .sjw = 1
+       },
+       {
+               .brp = 10,
+               .phase_seg1 = 5,
+               .phase_seg2 = 2,
+               .prop_seg = 8,
+               .sjw = 1
+       },
+};
 
-static int can_inited = 0;
 
 static struct rpp_can_ctrl_config ctrl_config[] = {
        {
-               .baudrate = 500000
+               .baudrate = 500000,
+               .clk = 80000000,
+               .timing_calc_method = RPP_CAN_TIMING_CALC_AUTO,
+               .timing_config = NULL
        },
        {
-               .baudrate = 500000
+               .baudrate = 500000,
+               .clk = 80000000,
+               .timing_calc_method = RPP_CAN_TIMING_CALC_AUTO,
+               .timing_config = NULL
        },
        {
-               .baudrate = 500000
+               .baudrate = 500000,
+               .clk = 80000000,
+               .timing_calc_method = RPP_CAN_TIMING_CALC_AUTO,
+               .timing_config = NULL
        }
 };
 
@@ -246,25 +116,25 @@ static struct rpp_can_rx_config rx_config[] = {
                .controller = 1,
                .msg_obj = 1,
                .id = 1,
-               .mask = 0,
+               .mask = 0x7fffff,
        },
        {
                .type = RPP_CAN_MIXED,
                .controller = 2,
                .msg_obj = 1,
                .id = 1,
-               .mask = 0,
+               .mask = 0x7fffff,
        },
        {
                .type = RPP_CAN_MIXED,
                .controller = 3,
                .msg_obj = 1,
                .id = 1,
-               .mask = 0,
+               .mask = 0x7fffff,
        }
 };
 
-static struct rpp_can_config can_config = {
+struct rpp_can_config can_config = {
        .num_tx_obj = 3,
        .num_rx_obj = 3,
        .tx_config = tx_config,
@@ -272,19 +142,531 @@ static struct rpp_can_config can_config = {
        .ctrl = ctrl_config,
 };
 
+/*
+ * Structures for RPP CAN functions tests.
+ */
+
+/**
+ * CAN test bit timings configurations.
+ */
+struct rpp_can_timing_cfg can_test_timing[] = {
+       {
+               .brp = 10,
+               .prop_seg = 8,
+               .phase_seg1 = 5,
+               .phase_seg2 = 2,
+               .sjw = 1
+       },
+       {
+               .brp = 10,
+               .prop_seg = 8,
+               .phase_seg1 = 5,
+               .phase_seg2 = 2,
+               .sjw = 1
+       },
+       {
+               .brp = 10,
+               .prop_seg = 8,
+               .phase_seg1 = 5,
+               .phase_seg2 = 2,
+               .sjw = 1
+       },
+};
 
-int cmd_do_can_init(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
+/**
+ * CAN test controllers configurations.
+ */
+struct rpp_can_ctrl_config can_test_ctrl_cfg[] = {
+       {
+               .baudrate = 500000,
+               .clk = 80000000,
+               .timing_calc_method = RPP_CAN_TIMING_CALC_MANUAL,
+               .timing_config = &can_test_timing[0]
+       },
+       {
+               .baudrate = 500000,
+               .clk = 80000000,
+               .timing_calc_method = RPP_CAN_TIMING_CALC_MANUAL,
+               .timing_config = &can_test_timing[1]
+       },
+       {
+               .baudrate = 500000,
+               .clk = 80000000,
+               .timing_calc_method = RPP_CAN_TIMING_CALC_MANUAL,
+               .timing_config = &can_test_timing[2]
+       },
+};
+
+/**
+ * CAN test TX configuration.
+ */
+struct rpp_can_tx_config can_test_tx_cfg[] = {
+       {
+               .type = RPP_CAN_STANDARD,
+               .controller = 1,
+               .msg_obj = 1
+       }
+};
+
+/**
+ * CAN test RX configuration.
+ */
+struct rpp_can_rx_config can_test_rx_cfg[] = {
+       {
+               .type = RPP_CAN_STANDARD,
+               .controller = 2,
+               .id = 0x1,
+               .mask = 1,
+               .msg_obj = 1
+       }
+};
+
+/**
+ * Root CAN test configuration structure
+ */
+struct rpp_can_config can_test_cfg = {
+       .num_tx_obj = 1,
+       .num_rx_obj = 1,
+       .tx_config = can_test_tx_cfg,
+       .rx_config = can_test_rx_cfg,
+       .ctrl = can_test_ctrl_cfg
+};
+
+/**
+ * Compare two CAN messages.
+ *
+ * @param[in] pdu1 CAN message 1
+ * @param[in] pdu2 CAN message 2
+ * @return TRUE, if the two CAN messages are equal.
+ */
+boolean_t cmd_can_messages_equal(const struct rpp_can_pdu *pdu1, const struct rpp_can_pdu *pdu2)
+{
+       boolean_t pdus_equal = TRUE;
+
+       if (pdu1->id != pdu2->id ||
+               pdu1->dlc != pdu2->dlc)
+               pdus_equal = FALSE;
+       else {
+               uint8_t i = 0;
+               for (i = 0; i < pdu1->dlc; i++) {
+                       if (pdu1->data[i] != pdu1->data[i]) {
+                               pdus_equal = FALSE;
+                               break;
+                       }
+               }
+       }
+       return pdus_equal;
+}
+
+/**
+ * Initialize the CAN bus driver for tests.
+ *
+ * @param[in] timing_calc Select RPP_CAN_TIMING_CALC_AUTO for automatic CAN bit timing calculation
+ * for a baudrate specified by desired_baudrate. Select RPP_CAN_TIMING_CALC_MANUAL for configuring the
+ * CAN bus to 500kbits/sec with verified bit timing parameters generated by HALCoGen.
+ *
+ * @return SUCCESS if the test passed, FAILURE otherwise.
+ */
+int cmd_can_test_init(enum rpp_can_timing_calculation timing_calc, uint32_t desired_baudrate)
+{
+       can_test_cfg.ctrl[0].baudrate = desired_baudrate;
+       can_test_cfg.ctrl[0].timing_calc_method = timing_calc;
+       can_test_cfg.ctrl[1].baudrate = desired_baudrate;
+       can_test_cfg.ctrl[1].timing_calc_method = timing_calc;
+       can_test_cfg.ctrl[2].baudrate = desired_baudrate;
+       can_test_cfg.ctrl[2].timing_calc_method = timing_calc;
+
+       if (rpp_can_init(&can_test_cfg) == SUCCESS)
+               return SUCCESS;
+       else
+               return FAILURE;
+}
+
+/**
+ * General test for receiving of message.
+ *
+ * This function verifies that the rpp_can_read() function is working
+ * properly and that the CAN driver behaves as expected.
+ *
+ * This is a blocking function that tries to receive a CAN message. The reception
+ * has to finish until specified timeout is reached.
+ * The received message is compared with the transmitted one.
+ *
+ * @param[in] can_tx_pdu A message pattern, which should be received. Used for RX
+ * and TX equality verification.
+ * @param[in] timeout How long should the test wait for the message.
+ * @return SUCCESS if the test passed, error code otherwise.
+ */
+int cmd_can_test_recv(const struct rpp_can_pdu *can_tx_pdu, uint32_t timeout)
+{
+       boolean_t msg_received = FALSE;
+       volatile uint32_t rec_time = 0;
+       struct rpp_can_pdu can_rx_pdu;
+
+       while (!msg_received) {
+               int ret = rpp_can_read(0, &can_rx_pdu);
+               switch (ret) {
+               case -RPP_EINVAL:
+                       return ERR_CCT_HW_OBJ;
+               case -RPP_ENODATA:
+                       if (++rec_time >= CCT_TIMEOUT)
+                               return ERR_CCT_RECV_TIMEOUT;
+                       break;
+               case SUCCESS:
+                       if (!cmd_can_messages_equal(&can_rx_pdu, can_tx_pdu))
+                               return ERR_CCT_MSG_MISMATCH;
+                       else
+                               msg_received = TRUE;
+                       break;
+               default:
+                       return ERR_CCT_UNEXPECTED_RETVAL;
+               }
+       }
+       return SUCCESS;
+}
+
+/**
+ * General test of sending a message.
+ *
+ * This function verifies that the rpp_can_write() function is working
+ * properly and that the CAN driver behaves as expected.
+ *
+ * @param[in] can_tx_msg A message for transmission.
+ * @return SUCCESS if the test passed, error code otherwise.
+ */
+int cmd_can_test_send(const struct rpp_can_pdu *can_tx_msg)
+{
+       if (rpp_can_write(0, can_tx_msg) != SUCCESS)
+               return ERR_CCT_HW_OBJ;
+       return SUCCESS;
+}
+
+/**
+ * General test of sending and receiving mechanism.
+ *
+ * This function verifies that the rpp_can_write() and rpp_can_read() functions
+ * are working properly and that the CAN driver behaves as expected.
+ *
+ * The message specified as a parameter is sent on the CAN bus and received to
+ * another mailbox. The received message is compared with the sent one.
+ *
+ * @param[in] can_tx_msg A message used to testing
+ * @return SUCCESS if the test passed, error code otherwise.
+ */
+int cmd_can_test_simple_send_recv(const struct rpp_can_pdu *can_tx_msg)
+{
+       int ret_val = 0;
+
+       if ((ret_val = cmd_can_test_send(can_tx_msg)) != SUCCESS)
+               return ERR_CCT_SEND|ret_val;
+       else if ((ret_val = cmd_can_test_recv(can_tx_msg, CCT_TIMEOUT)) != SUCCESS)
+               return ERR_CCT_RCV|ret_val;
+
+       return SUCCESS;
+}
+
+/**
+ * Test automatic CAN bit timing calculation for the specified baudrate.
+ *
+ * @param[in] tested_baudrate Desired baudrate.
+ * @param[in] can_tx_msg A message used to testing.
+ * @return SUCCESS if the test passed, error code otherwise.
+ *
+ */
+int cmd_can_test_baudrate_calc(uint32_t tested_baudrate,const struct rpp_can_pdu *can_tx_msg)
+{
+       int ret_val = 0;
+
+       if ((ret_val = cmd_can_test_init(RPP_CAN_TIMING_CALC_AUTO, 125000)) != SUCCESS)
+               return ERR_CCT_INIT|ret_val;
+       else if ((ret_val = cmd_can_test_simple_send_recv(can_tx_msg)) != SUCCESS)
+               return ret_val;
+
+       return SUCCESS;
+}
+
+/**
+ * Test behavioral of two consecutive TX requests posting.
+ *
+ * This function verifies that the rpp_can_write() function is working properly and
+ * that the CAN driver behaves as expected.
+ *
+ * According to the behavioral defined by tha Autosar, the rpp_can_write() should not fail when
+ * new transmission request comes before the previous one has been processed. The function should
+ * overwrite the old request and only the new one should be transmitted.
+ *
+ * @param[in] can_tx_msg1 A message which transmission is requested foremost.
+ * @param[in] can_tx_msg2 A message, which transmission is requested right after the can_tx_msg1
+ * @return SUCCESS if the test passed, error code otherwise.
+ */
+int cmd_can_test_tx_request_replace(const struct rpp_can_pdu *can_tx_msg1, const struct rpp_can_pdu *can_tx_msg2)
+{
+       int ret_val = 0;
+
+       if ((ret_val = cmd_can_test_send(can_tx_msg1)) != SUCCESS)
+               return ret_val;
+       else if ((ret_val = cmd_can_test_simple_send_recv(can_tx_msg2)) != SUCCESS)
+               return ret_val;
+
+       return SUCCESS;
+}
+
+/**
+ * Test the TX request flag.
+ *
+ * This function verifies that the rpp_can_check_tx_pend() function is working properly and
+ * that the CAN driver behaves as expected.
+ *
+ * The TX request flag should be clear if no transmission request is pending. Once a rpp_can_write()
+ * is called a new transmission requst is posted and the TX request flag should be set, until the CAN
+ * bus driver sends the message. After the transmission is finished, the flag should be cleared.
+ *
+ * @param[in] rpp_can_pdu A message which used to testing.
+ * @param[out] time Measured time between posting the transmission request and setting the TX request flag.
+ * @return SUCCESS if the test passed, error code otherwise.
+ */
+int cmd_can_test_tx_request_flag(const struct rpp_can_pdu *can_tx_msg, uint32_t *time)
+{
+       *time = 0;
+       uint32_t timeout = 0;
+       boolean_t tx_pend = FALSE;
+       int ret_val = 0;
+       if ((ret_val = cmd_can_test_send(can_tx_msg)) != SUCCESS)
+               return ret_val;
+       else {
+               /* Wait for the flag to be set */
+               while (!tx_pend) {
+                       if (++timeout > CCT_TIMEOUT)
+                               return ERR_CCT_SET_TX_PEND_TO;
+                       if (rpp_can_check_tx_pend(0, &tx_pend) == FAILURE)
+                               return ERR_CCT_HW_OBJ;
+               }
+               timeout = 0;
+               while (tx_pend) {
+                       if (rpp_can_check_tx_pend(0, &tx_pend) == FAILURE)
+                               return ERR_CCT_HW_OBJ;
+                       (*time)++;
+                       if (++timeout > CCT_TIMEOUT)
+                               return ERR_CCT_CLEAR_TX_PEND_TO;
+               }
+               if ((ret_val = cmd_can_test_recv(can_tx_msg, CCT_TIMEOUT)) != SUCCESS)
+                       return ERR_CCT_RCV|ret_val;
+       }
+
+       return SUCCESS;
+}
+
+/**
+ * Test the RX indicator.
+ *
+ * This function verifies that the rpp_can_check_rx_ind() function is working properly and
+ * that the CAN driver behaves as expected.
+ *
+ * The RX indicator should be set whenever new CAN message is received and remains set, until
+ * rpp_can_read() is called in order to retrieve the message.
+ *
+ * @param[in] rpp_can_pdu A message which used to testing.
+ * @param[out] time Measured time between posting the transmission request and setting the RX flag.
+ * @return SUCCESS if the test passed, error code otherwise.
+ */
+int cmd_can_test_rx_indicator(const struct rpp_can_pdu *can_tx_msg, uint32_t *time)
 {
-    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
+       *time = 0;
+       volatile uint32_t timeout = 0;
+       boolean_t rx_ind = FALSE;
+       int ret_val = 0;
+       struct rpp_can_pdu can_rx_pdu;
+
+       if ((ret_val = cmd_can_test_send(can_tx_msg)) != SUCCESS)
+               return ret_val;
+       else {
+               /* Wait for the flag to be set */
+               while (!rx_ind) {
+                       if (rpp_can_check_rx_ind(0, &rx_ind) == FAILURE)
+                               return ERR_CCT_HW_OBJ;
+                       (*time)++;
+                       if (++timeout > CCT_TIMEOUT)
+                               return ERR_CCT_SET_TX_PEND_TO;
+               }
 
+               if ((ret_val = rpp_can_read(0, &can_rx_pdu)) != SUCCESS) {
+                       switch (ret_val) {
+                       case -RPP_ENODATA:
+                               return ERR_CCT_RX_IND_SET_NO_MSG_REC;
+                       case -RPP_EINVAL:
+                               return ERR_CCT_HW_OBJ;
+                       default:
+                               return ERR_CCT_UNEXPECTED_RETVAL;
+                       }
+               }
+               else {
+                       if (!cmd_can_messages_equal(&can_rx_pdu, can_tx_msg))
+                               return ERR_CCT_MSG_MISMATCH;
+                       else {
+                               if (rpp_can_check_rx_ind(0, &rx_ind) == FAILURE)
+                                       return ERR_CCT_HW_OBJ;
+                               if (rx_ind == TRUE)
+                                       return ERR_CCT_RX_IND_NOT_CLEARED;
+                       }
+               }
+       }
+
+       return SUCCESS;
+}
 
+/**
+ * Test CAN functions from RPP library.
+ *
+ * This is a complex test command for verification of automatic CAN bit timing
+ * calculation for baudrates 125k, 250k and 500kbits/sec and for checking RPP
+ * CAN functions:
+ * - rpp_can_init()
+ * - rpp_can_write()
+ * - rpp_can_read()
+ * - rpp_can_check_rx_ind()
+ * - rpp_can_check_tx_pend()
+ *
+ * @return always SUCCESS
+ */
+int cmd_do_can_test_functions(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
+{
+       struct rpp_can_pdu can_tx_msg1 = {
+               .id = 0x1,
+               .dlc = 8,
+               .data = {'H', 'E', 'L', 'L', 'O', '0', '0', '1'}
+       };
+
+       struct rpp_can_pdu can_tx_msg2 = {
+               .id = 0x1,
+               .dlc = 8,
+               .data = {'H', 'E', 'L', 'L', 'O', '0', '0', '2'}
+       };
+
+       rpp_sci_printf("This is a test for RPP CAN library functions:\n");
+       /*
+        * Simple send and receive a message with CAN bit time parameters for 500 kb/sec, picked
+        * from HALCoGen, which are proven to be functional.
+        */
+       rpp_sci_printf("Test of simple message transmission and reception.\n");
+       int ret_val = 0;
+       rpp_sci_printf("\tCAN bus Initialization: ");
+       if ((ret_val = cmd_can_test_init(RPP_CAN_TIMING_CALC_MANUAL, 500000)) != SUCCESS)
+               rpp_sci_printf("failed: error: 0x%X.\n", ret_val);
+       else {
+               rpp_sci_printf("OK\n");
+               rpp_sci_printf("\tTransmission and reception...");
+               if ((ret_val = cmd_can_test_simple_send_recv(&can_tx_msg1)) != SUCCESS)
+                       rpp_sci_printf("failed: error: 0x%X.\n", ret_val);
+               else
+                       rpp_sci_printf("OK\n");
+       }
+       rpp_sci_printf("---\n");
+       /* Baudrate calculation testing
+        *
+        * Based on EATON requirements for baudrates: 125k, 250k, 500k
+        *  - calculate bit timing parameters,
+        *  - initialize the CAN bus,
+        *  - send a message
+        *  - receive a message
+        *  - test if the received message is OK.
+        */
+       uint32_t baudrates[] = {125000, 250000, 500000};
+       uint8_t num_baudrates = 3;
+       uint8_t i;
+       rpp_sci_printf("Test of automatic CAN bit timing calculation.\n");
+
+       for (i = 0; i < num_baudrates; i++) {
+               rpp_sci_printf("\tBaudrate: %d: ", baudrates[i]);
+               if ((ret_val = cmd_can_test_baudrate_calc(baudrates[i], &can_tx_msg1)) != SUCCESS)
+                       rpp_sci_printf("failed: error: 0x%X.\n", ret_val);
+               else
+                       rpp_sci_printf("OK\n");
+       }
+       rpp_sci_printf("---\n");
+
+       /*
+        * Test the behavioral when a new message replaces the actually pending message.
+        *
+        *  - Send a request for message A transmission,
+        *  - right after that, send a request for another message B transmission,
+        *  - receive a message, which should be the message B.
+        */
+       rpp_sci_printf("Test of transmission request rewritting.\n");
+       rpp_sci_printf("\tCAN bus Initialization: ");
+       if ((ret_val = cmd_can_test_init(RPP_CAN_TIMING_CALC_MANUAL, 500000)) != SUCCESS)
+               rpp_sci_printf("failed: error: 0x%X.\n", ret_val);
+       else {
+               rpp_sci_printf("OK\n");
+               rpp_sci_printf("\tTX request rewritting...");
+               if ((ret_val = cmd_can_test_tx_request_replace(&can_tx_msg1, &can_tx_msg2)) != SUCCESS)
+                       rpp_sci_printf("failed: error: 0x%X.\n", ret_val);
+               else
+                       rpp_sci_printf("OK\n");
+       }
+       rpp_sci_printf("---\n");
+
+       /*
+        * Test the tx_pending flag detection
+        *  - Send a request for a message transmission request,
+        *  - Wait while the flag is reset, which means that the message has been received
+        *    by another node, while measuring the time between the sending the request and
+        *    resetting the flag.
+        *  - Read the message to check that it has been already received.
+        *
+        */
+       rpp_sci_printf("Test of TX request pending flag detection.\n");
+       rpp_sci_printf("\tCAN bus Initialization: ");
+       if ((ret_val = cmd_can_test_init(RPP_CAN_TIMING_CALC_MANUAL, 500000)) != SUCCESS)
+               rpp_sci_printf("failed: error: 0x%X.\n", ret_val);
+       else {
+               rpp_sci_printf("OK\n");
+               uint32_t time = 0;
+               rpp_sci_printf("\tTX request pending flag behavioral: ");
+               if ((ret_val = cmd_can_test_tx_request_flag(&can_tx_msg1, &time)) != SUCCESS)
+                       rpp_sci_printf("failed: error: 0x%X.\n", ret_val);
+               else
+                       rpp_sci_printf("OK, time: %d cycles.\n", time);
+       }
+       rpp_sci_printf("---\n");
+
+       /*
+        * Test the rx_ind flag
+        *  - Send a message
+        *  - Wait for setting the rx_ind flag
+        *  - Try to read the message.
+        */
+       rpp_sci_printf("Test of RX indicator.\n");
+       rpp_sci_printf("\tCAN bus Initialization: ");
+       if ((ret_val = cmd_can_test_init(RPP_CAN_TIMING_CALC_MANUAL, 500000)) != SUCCESS)
+               rpp_sci_printf("failed: error: 0x%X.\n", ret_val);
+       else {
+               rpp_sci_printf("OK\n");
+               uint32_t time = 0;
+               rpp_sci_printf("\tRX indicator behavioral: ");
+               if ((ret_val = cmd_can_test_rx_indicator(&can_tx_msg1, &time)) != SUCCESS)
+                       rpp_sci_printf("failed: error: 0x%X.\n", ret_val);
+               else
+                       rpp_sci_printf("OK, time: %d cycles.\n", time);
+       }
+       rpp_sci_printf("---\n");
+
+       /*
+        * Reset the CAN bus to a determined state
+        * Baudrate: 500kb
+        */
+       rpp_sci_printf("Reset the CAN bus.\n");
+       rpp_sci_printf("\tCAN bus Initialization: ");
+       if ((ret_val = cmd_can_test_init(RPP_CAN_TIMING_CALC_MANUAL, 500000)) != SUCCESS)
+               rpp_sci_printf("failed: error: 0x%X.\n", ret_val);
+       else
+               rpp_sci_printf("OK\n");
+       return SUCCESS;
+}
 
-    can_inited = (rpp_can_init(&can_config) == SUCCESS ? 1 : 0);
-    return (can_inited ? 0 : 1);
+int cmd_do_can_init(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
+{
+       can_inited = (rpp_can_init(&can_config) == SUCCESS ? 1 : 0);
+       return (can_inited ? 0 : 1);
 }
 
 
@@ -296,16 +678,14 @@ int cmd_do_can_send(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
        struct rpp_can_pdu pdu;
        char *p;
 
-       if (!can_inited)
-       {
+       if (!can_inited) {
                rpp_sci_printf("CAN is not initialized\n");
                return -CMDERR_NODEV;
        }
 
        p = param[1];
        ret = sscanf(p, "%i %i%n", &controller_id, &pdu.id, &l);
-       if (ret < 2)
-       {
+       if (ret < 2) {
                rpp_sci_printf("Cannot parse parameter %d\n", ret+1);
                return -CMDERR_BADPAR;
        }
@@ -324,18 +704,14 @@ int cmd_do_can_send(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
        pdu.dlc = i;
 
 
-       if (rpp_can_write(controller_id-1, &pdu) == SUCCESS)
-       {
+       if (rpp_can_write(controller_id-1, &pdu) == SUCCESS) {
                rpp_sci_printf("Sent: can%u\t%X\t[%u]\t", controller_id, pdu.id, pdu.dlc);
-               for (i=0; i<pdu.dlc; i++)
-               {
+               for (i = 0; i < pdu.dlc; i++) {
                        rpp_sci_printf("%X ", pdu.data[i]);
                }
        }
        else
-       {
                rpp_sci_printf("Error: rpp_can_write");
-       }
        rpp_sci_printf("\n");
 
 
@@ -351,46 +727,39 @@ int cmd_do_can_dump(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
 
        uint32_t i;
 
-       if (!can_inited)
-       {
+       if (!can_inited) {
                rpp_sci_printf("CAN is not initialized\n");
                return -CMDERR_NODEV;
        }
 
-       if (!(sscanf(param[1], "%u", &controller_id) == 1))
-       {
+       if (!(sscanf(param[1], "%u", &controller_id) == 1)) {
                rpp_sci_printf("Unable to parse controller ID\n");
                return 1;
        }
 
+       if (controller_id < 1 || controller_id > 3) {
+               rpp_sci_printf("Invalid controller ID\n");
+               return -CMDERR_NODEV;
+       }
+
        rpp_can_init(&can_config);
 
-       while(cmd_io->getc(cmd_io) < 0)
-       {
+       while (cmd_io->getc(cmd_io) < 0) {
                rpp_can_check_rx_ind(controller_id-1, &rx_ind);
-               if (rx_ind)
-               {
-                       if (rpp_can_read(controller_id-1, &pdu) == SUCCESS)
-                       {
+               if (rx_ind) {
+                       if (rpp_can_read(controller_id-1, &pdu) == SUCCESS) {
                                if (pdu.id & CAN_EFF_FLAG)
-                               {
                                        rpp_sci_printf("can%u  %08X  [%u]  ", controller_id & (~CAN_EFF_FLAG), pdu.id, pdu.dlc);
-                               }
                                else
-                               {
                                        rpp_sci_printf("can%u  %03X  [%u]  ", controller_id, pdu.id, pdu.dlc);
-                               }
 
-                               for (i=0; i<pdu.dlc; i++)
-                               {
-                                           rpp_sci_printf("%X ", pdu.data[i]);
+                               for (i = 0; i < pdu.dlc; i++) {
+                                       rpp_sci_printf("%X ", pdu.data[i]);
                                }
                                rpp_sci_printf("\n");
                        }
                        else
-                       {
                                rpp_sci_printf("Error rpp_can_read\n");
-                       }
                }
        }
 
@@ -406,10 +775,8 @@ int cmd_do_can_change_baudrate(cmd_io_t *cmd_io, const struct cmd_des *des, char
        if ((opchar = cmd_opchar_check(cmd_io, des, param)) < 0)
                return opchar;
 
-       if (opchar == ':')
-       {
-               if (!(sscanf(param[1], "%u:%u", &controller_id, &baudrate) == 2))
-               {
+       if (opchar == ':') {
+               if (!(sscanf(param[1], "%u:%u", &controller_id, &baudrate) == 2)) {
                        rpp_sci_printf("Unable to parse arguments\n");
                        return 1;
                }
@@ -418,15 +785,66 @@ int cmd_do_can_change_baudrate(cmd_io_t *cmd_io, const struct cmd_des *des, char
                        return -CMDERR_BADPAR;
 
                can_config.ctrl[controller_id-1].baudrate = baudrate;
+               can_config.ctrl[controller_id-1].timing_config = NULL;
+               can_config.ctrl[controller_id-1].timing_calc_method = RPP_CAN_TIMING_CALC_AUTO;
        }
        else
        {
                if (!(sscanf(param[1], "%u", &controller_id) == 1))
 
+                       if (controller_id < 1 || controller_id > 3)
+                               return -CMDERR_BADPAR;
+
+               cmd_opchar_replong(cmd_io, param, can_config.ctrl[controller_id-1].baudrate, 0, 10);
+       }
+
+       return 0;
+}
+
+int cmd_do_can_change_timing(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
+{
+       int opchar;
+       uint32_t controller_id, brp, prop_seg, phase_seg1, phase_seg2, sjw;
+
+       if ((opchar = cmd_opchar_check(cmd_io, des, param)) < 0)
+               return opchar;
+
+       if (opchar == ':') {
+               if (!(sscanf(param[1], "%u:%u %u %u %u %u", &controller_id, &brp, &prop_seg, &phase_seg1, &phase_seg2, &sjw) == 6)) {
+                       rpp_sci_printf("Unable to parse arguments\n");
+                       return 1;
+               }
+
                if (controller_id < 1 || controller_id > 3)
                        return -CMDERR_BADPAR;
 
-               cmd_opchar_replong(cmd_io, param, can_config.ctrl[controller_id-1].baudrate, 0, 10);
+               can_config.ctrl[controller_id-1].baudrate = 0;
+               can_config.ctrl[controller_id-1].timing_config = &can_timing[controller_id-1];
+               can_config.ctrl[controller_id-1].timing_config->brp = brp;
+               can_config.ctrl[controller_id-1].timing_config->phase_seg1 = phase_seg1;
+               can_config.ctrl[controller_id-1].timing_config->phase_seg2 = phase_seg2;
+               can_config.ctrl[controller_id-1].timing_config->prop_seg = prop_seg;
+               can_config.ctrl[controller_id-1].timing_config->sjw = sjw;
+               can_config.ctrl[controller_id-1].timing_calc_method = RPP_CAN_TIMING_CALC_MANUAL;
+       }
+       else
+       {
+               if (!(sscanf(param[1], "%u", &controller_id) == 1))
+
+                       if (controller_id < 1 || controller_id > 3)
+                               return -CMDERR_BADPAR;
+
+               if (can_config.ctrl[controller_id-1].timing_config != NULL)
+                       rpp_sci_printf("brp: %u\r\nprop_seg: %u tQ\r\nphase_seg1: %u tQ\r\nphase_seg2: %u tQ\r\nsjw: %u tQ\r\n",
+                                                  can_config.ctrl[controller_id-1].timing_config->brp,
+                                                  can_config.ctrl[controller_id-1].timing_config->prop_seg,
+                                                  can_config.ctrl[controller_id-1].timing_config->phase_seg1,
+                                                  can_config.ctrl[controller_id-1].timing_config->phase_seg2,
+                                                  can_config.ctrl[controller_id-1].timing_config->sjw
+                                                  );
+
+               else
+                       rpp_sci_printf("CAN timing has not yet been manually specified.\r\n");
        }
 
        return 0;
@@ -434,154 +852,281 @@ int cmd_do_can_change_baudrate(cmd_io_t *cmd_io, const struct cmd_des *des, char
 
 
 
-#endif /* DOCGEN */
 
-/** @brief command descriptor for test CAN loopback command */
-cmd_des_t const cmd_des_test_can_loopback={
-    0, 0,
-    "cantest*", "Test CAN loopback between two CAN interfaces",
-    "### Command syntax ###\n"
-    "\n"
-    "    cantest<SRC> <DST>\n"
-    "\n"
-    "where `<SRC>` and `<DST>` are different numbers in range 1-3.\n"
-    "\n"
-    "### Description ###\n"
-    "\n"
-    "This command tests CAN communication by sending and receiving messages\n"
-    "through external loopback. At the beginning, the involved CAN\n"
-    "controller are initialized to the Bus-On state.\n"
-    "\n"
-    "The command sends 100 messages and measures the numbers of TX errors,\n"
-    "RX errors and detected timeouts. At the end, these statistics are\n"
-    "printed as well as the status of the involved CAN controllers.\n"
-    "\n"
-    "When an error is detected during the test, the status of faulty CAN\n"
-    "controller is printed immediately.\n"
-    "\n"
-    "### Example ###\n"
-    "\n"
-    "    --> cantest1 2\n"
-    "    Testing CAN loopback\n"
-    "    Messages transmitted: 100/100\n"
-    "    Messages received: 100/100\n"
-    "    TX timeouts: 0\n"
-    "    RX timeouts: 0\n"
-    "    Src TX error counter: 0\n"
-    "    Src RX error counter: 0\n"
-    "    Dst TX error counter: 0\n"
-    "    Dst RX error counter: 0\n"
-    "    CAN1 status: Bus-On, ES: 0x8\n"
-    "    CAN2 status: Bus-On, ES: 0x10\n",
-    CMD_HANDLER(cmd_do_test_can_loopback), (void *)&cmd_list_can
+#endif  /* DOCGEN */
+
+cmd_des_t const cmd_des_can_init = {
+       0, 0,
+       "caninit", "Initialize CAN controllers",
+       "### Command syntax ###\n"
+       "\n"
+       "    caninit\n"
+       "\n"
+       "### Description ###\n"
+       "\n"
+       "This command (re-)initializes all CAN controllers using current\n"
+       "CAN configuration. This configuration can be changed using\n"
+       "canbaudrate command.\n"
+       "\n"
+       "In the default configuration the baudrate of all CAN controllers i set\n"
+       "to 500 kbit/s.\n"
+       "\n"
+       "### Example ###\n"
+       "  --> caninit\n",
+       CMD_HANDLER(cmd_do_can_init), (void *)&cmd_list_can
 };
 
+cmd_des_t const cmd_des_can_baudrate = {
+       0, CDESM_OPCHR|CDESM_RW,
+       "canbaudrate#", "Change baudrate of CAN controller",
+       "### Command syntax ###\n"
+       "\n"
+       "    canbaudrate<CONTROLLER>?\n"
+       "    canbaudrate<CONTROLLER>:<BAUDRATE>\n"
+       "\n"
+       "where `<CONTROLLER>` is number in range 1-3 and BAUDRATE is number in\n"
+       "range 1000-10000000 specifying the baudrate in bits per second.\n"
+       "\n"
+       "### Description ###\n"
+       "\n"
+       "This command is used to set or show the baudrate of a CAN controller.\n"
+       "The baudrate shown is the one which will be used by next invocation of\n"
+       "the caninit command.\n"
+       "The baudrate specified by the command is used to automatic calculation of\n"
+       "the CAN controller timing. If you want to specify the timing manually,\n"
+       "please use the command cantiming.\n"
+       "The automatic calculation might not work properly for some baudrates. In\n"
+       "this case you should calculate the timing manually and specify it by the\n"
+       "command cantiming."
+       "\n"
+       "### Examples ###\n"
+       "\n"
+       "    --> canbaudrate2?\n"
+       "    canbaudrate2=500000\n"
+       "\n"
+       "    --> canbaudrate2:100000\n",
+       CMD_HANDLER(cmd_do_can_change_baudrate), (void *)&cmd_list_can
+};
 
-cmd_des_t const cmd_des_can_init={
-    0, 0,
-    "caninit", "Initialize CAN controllers",
-    "### Command syntax ###\n"
-    "\n"
-    "    caninit\n"
-    "\n"
-    "### Description ###\n"
-    "\n"
-    "This command (re-)initializes all CAN controllers using current\n"
-    "CAN configuration. This configuration can be changed using\n"
-    "canbaudrate command.\n"
-    "\n"
-    "In the default configuration the baudrate of all CAN controllers i set\n"
-    "to 500 kbit/s.\n"
-    "\n"
-    "### Example ###\n"
-    "  --> caninit\n",
-    CMD_HANDLER(cmd_do_can_init), (void *)&cmd_list_can
+cmd_des_t const cmd_des_can_timing = {
+       0, CDESM_OPCHR|CDESM_RW,
+       "cantiming#", "Change timing of CAN controller manually",
+       "### Command syntax ###\n"
+       "\n"
+       "    cantiming<CONTROLLER>?\n"
+       "    cantiming<CONTROLLER>:<BRP> <PROP_SEG> <PHASE_SEG1> <PHASE_SEG2> <SJW>\n"
+       "\n"
+       "where:"
+       " - `<CONTROLLER>` is number in range 1-3\n"
+       " - `<BRP>` (baudrate prescaler) is number in range 1-65\n"
+       " - `<PROP_SEG>` (length of propagation segment in tQ) is a number in range 1-8\n"
+       " - `<PHASE_SEG1>` (phase buffer segment 1 in tQ) is a number in range 1-8\n"
+       " - `<PHASE_SEG2>` (phase buffer segment 2 in tQ) is a number in range 1-8\n"
+       " - `<SJW>` (synchronization jump width in tQ) is a number in range 1-4\n"
+       "\n"
+       "### Description ###\n"
+       "\n"
+       "This command is used to set or show the timing of a CAN controller.\n"
+       "The timing shown is the one which will be used by next invocation of\n"
+       "the caninit command.\n"
+       "The timing configured by this command defines manually the baudrate of\n"
+       "the CAN controller. If you want to calculate the timing automaticaly from\n"
+       "a baudrate, please use the command canbaudrate.\n"
+       "\n"
+       "### Examples ###\n"
+       "\n"
+       "    --> cantiming2?\n"
+       "    brp: 17\n"
+       "    prop_seg: 4 tQ\n"
+       "    phase_seg1: 5 tQ\n"
+       "    phase_seg2: 5 tQ\n"
+       "    sjw: 4 tQ\n"
+       "    sample_pt: 875 ns\n"
+       "    error: 0\n"
+       "    tQ: 125 ns\n"
+       "\n"
+       "    --> cantiming2:5 8 7 4 1\n",
+       CMD_HANDLER(cmd_do_can_change_timing), (void *)&cmd_list_can
 };
 
-cmd_des_t const cmd_des_can_baudrate={
-    0, CDESM_OPCHR|CDESM_RW,
-    "canbaudrate#", "Change baudrate of CAN controller",
+
+cmd_des_t const cmd_des_can_send = {
+       0, 0,
+       "cansend", "Test sending message over CAN",
+       "### Command syntax ###\n"
+       "\n"
+       "    cansend <CONTROLLER> <ID> <DATA>\n"
+       "\n"
+       "where `<CONTROLLER>` is number in range 1-3, `<ID>` is a valid CAN ID\n"
+       "and `<DATA>` is 0-8 bytes of data in hexadecimal representation.\n"
+       "There may be any number of spaces between the data bytes.\n"
+       "`<ID>` may be given in octal, decimal or hexadecimal base.\n"
+       "\n"
+       "### Description ###\n"
+       "\n"
+       "This command sends a CAN frame using specified CAN controller.\n"
+       "\n"
+       "The caninit command must be called before using this command.\n"
+       "\n"
+       "### Example ###\n"
+       "    --> cansend 2 0x123 DEAD BEEF\n"
+       "    Sent: can2      123     [4]     DE AD BE EF\n",
+       CMD_HANDLER(cmd_do_can_send), (void *)&cmd_list_can
+};
+
+
+cmd_des_t const cmd_des_can_dump = {
+       0, 0,
+       "candump", "Dump all messages received over CAN",
+       "### Command syntax ###\n"
+       "\n"
+       "    candump <CONTROLLER>\n"
+       "\n"
+       "where `<CONTROLLER>` is a number in range 1-3.\n"
+       "\n"
+       "### Description ###\n"
+       "\n"
+       "This command prints out all CAN messages received via the specified\n"
+       "controller.\n"
+       "\n"
+       "IDs are zero-filled to length 3 if a message in the standard frame\n"
+       "format is received and to 8 for extended frame format messages.\n"
+       "\n"
+       "`caninit` must be called before using this command.\n"
+       "\n"
+       "### Example ###\n"
+       "\n"
+       "    --> candump 2\n"
+       "    can2  0000FADE  [2]  12 34\n",
+       CMD_HANDLER(cmd_do_can_dump), (void *)&cmd_list_can
+};
+
+cmd_des_t const cmd_des_can_test={
+    0, 0,
+    "canrpptest", "Test the CAN functions from the RPP library",
     "### Command syntax ###\n"
     "\n"
-    "    canbaudrate<CONTROLLER>?\n"
-    "    canbaudrate<CONTROLLER>:<BAUDRATE>\n"
-    "\n"
-    "where `<CONTROLLER>` is number in range 1-3 and BAUDRATE is number in\n"
-    "range 1000-10000000 specifying the baurdate in bits per second.\n"
+    "    canrpptest\n"
     "\n"
     "### Description ###\n"
     "\n"
-    "This command is used to set or show the baudrate of a CAN controller.\n"
-    "The baudrate shown is the one which will be used by next invocation of\n"
-    "the caninit command.\n"
+    "This command tests all CAN functions in the RPP library. It requires\n"
+    "the CAN1 and CAN2 connectors to be connected with HW loopback. The\n"
+    "following tests are performed:\n"
     "\n"
-    "### Examples ###\n"
+    "1.  Test of `rpp_can_init()`, `rpp_can_write()` and `rpp_can_read()` functions.\n"
     "\n"
-    "    --> canbaudrate2?\n"
-    "    canbaudrate2=500000\n"
+    "    At the beginning, the CAN bus is initialized with hardcoded (and\n"
+    "    verified) verified CAN bit timing parameters. Then a message is\n"
+    "    sent to the CAN1 interface and received from CAN2. The received\n"
+    "    message is compared with the sent one. If the transmissions fails,\n"
+    "    reception exceeds a timeout or the sent and received messages\n"
+    "    differ, the command prints an appropriate error code.\n"
     "\n"
-    "    --> canbaudrate2:100000\n",
-    CMD_HANDLER(cmd_do_can_change_baudrate), (void *)&cmd_list_can
-};
-
-cmd_des_t const cmd_des_can_send={
-    0, 0,
-    "cansend", "Test sending message over CAN",
-    "### Command syntax ###\n"
+    "2.  Test of CAN bit timing parameters calculation.\n"
     "\n"
-    "    cansend <CONTROLLER> <ID> <DATA>\n"
+    "    This test subsequently initializes the CAN controller to baudrates\n"
+    "    125k, 250k and 500k. For each one of them a message is sent to\n"
+    "    CAN1 and received from CAN2. The received message is compared with\n"
+    "    the sent one like in test 1. If the initialization, transmission,\n"
+    "    reception or comparison fails or if the reception timeout is\n"
+    "    reached, an appropriate error code is printed.\n"
     "\n"
-    "where `<CONTROLLER>` is number in range 1-3, `<ID>` is a valid CAN ID\n"
-    "and `<DATA>` is 0-8 bytes of data in hexadecimal representation.\n"
-    "There may be any number of spaces between the data bytes.\n"
-    "`<ID>` may be given in octal, decimal or hexadecimal base.\n"
+    "3.  Test of the behavior of transmission request overwriting.\n"
     "\n"
-    "### Description ###\n"
+    "    The CAN controller is initialized as in test 1. A transmission\n"
+    "    request for message A is made on CAN1 by calling `rpp_can_write()`.\n"
+    "    Right after that another transmission request for message B is\n"
+    "    made on CAN1 by another call to `rpp_can_write()`. A message B is\n"
+    "    received on CAN2, because the second request came so quickly, that\n"
+    "    it overwrote message A in the TX buffer. The sent and received\n"
+    "    messages are compared to verify that the behavior was correct.\n"
     "\n"
-    "This command sends a CAN frame using specified CAN controller.\n"
+    "    If the initialization, transmission, reception or comparison fails\n"
+    "    or if the reception timeout is reached, an appropriate error code\n"
+    "    is printed.\n"
     "\n"
-    "The caninit command must be called before using this command.\n"
+    "4.  Test of the TX request pending flag detection.\n"
     "\n"
-    "### Example ###\n"
-    "    --> cansend 2 0x123 DEAD BEEF\n"
-    "    Sent: can2      123     [4]     DE AD BE EF\n",
-    CMD_HANDLER(cmd_do_can_send), (void *)&cmd_list_can
-};
-
-
-cmd_des_t const cmd_des_can_dump={
-    0, 0,
-    "candump", "Dump all messages received over CAN",
-    "### Command syntax ###\n"
+    "    The CAN bus is initialized like in test 1. A message is\n"
+    "    transmitted on CAN1 and the test waits for the TX pending flag to\n"
+    "    be set, which signalizes that there is a message transmission\n"
+    "    request pending. After the flag has been set, the test waits for\n"
+    "    its clearance, which means that the message has been sent. The\n"
+    "    test measures, how many flag test cycles passed, until the flag\n"
+    "    has been cleared. This value is then presented as time. At the\n"
+    "    end, the message is received from CAN2 and it is compared with the\n"
+    "    sent message for verification.\n"
     "\n"
-    "    candump <CONTROLLER>\n"
+    "    If the initialization, transmission, reception or comparison fails or if\n"
+    "    timeout is reached while waiting for the flag set/clear or receive timeout\n"
+    "    is reached, an appropriate error code is printed.\n"
     "\n"
-    "where `<CONTROLLER>` is a number in range 1-3.\n"
+    "5.  Test of the message received (RX) indication.\n"
     "\n"
-    "### Description ###\n"
+    "    The CAN bus is initialized like in test 1. A message is\n"
+    "    transmitted on CAN1. The test then waits for the RX indication to\n"
+    "    be set, which indicates that a message has been received. The\n"
+    "    message is picked up by calling `rpp_can_read()`. This should\n"
+    "    clear the indicator, which is tested. Finally the received\n"
+    "    messages is compared with the sent one.\n"
     "\n"
-    "This command prints out all CAN messages received via the specified\n"
-    "controller.\n"
+    "    If the initialization, transmission, reception, message comparison or indicator\n"
+    "    test fails or if timeout is reached while waiting for the flag set, the\n"
+    "    appropriate error code is printed.\n"
     "\n"
-    "IDs are zero-filled to length 3 if a message in the standard frame\n"
-    "format is received and to 8 for extended frame format messages.\n"
+    "At the end the CAN bus is reset and left with the configuration from\n"
+    "test 1.\n"
     "\n"
-    "caninit must be called before using this command.\n"
+    "The command can be called even after the CAN bus has been already\n"
+    "configured by previous invocation of the `caninit` command. The\n"
+    "previous timing configuration set by `cantiming#` command not\n"
+    "modified. Therefore, calling `caninit` after this command finishes\n"
+    "restores the previous timing settings.\n"
+    "\n"
+    "For error codes description please refer to the API documentation for\n"
+    "the rpp-test-sw.\n"
     "\n"
     "### Example ###\n"
     "\n"
-    "    --> candump 2\n"
-    "can2  0000FADE  [2]  12 34\n",
-    CMD_HANDLER(cmd_do_can_dump), (void *)&cmd_list_can
+    "    --> canrpptest\n"
+    "    This is a test for RPP CAN library functions:\n"
+    "    Test of simple message transmission and reception.\n"
+    "          CAN bus Initialization...OK\n"
+    "          Transmission and reception...OK\n"
+    "    ---\n"
+    "    Test of automatic CAN bit timing calculation.\n"
+    "          Baudrate: 125000: OK\n"
+    "          Baudrate: 250000: OK\n"
+    "          Baudrate: 500000: OK\n"
+    "    ---\n"
+    "    Test of transmission request rewritting.\n"
+    "          CAN bus Initialization...OK\n"
+    "          TX request rewritting...OK\n"
+    "    ---\n"
+    "    Test of TX request pending flag detection.\n"
+    "          CAN bus Initialization...OK\n"
+    "          TX request pending flag behavioral: OK, time: 256 cycles.\n"
+    "    ---\n"
+    "    Test of RX indicator.\n"
+    "          CAN bus Initialization...OK\n"
+    "          RX indicator behavioral:\n"
+    "    OK, time: 0 cycles.\n"
+    "    ---\n"
+    "    Reset the CAN bus.\n"
+    "          CAN bus Initialization...OK\n",
+    CMD_HANDLER(cmd_do_can_test_functions), (void *)&cmd_list_can
 };
 
 
 
-cmd_des_t const *cmd_list_can[]={
-  &cmd_des_test_can_loopback,
-  &cmd_des_can_init,
-  &cmd_des_can_baudrate,
-  &cmd_des_can_send,
-  &cmd_des_can_dump,
-  NULL
+
+cmd_des_t const *cmd_list_can[] = {
+       &cmd_des_can_init,
+       &cmd_des_can_baudrate,
+       &cmd_des_can_timing,
+       &cmd_des_can_send,
+       &cmd_des_can_dump,
+       &cmd_des_can_test,
+       NULL
 };