Subversion Repositories HomeAutomation

Rev

Rev 127 | Blame | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * CAN communication interface. This is a general, high-level interface for CAN
  3.  * communication. Underlying CAN controllers are abstracted by this interface,
  4.  * so the application needs not work directly with the CAN controllers.
  5.  *
  6.  * The interface is fully queued in both directions. Both queues can configured
  7.  * in terms of size, and can also be disabled completely to save both RAM and
  8.  * FLASH space (the queue routines are removed by preprocessor when queues
  9.  * are disabled). When queues are enabled, the application has to call
  10.  * Can_Service as often as possible, so messages can be moved between the CAN
  11.  * controller and the message queues. This might be handled by interrupts in
  12.  * future. When queues are disabled, on the other hand, the application has
  13.  * to call Can_Receive as often as possible in order not to loose any messages.
  14.  *
  15.  * @date    2006-11-21
  16.  *
  17.  * @author  Jimmy Myhrman
  18.  *  
  19.  */
  20.  
  21. /*-----------------------------------------------------------------------------
  22.  * Includes
  23.  *---------------------------------------------------------------------------*/
  24. #include <string.h>
  25. #include <can.h>
  26. #include <mcu.h>
  27. #include <stdio.h>
  28. #include <timebase.h>
  29. #include <assert.h>
  30. #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515
  31.     #include "mcp2515.h"
  32. #endif
  33.  
  34.  
  35. /*-----------------------------------------------------------------------------
  36.  * Prerequisites
  37.  *---------------------------------------------------------------------------*/
  38. #ifndef CAN_CONTROLLER
  39.     #error CAN_CONTROLLER not specified! Edit can_cfg.h !
  40. #endif
  41.  
  42. #ifndef CAN_BITRATE
  43.     #error CAN_BITRATE not defined! Edit can_cfg.h !
  44. #endif
  45.  
  46. #ifndef CAN_QUEUE_SIZE_RX
  47.     #error CAN_QUEUE_SIZE_RX not defined! Edit can_cfg.h !
  48. #endif
  49.  
  50. #ifndef CAN_QUEUE_SIZE_TX
  51.     #error CAN_QUEUE_SIZE_TX not defined! Edit can_cfg.h !
  52. #endif
  53.  
  54. #ifndef CAN_CONTROLLER_NR_TX_BUFFERS
  55.     #error CAN_CONTROLLER_NR_TX_BUFFERS not defined! Edit can_cfg.h !
  56. #endif
  57.  
  58. #ifndef CAN_CONTROLLER_NR_RX_BUFFERS
  59.     #error CAN_CONTROLLER_NR_RX_BUFFERS not defined! Edit can_cfg.h !
  60. #endif
  61.  
  62.  
  63. /*-----------------------------------------------------------------------------
  64.  * Type Definitions
  65.  *---------------------------------------------------------------------------*/
  66.  
  67. #if (CAN_QUEUE_SIZE_TX > 0) || (CAN_QUEUE_SIZE_RX > 0)
  68. /**
  69.  * CAN Message Queue Type. Stores and manages several CAN messages
  70.  * in a FIFO structure.
  71.  */
  72. typedef struct {
  73.     Can_Message_t *dataPtr; /* pointer to the data storage */
  74.     uint8_t head;       /* current OUTPUT position */
  75.     uint8_t tail;       /* current INPUT position */
  76.     uint8_t nrElements; /* nr of elements currently queued */
  77.     uint8_t size;       /* total size of the queue */
  78. } Can_MessageQueue_t;
  79. #endif
  80.  
  81.  
  82. /*-----------------------------------------------------------------------------
  83.  * Private (static) variables
  84.  *---------------------------------------------------------------------------*/
  85.  
  86. #if CAN_QUEUE_SIZE_TX > 0
  87.     /* TX queue object and static memory storage buffer for this queue */
  88.     static Can_MessageQueue_t canTxQueue;
  89.     static Can_Message_t canTxQueueDataStorage[CAN_QUEUE_SIZE_TX];
  90. #endif
  91. #if CAN_QUEUE_SIZE_RX > 0
  92.     /* RX queue object and static memory storage buffer for this queue */
  93.     static Can_MessageQueue_t canRxQueue;
  94.     static Can_Message_t canRxQueueDataStorage[CAN_QUEUE_SIZE_RX];
  95. #endif
  96.  
  97.  
  98. /*-----------------------------------------------------------------------------
  99.  * Private Function Prototypes
  100.  *---------------------------------------------------------------------------*/
  101.  
  102. /* functions that deal with the controller hardware */
  103. static Can_Return_t Can_SendImmediately(Can_Message_t *msg);
  104. static Can_Return_t Can_ReceiveFromController(Can_Message_t *msg, uint8_t rxBuffer);
  105. static uint8_t Can_MessagesAvailableInController(void);
  106. static Can_Return_t Can_ControllerCheckError(void);
  107.  
  108. #if (CAN_QUEUE_SIZE_TX > 0) || (CAN_QUEUE_SIZE_RX > 0)
  109. /* functions that deal with the message queues */
  110. static void Can_QueueInit(Can_MessageQueue_t *q, uint8_t size, Can_Message_t *dataPtr);
  111. static Can_Message_t* Can_QueueInsert(Can_MessageQueue_t *q);
  112. static Can_Message_t* Can_QueueReadTailPtr(Can_MessageQueue_t *q);
  113. static void Can_QueueRemoveTail(Can_MessageQueue_t *q);
  114. #endif
  115.  
  116.  
  117. /*-----------------------------------------------------------------------------
  118.  * Public Functions
  119.  *---------------------------------------------------------------------------*/
  120.  
  121. /**
  122.  * Initializes the CAN interface. Edit can_cfg.h to choose bitrate.
  123.  *
  124.  * @return
  125.  *      CAN_OK if initialization was successful.
  126.  *      CAN_INIT_FAIL_SET_BITRATE if bitrate could not be set correctly.
  127.  *      CAN_INIT_FAIL_SET_MODE if the controller could not be set to normal operation mode.
  128.  *      CAN_INIT_FAIL in case of general error.
  129.  */
  130. Can_Return_t Can_Init() {
  131.     #if CAN_QUEUE_SIZE_TX > 0
  132.         /* initialize TX queue */
  133.         Can_QueueInit(&canTxQueue, CAN_QUEUE_SIZE_TX, canTxQueueDataStorage);
  134.     #endif
  135.     #if CAN_QUEUE_SIZE_RX > 0
  136.         /* initialize RX queue */
  137.         Can_QueueInit(&canRxQueue, CAN_QUEUE_SIZE_RX, canRxQueueDataStorage);
  138.     #endif
  139.    
  140.     #if CAN_CONTROLLER == CAN_CONTROLLER_NULL
  141.         /*
  142.          * Initialize null device.
  143.          */
  144.         return CAN_OK;
  145.     #endif
  146.    
  147.     #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515
  148.         /*
  149.          * Initialize MCP2515 device.
  150.          */
  151.         if (MCP2515_Init(CAN_BITRATE) != MCP2515_OK) {
  152.             return CAN_FAIL;
  153.         }
  154.         if (MCP2515_SetCanCtrlMode(MODE_NORMAL) != MCP2515_OK) {
  155.             return CAN_FAIL;
  156.         }
  157.         return CAN_OK;
  158.     #endif
  159.    
  160.     return CAN_FAIL;
  161. }
  162.  
  163.  
  164. /**
  165.  * Sends a CAN message. The message will be put into the transmission queue,
  166.  * and hence, it might not be sent immediately. If the queue is full, the
  167.  * message will not be taken care of, and CAN_FAIL is returned.
  168.  *
  169.  * @param msg
  170.  *      Pointer to the CAN message.
  171.  *
  172.  * @return
  173.  *      CAN_OK if the message was successfully enqueued.
  174.  *      CAN_FAIL if the transmission queue is full.
  175.  */
  176. Can_Return_t Can_Send(Can_Message_t *msg) {
  177.     #if CAN_QUEUE_SIZE_TX == 0
  178.         /* TX queue is disabled, so send immediately */
  179.         return Can_SendImmediately(msg);
  180.     #else
  181.         #if 0
  182.         printf("Can_Send()\n\r");
  183.         printf("    queue size before = %u\n\r", canTxQueue.nrElements);
  184.         #endif
  185.         /* check if there is room available in the tx queue */
  186.         if (canTxQueue.nrElements >= canTxQueue.size) {
  187.             #if 0
  188.             printf("    TX queue full!\n\r");
  189.             #endif
  190.             return CAN_FAIL;
  191.         }
  192.         /* put message in queue */
  193.         Can_Message_t *ptr = Can_QueueInsert(&canTxQueue);
  194.         memcpy(ptr, msg, sizeof(Can_Message_t));
  195.         #if 0
  196.         printf("    queue size after = %u\n\r", canTxQueue.nrElements);
  197.         #endif
  198.         return CAN_OK;
  199.     #endif
  200. }
  201.  
  202.  
  203. /**
  204.  * Services the CAN subsystem. Messages waiting in the transmission queue
  205.  * will be transmitted if the controller is not busy, and any messages
  206.  * received by the controller will be moved from the controller buffers
  207.  * into the internal reception queue.
  208.  */
  209. void Can_Service() {
  210.     #if CAN_QUEUE_SIZE_TX > 0
  211.         /* try to transmit messages waiting in the transmission queue */
  212.         for (uint8_t i=0; i<CAN_CONTROLLER_NR_TX_BUFFERS; i++) {
  213.             if (canTxQueue.nrElements > 0) {
  214.                 #if 0
  215.                 printf("msg in TX queue. trying to send...\n");
  216.                 #endif
  217.                 /* ensure the queue operations are atomic */
  218.                 Mcu_DisableIRQ();
  219.                 Can_Message_t *txMsg = Can_QueueReadTailPtr(&canTxQueue);
  220.                 if (Can_SendImmediately(txMsg) == CAN_OK) {
  221.                     /* transmission OK, remove from queue */
  222.                     Can_QueueRemoveTail(&canTxQueue);
  223.                 }
  224.                 Mcu_EnableIRQ();
  225.             }
  226.             else {
  227.                 /* quit the loop if the queue is empty */
  228.                 break;
  229.             }
  230.         }
  231.     #endif
  232.    
  233.     #if CAN_QUEUE_SIZE_RX > 0
  234.         /* move all received messages from CAN controller to reception queue */
  235.         Can_Message_t rxMsg;
  236.         /* all RX buffers have to be checked (and in correct order) */
  237.         for (uint8_t buf=0; buf<CAN_CONTROLLER_NR_RX_BUFFERS; buf++) {
  238.             /* if buffer contains a message, handle it */
  239.             if (Can_ReceiveFromController(&rxMsg, buf) == CAN_OK) {
  240.                 /* ensure the queue operations are atomic */
  241.                 Mcu_DisableIRQ();
  242.                 /* try to get access to the queue */
  243.                 Can_Message_t *destPtr = Can_QueueInsert(&canRxQueue);
  244.                 /* if we can insert into queue, copy the message */
  245.                 if (destPtr != 0) {
  246.                     memcpy(destPtr, &rxMsg, sizeof(Can_Message_t));
  247.                 }
  248.                 else {
  249.                     /* otherwise, the received message will be discarded... */
  250.                 }
  251.                 Mcu_EnableIRQ();
  252.             }
  253.         }
  254.     #endif
  255.    
  256.     /* TODO: check error status in controller */
  257. }
  258.  
  259.  
  260. /**
  261.  * Receives a CAN message that is waiting in the reception queue. If no
  262.  * messages have been received, CAN_NO_MSG_AVAILABLE is returned.
  263.  * Otherwise, a CAN message is copied into the specified message buffer
  264.  * and deleted from the internal message reception queue. In this case,
  265.  * CAN_OK is returned.
  266.  *
  267.  * @param msg
  268.  *          Pointer to the message storage buffer into which the message
  269.  *          should be copied.
  270.  *
  271.  * @return
  272.  *          CAN_OK if a received message was successfully copied into the buffer.
  273.  *          CAN_NO_MSG_AVAILABLE if no messages are available.
  274.  */
  275. Can_Return_t Can_Receive(Can_Message_t *msg) {
  276.    
  277.     #if CAN_QUEUE_SIZE_RX > 0
  278.         /*
  279.          * RX queue is enabled, so try to get message from queue.
  280.          */
  281.         Can_Message_t *pSrc;    /* Source pointer */
  282.         /* Check if there is anything available in the RxQueue */
  283.         if (canRxQueue.nrElements == 0) {
  284.             return CAN_NO_MSG_AVAILABLE;
  285.         }
  286.         /* ensure the queue operations are atomic */
  287.         Mcu_DisableIRQ();
  288.         pSrc = Can_QueueReadTailPtr(&canRxQueue);
  289.         /* copy frame from queue, and then remove from queue */
  290.         memcpy(msg, pSrc, sizeof(Can_Message_t));
  291.         Can_QueueRemoveTail(&canRxQueue);
  292.         Mcu_EnableIRQ();
  293.         /* a message has successfully been copied and removed from queue */
  294.         return CAN_OK;
  295.     #else
  296.         /*
  297.          * RX queue is disabled, so try to get message from controller.
  298.          * We don't know which buffer to get the message from, so best
  299.          * we can do is to get from buf0 first time, and then increase
  300.          * buffer number at each call, finally wrapping around at
  301.          * CAN_CONTROLLER_NR_RX_BUFFERS.
  302.          */
  303.         static uint8_t rxBuffer = 0;
  304.         /* worst case is that we need to check all available rx buffers in order to find a message */
  305.         for (uint8_t i=0; i<CAN_CONTROLLER_NR_RX_BUFFERS; i++) {
  306.             /* is there a message available in this buffer? */
  307.             if (Can_ReceiveFromController(msg, rxBuffer) == CAN_OK) {
  308.                 /* increase buffer number and return the message */
  309.                 rxBuffer = (rxBuffer + 1) % CAN_CONTROLLER_NR_RX_BUFFERS;
  310.                 return CAN_OK;
  311.             }
  312.             /* increase buffer number so we can check next buffer */
  313.             rxBuffer = (rxBuffer + 1) % CAN_CONTROLLER_NR_RX_BUFFERS;
  314.         }
  315.         /* all buffers were checked, but no message found */
  316.         return CAN_NO_MSG_AVAILABLE;
  317.     #endif
  318. }
  319.  
  320.  
  321.  
  322. /*-----------------------------------------------------------------------------
  323.  * Private Functions
  324.  *---------------------------------------------------------------------------*/  
  325.  
  326. /**
  327.  * Sends a CAN message immediately with the controller hardware. If the CAN
  328.  * controller is busy, the function will return CAN_SEND_FAIL_TX_BUSY.
  329.  *
  330.  * @param msg
  331.  *      Pointer to the CAN message storage buffer.
  332.  *
  333.  * @return
  334.  *      CAN_OK if the message was successfully sent to the controller.
  335.  *      CAN_FAIL if the controller is busy.
  336.  */
  337. static Can_Return_t Can_SendImmediately(Can_Message_t* msg) {
  338.     #if CAN_CONTROLLER == CAN_CONTROLLER_NULL
  339.         /*
  340.          * Send with null device.
  341.          */
  342.         return CAN_OK;
  343.     #endif
  344.  
  345.     #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515
  346.         /*
  347.          * Send with MCP2515 device.
  348.          */
  349.         uint8_t res, txbuf_n;
  350.         res = MCP2515_GetNextFreeTXBuf(&txbuf_n); // info = addr.
  351.         if (res == MCP_ALLTXBUSY) {
  352.             return CAN_FAIL;
  353.         }
  354.         MCP2515_WriteCanMsg(txbuf_n, msg);
  355.         MCP2515_StartTransmit(txbuf_n);
  356.         return CAN_OK;
  357.     #endif
  358. }
  359.  
  360.  
  361. /**
  362.  * Receives a CAN message from the CAN controller hardware.
  363.  *
  364.  * @param msg
  365.  *      Pointer to the message storage buffer into which the message should be copied.
  366.  *
  367.  * @param rxBuffer
  368.  *      Identifies the RX buffer in the controller. Range is [0,CAN_CONTROLLER_NR_RX_BUFFERS-1].
  369.  *
  370.  * @return
  371.  *      CAN_OK if a received message was successfully copied into the buffer.
  372.  *      CAN_NO_MSG_AVAILABLE if there are is no message available in the specified buffer.
  373.  *      CAN_FAIL if the rxBuffer parameter i out of range for the specified controller.
  374.  */
  375. static Can_Return_t Can_ReceiveFromController(Can_Message_t *msg, uint8_t rxBuffer) {
  376.     #if CAN_CONTROLLER == CAN_CONTROLLER_NULL
  377.         /*
  378.          * Receive from null device.
  379.          */
  380.         return CAN_NO_MSG_AVAILABLE;
  381.     #endif
  382.    
  383.     #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515
  384.         /*
  385.          * Receive from MCP2515 device.
  386.          */
  387.         uint8_t stat;
  388.         stat = MCP2515_ReadStatus();
  389.         if (rxBuffer == 0) {
  390.             /* check BUF0 */
  391.             if (stat & MCP_STAT_RX0IF) {
  392.                 /* Msg in Buffer 0 */
  393.                 MCP2515_ReadCanMsg(MCP_RXBUF_0, msg);
  394.                 MCP2515_ModifyRegister(MCP_CANINTF, MCP_RX0IF, 0);
  395.                 return CAN_OK;
  396.             }
  397.         }
  398.         else if (rxBuffer == 1) {
  399.             /* check BUF1 */
  400.             if (stat & MCP_STAT_RX1IF) {
  401.                 /* Msg in Buffer 1 */
  402.                 MCP2515_ReadCanMsg(MCP_RXBUF_1, msg);
  403.                 MCP2515_ModifyRegister(MCP_CANINTF, MCP_RX1IF, 0);
  404.                 return CAN_OK;
  405.             }
  406.         }
  407.         else {
  408.             /* invalid parameters */
  409.             return CAN_FAIL;
  410.         }
  411.         return CAN_NO_MSG_AVAILABLE;
  412.     #endif
  413. }
  414.  
  415.  
  416. /**
  417.  * Checks how many messages are available in the CAN controller hardware.
  418.  *
  419.  * @return
  420.  *      The number of messages available (0 if none).
  421.  */
  422. static uint8_t Can_MessagesAvailableInController() {
  423.     #if CAN_CONTROLLER == CAN_CONTROLLER_NULL
  424.         /*
  425.          * Check for messages in null device.
  426.          */
  427.         return 0;
  428.     #endif
  429.    
  430.     #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515
  431.         /*
  432.          * Check for message in MCP2515 device.
  433.          */
  434.         uint8_t res;
  435.         res = MCP2515_ReadStatus(); /* RXnIF in Bit 1 and 0 */
  436.         if (res & MCP_STAT_RXIF_MASK) {
  437.             //TODO: check how many messages are available
  438.             return 1;   /* at least one message available */
  439.         }
  440.         else {
  441.             return 0;   /* no messages available */
  442.         }
  443.     #endif
  444.    
  445.     return 0;
  446. }
  447.  
  448.  
  449. /*
  450.  * Checks Controller-Error-State.
  451.  *
  452.  * @return
  453.  *      CAN_OK if the controller is OK.
  454.  *      CAN_FAIL if errors have occured.
  455.  *
  456.  * @todo
  457.  *      Styr upp denna funktion lite bättre.
  458.  */
  459. static Can_Return_t Can_ControllerCheckError() {
  460.     #if CAN_CONTROLLER == CAN_CONTROLLER_NULL
  461.         /*
  462.          * Check for errors in null device.
  463.          */
  464.         return CAN_OK;
  465.     #endif
  466.    
  467.     #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515
  468.         /*
  469.          * Check for errors in MCP2515 device.
  470.          */
  471.         uint8_t eflg = MCP2515_ReadRegister(MCP_EFLG);
  472.         if (eflg & MCP_EFLG_ERRORMASK) {
  473.             return CAN_FAIL;    /* errors found */
  474.         }
  475.         else {
  476.             return CAN_OK;      /* no errors found */
  477.         }
  478.     #endif
  479. }
  480.  
  481.  
  482. #if (CAN_QUEUE_SIZE_TX > 0) || (CAN_QUEUE_SIZE_RX > 0)
  483. /**
  484.  * Initializes a CAN queue.
  485.  *
  486.  * @param q
  487.  *      Pointer to the queue object.
  488.  *
  489.  * @param size
  490.  *      Size of the queue (number of messages that can be queued).
  491.  *
  492.  * @param dataPtr
  493.  *      Pointer to the message storage buffer that should be used by the queue.
  494.  */
  495. static void Can_QueueInit(Can_MessageQueue_t *q, uint8_t size, Can_Message_t *dataPtr) {
  496.     q->dataPtr = dataPtr;
  497.     q->head = 0;
  498.     q->tail = 0;
  499.     q->nrElements = 0;
  500.     q->size = size;
  501. }
  502.  
  503.  
  504. /**
  505.  * Inserts a new element in a queue and returns a pointer to the new element.
  506.  * If the queue is full, the last element (the tail) will be overwritten by
  507.  * the new element.
  508.  *
  509.  * @param q
  510.  *      Pointer to the queue object.
  511.  *
  512.  * @return
  513.  *      Pointer to the new message element. Use this pointer to copy data into the queue.
  514.  */
  515. static Can_Message_t* Can_QueueInsert(Can_MessageQueue_t *q) {
  516.     Can_Message_t *ptr;
  517.     #if 0
  518.     printf("INSERT: bef=%u, ", q->nrElements);
  519.     #endif
  520.     if ((q->nrElements+1) > q->size) {
  521.         q->tail = (q->tail + 1) % q->size;
  522.         q->nrElements--;
  523.     #if 0
  524.         printf("Can_QueueInsertViaPtr: QUEUE OVERRUN!\n\r");
  525.     #endif
  526.     }
  527.     ptr = &(q->dataPtr[q->head]);
  528.     #if 0
  529.     if (q->handled[q->head] == 0) {
  530.         printf("Can_QueueInsertViaPtr: discarding non-handled msg!\n\r");
  531.     }
  532.     #endif
  533.     q->head = (q->head + 1) % q->size;
  534.     q->nrElements++;
  535.     #if 0
  536.     printf("aft=%u\n\n", q->nrElements);
  537.     #endif
  538.     return ptr;
  539. }
  540.  
  541.  
  542. /**
  543.  * Returns a pointer to the last element in the queue (the tail). Use this pointer
  544.  * to extract the message, and then call Can_QueueRemoveTail to actually remove
  545.  * the element.
  546.  *
  547.  * @param q
  548.  *      Pointer to the queue object.
  549.  *
  550.  * @return
  551.  *      Pointer to the tail message element.
  552.  */
  553. static Can_Message_t* Can_QueueReadTailPtr(Can_MessageQueue_t *q) {
  554.     if (q->nrElements > 0) {
  555.         return &(q->dataPtr[q->tail]);
  556.     }
  557.     else {
  558.         return 0;
  559.     }
  560. }
  561.  
  562.  
  563. /**
  564.  * Removes the last element in the queue (the tail). You should have extracted
  565.  * the data using Can_QueueReadTailPtr before using this function.
  566.  *
  567.  * @param q
  568.  *      Pointer to the queue object.
  569.  */
  570. static void Can_QueueRemoveTail(Can_MessageQueue_t *q) {
  571.     if (q->nrElements > 0) {
  572.         q->tail = (q->tail + 1) % q->size;
  573.         q->nrElements--;
  574.         #if 0
  575.         printf("queue size = %u\n", q->nrElements);
  576.         #endif
  577.     }
  578. }
  579.  
  580. #endif
  581.