Subversion Repositories HomeAutomation

Rev

Rev 240 | 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/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) __attribute__((unused));
  106. static Can_Return_t Can_ControllerCheckError(void) __attribute__((unused));
  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() != 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.                 cli();
  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.                 //TODO: dont enable interrupts, restore previous state
  225.                 sei();
  226.             }
  227.             else {
  228.                 /* quit the loop if the queue is empty */
  229.                 break;
  230.             }
  231.         }
  232.     #endif
  233.    
  234.     #if CAN_QUEUE_SIZE_RX > 0
  235.         /* move all received messages from CAN controller to reception queue */
  236.         Can_Message_t rxMsg;
  237.         /* all RX buffers have to be checked (and in correct order) */
  238.         for (uint8_t buf=0; buf<CAN_CONTROLLER_NR_RX_BUFFERS; buf++) {
  239.             /* if buffer contains a message, handle it */
  240.             if (Can_ReceiveFromController(&rxMsg, buf) == CAN_OK) {
  241.                 /* ensure the queue operations are atomic */
  242.                 cli();
  243.                 /* try to get access to the queue */
  244.                 Can_Message_t *destPtr = Can_QueueInsert(&canRxQueue);
  245.                 /* if we can insert into queue, copy the message */
  246.                 if (destPtr != 0) {
  247.                     memcpy(destPtr, &rxMsg, sizeof(Can_Message_t));
  248.                 }
  249.                 else {
  250.                     /* otherwise, the received message will be discarded... */
  251.                 }
  252.                 //TODO: dont enable interrupts, restore previous state
  253.                 sei();
  254.             }
  255.         }
  256.     #endif
  257.    
  258.     /* TODO: check error status in controller */
  259. }
  260.  
  261.  
  262. /**
  263.  * Receives a CAN message that is waiting in the reception queue. If no
  264.  * messages have been received, CAN_NO_MSG_AVAILABLE is returned.
  265.  * Otherwise, a CAN message is copied into the specified message buffer
  266.  * and deleted from the internal message reception queue. In this case,
  267.  * CAN_OK is returned.
  268.  *
  269.  * @param msg
  270.  *          Pointer to the message storage buffer into which the message
  271.  *          should be copied.
  272.  *
  273.  * @return
  274.  *          CAN_OK if a received message was successfully copied into the buffer.
  275.  *          CAN_NO_MSG_AVAILABLE if no messages are available.
  276.  */
  277. Can_Return_t Can_Receive(Can_Message_t *msg) {
  278.    
  279.     #if CAN_QUEUE_SIZE_RX > 0
  280.         /*
  281.          * RX queue is enabled, so try to get message from queue.
  282.          */
  283.         Can_Message_t *pSrc;    /* Source pointer */
  284.         /* Check if there is anything available in the RxQueue */
  285.         if (canRxQueue.nrElements == 0) {
  286.             return CAN_NO_MSG_AVAILABLE;
  287.         }
  288.         /* ensure the queue operations are atomic */
  289.         cli();
  290.         pSrc = Can_QueueReadTailPtr(&canRxQueue);
  291.         /* copy frame from queue, and then remove from queue */
  292.         memcpy(msg, pSrc, sizeof(Can_Message_t));
  293.         Can_QueueRemoveTail(&canRxQueue);
  294.         //TODO: dont enable interrupts, restore previous state
  295.         sei();
  296.         /* a message has successfully been copied and removed from queue */
  297.         return CAN_OK;
  298.     #else
  299.         /*
  300.          * RX queue is disabled, so try to get message from controller.
  301.          * We don't know which buffer to get the message from, so best
  302.          * we can do is to get from buf0 first time, and then increase
  303.          * buffer number at each call, finally wrapping around at
  304.          * CAN_CONTROLLER_NR_RX_BUFFERS.
  305.          */
  306.         static uint8_t rxBuffer = 0;
  307.         uint8_t i;
  308.         /* worst case is that we need to check all available rx buffers in order to find a message */
  309.         for (i=0; i<CAN_CONTROLLER_NR_RX_BUFFERS; i++) {
  310.             /* is there a message available in this buffer? */
  311.             if (Can_ReceiveFromController(msg, rxBuffer) == CAN_OK) {
  312.                 /* increase buffer number and return the message */
  313.                 rxBuffer = (rxBuffer + 1) % CAN_CONTROLLER_NR_RX_BUFFERS;
  314.                 return CAN_OK;
  315.             }
  316.             /* increase buffer number so we can check next buffer */
  317.             rxBuffer = (rxBuffer + 1) % CAN_CONTROLLER_NR_RX_BUFFERS;
  318.         }
  319.         /* all buffers were checked, but no message found */
  320.         return CAN_NO_MSG_AVAILABLE;
  321.     #endif
  322. }
  323.  
  324.  
  325.  
  326. /*-----------------------------------------------------------------------------
  327.  * Private Functions
  328.  *---------------------------------------------------------------------------*/  
  329.  
  330. /**
  331.  * Sends a CAN message immediately with the controller hardware. If the CAN
  332.  * controller is busy, the function will return CAN_SEND_FAIL_TX_BUSY.
  333.  *
  334.  * @param msg
  335.  *      Pointer to the CAN message storage buffer.
  336.  *
  337.  * @return
  338.  *      CAN_OK if the message was successfully sent to the controller.
  339.  *      CAN_FAIL if the controller is busy.
  340.  */
  341. static Can_Return_t Can_SendImmediately(Can_Message_t* msg) {
  342.     #if CAN_CONTROLLER == CAN_CONTROLLER_NULL
  343.         /*
  344.          * Send with null device.
  345.          */
  346.         return CAN_OK;
  347.     #endif
  348.  
  349.     #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515
  350.         /*
  351.          * Send with MCP2515 device.
  352.          */
  353.         uint8_t res, txbuf_n;
  354.         res = MCP2515_GetNextFreeTXBuf(&txbuf_n); // info = addr.
  355.         if (res == MCP_ALLTXBUSY) {
  356.             return CAN_FAIL;
  357.         }
  358.         MCP2515_WriteCanMsg(txbuf_n, msg);
  359.         MCP2515_StartTransmit(txbuf_n);
  360.         return CAN_OK;
  361.     #endif
  362. }
  363.  
  364.  
  365. /**
  366.  * Receives a CAN message from the CAN controller hardware.
  367.  *
  368.  * @param msg
  369.  *      Pointer to the message storage buffer into which the message should be copied.
  370.  *
  371.  * @param rxBuffer
  372.  *      Identifies the RX buffer in the controller. Range is [0,CAN_CONTROLLER_NR_RX_BUFFERS-1].
  373.  *
  374.  * @return
  375.  *      CAN_OK if a received message was successfully copied into the buffer.
  376.  *      CAN_NO_MSG_AVAILABLE if there are is no message available in the specified buffer.
  377.  *      CAN_FAIL if the rxBuffer parameter i out of range for the specified controller.
  378.  */
  379. static Can_Return_t Can_ReceiveFromController(Can_Message_t *msg, uint8_t rxBuffer) {
  380.     #if CAN_CONTROLLER == CAN_CONTROLLER_NULL
  381.         /*
  382.          * Receive from null device.
  383.          */
  384.         return CAN_NO_MSG_AVAILABLE;
  385.     #endif
  386.    
  387.     #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515
  388.         /*
  389.          * Receive from MCP2515 device.
  390.          */
  391.         uint8_t stat;
  392.         stat = MCP2515_ReadStatus();
  393.         if (rxBuffer == 0) {
  394.             /* check BUF0 */
  395.             if (stat & MCP_STAT_RX0IF) {
  396.                 /* Msg in Buffer 0 */
  397.                 MCP2515_ReadCanMsg(MCP_RXBUF_0, msg);
  398.                 MCP2515_ModifyRegister(MCP_CANINTF, MCP_RX0IF, 0);
  399.                 return CAN_OK;
  400.             }
  401.         }
  402.         else if (rxBuffer == 1) {
  403.             /* check BUF1 */
  404.             if (stat & MCP_STAT_RX1IF) {
  405.                 /* Msg in Buffer 1 */
  406.                 MCP2515_ReadCanMsg(MCP_RXBUF_1, msg);
  407.                 MCP2515_ModifyRegister(MCP_CANINTF, MCP_RX1IF, 0);
  408.                 return CAN_OK;
  409.             }
  410.         }
  411.         else {
  412.             /* invalid parameters */
  413.             return CAN_FAIL;
  414.         }
  415.         return CAN_NO_MSG_AVAILABLE;
  416.     #endif
  417. }
  418.  
  419.  
  420. /**
  421.  * Checks how many messages are available in the CAN controller hardware.
  422.  *
  423.  * @return
  424.  *      The number of messages available (0 if none).
  425.  */
  426. static uint8_t Can_MessagesAvailableInController() {
  427.     #if CAN_CONTROLLER == CAN_CONTROLLER_NULL
  428.         /*
  429.          * Check for messages in null device.
  430.          */
  431.         return 0;
  432.     #endif
  433.    
  434.     #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515
  435.         /*
  436.          * Check for message in MCP2515 device.
  437.          */
  438.         uint8_t res;
  439.         res = MCP2515_ReadStatus(); /* RXnIF in Bit 1 and 0 */
  440.         if (res & MCP_STAT_RXIF_MASK) {
  441.             //TODO: check how many messages are available
  442.             return 1;   /* at least one message available */
  443.         }
  444.         else {
  445.             return 0;   /* no messages available */
  446.         }
  447.     #endif
  448.    
  449.     return 0;
  450. }
  451.  
  452.  
  453. /*
  454.  * Checks Controller-Error-State.
  455.  *
  456.  * @return
  457.  *      CAN_OK if the controller is OK.
  458.  *      CAN_FAIL if errors have occured.
  459.  *
  460.  * @todo
  461.  *      Styr upp denna funktion lite b�ttre.
  462.  */
  463. static Can_Return_t Can_ControllerCheckError() {
  464.     #if CAN_CONTROLLER == CAN_CONTROLLER_NULL
  465.         /*
  466.          * Check for errors in null device.
  467.          */
  468.         return CAN_OK;
  469.     #endif
  470.    
  471.     #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515
  472.         /*
  473.          * Check for errors in MCP2515 device.
  474.          */
  475.         uint8_t eflg = MCP2515_ReadRegister(MCP_EFLG);
  476.         if (eflg & MCP_EFLG_ERRORMASK) {
  477.             return CAN_FAIL;    /* errors found */
  478.         }
  479.         else {
  480.             return CAN_OK;      /* no errors found */
  481.         }
  482.     #endif
  483. }
  484.  
  485.  
  486. #if (CAN_QUEUE_SIZE_TX > 0) || (CAN_QUEUE_SIZE_RX > 0)
  487. /**
  488.  * Initializes a CAN queue.
  489.  *
  490.  * @param q
  491.  *      Pointer to the queue object.
  492.  *
  493.  * @param size
  494.  *      Size of the queue (number of messages that can be queued).
  495.  *
  496.  * @param dataPtr
  497.  *      Pointer to the message storage buffer that should be used by the queue.
  498.  */
  499. static void Can_QueueInit(Can_MessageQueue_t *q, uint8_t size, Can_Message_t *dataPtr) {
  500.     q->dataPtr = dataPtr;
  501.     q->head = 0;
  502.     q->tail = 0;
  503.     q->nrElements = 0;
  504.     q->size = size;
  505. }
  506.  
  507.  
  508. /**
  509.  * Inserts a new element in a queue and returns a pointer to the new element.
  510.  * If the queue is full, the last element (the tail) will be overwritten by
  511.  * the new element.
  512.  *
  513.  * @param q
  514.  *      Pointer to the queue object.
  515.  *
  516.  * @return
  517.  *      Pointer to the new message element. Use this pointer to copy data into the queue.
  518.  */
  519. static Can_Message_t* Can_QueueInsert(Can_MessageQueue_t *q) {
  520.     Can_Message_t *ptr;
  521.     #if 0
  522.     printf("INSERT: bef=%u, ", q->nrElements);
  523.     #endif
  524.     if ((q->nrElements+1) > q->size) {
  525.         q->tail = (q->tail + 1) % q->size;
  526.         q->nrElements--;
  527.     #if 0
  528.         printf("Can_QueueInsertViaPtr: QUEUE OVERRUN!\n\r");
  529.     #endif
  530.     }
  531.     ptr = &(q->dataPtr[q->head]);
  532.     #if 0
  533.     if (q->handled[q->head] == 0) {
  534.         printf("Can_QueueInsertViaPtr: discarding non-handled msg!\n\r");
  535.     }
  536.     #endif
  537.     q->head = (q->head + 1) % q->size;
  538.     q->nrElements++;
  539.     #if 0
  540.     printf("aft=%u\n\n", q->nrElements);
  541.     #endif
  542.     return ptr;
  543. }
  544.  
  545.  
  546. /**
  547.  * Returns a pointer to the last element in the queue (the tail). Use this pointer
  548.  * to extract the message, and then call Can_QueueRemoveTail to actually remove
  549.  * the element.
  550.  *
  551.  * @param q
  552.  *      Pointer to the queue object.
  553.  *
  554.  * @return
  555.  *      Pointer to the tail message element.
  556.  */
  557. static Can_Message_t* Can_QueueReadTailPtr(Can_MessageQueue_t *q) {
  558.     if (q->nrElements > 0) {
  559.         return &(q->dataPtr[q->tail]);
  560.     }
  561.     else {
  562.         return 0;
  563.     }
  564. }
  565.  
  566.  
  567. /**
  568.  * Removes the last element in the queue (the tail). You should have extracted
  569.  * the data using Can_QueueReadTailPtr before using this function.
  570.  *
  571.  * @param q
  572.  *      Pointer to the queue object.
  573.  */
  574. static void Can_QueueRemoveTail(Can_MessageQueue_t *q) {
  575.     if (q->nrElements > 0) {
  576.         q->tail = (q->tail + 1) % q->size;
  577.         q->nrElements--;
  578.         #if 0
  579.         printf("queue size = %u\n", q->nrElements);
  580.         #endif
  581.     }
  582. }
  583.  
  584. #endif
  585.