Subversion Repositories HomeAutomation

Rev

Rev 2150 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. #include "stdcan.h"
  2.  
  3. #ifdef MCP_CAN_BITRATE_KBPS
  4. #ifndef CAN_BAUDRATE
  5. #define CAN_BAUDRATE MCP_CAN_BITRATE_KBPS
  6. #endif
  7. #endif
  8.  
  9. #if defined(_AVRLIB_BIOS_)
  10. #include <bios.h>
  11. #define Can_Send BIOS_CanSend
  12. #else
  13. #if (CAN_CONTROLLER == MCP2515)
  14. #include <drivers/can/mcp2515/mcp2515.h>
  15. #elif (CAN_CONTROLLER == CAN_AVR_INTERNAL)
  16. #include <drivers/can/avr_internal/avr_internal.h>
  17. #endif
  18. #endif
  19.  
  20. #include <avr/interrupt.h>
  21. #include <util/atomic.h>
  22. #if (STDCAN_TX_QUEUE_SIZE > 1)
  23. #error StdCan: Tx queue size longer than one msg not yet implemented.
  24. #endif
  25.  
  26. /**
  27.  * The receive queue.
  28.  */
  29. StdCan_Msg_t RxQ[STDCAN_RX_QUEUE_SIZE + 1];
  30. unsigned char RxQ_Rd_idx; /**< Receive queue read index. */
  31. unsigned char RxQ_Wr_idx; /**< Receive queue write index. */
  32.  
  33. #if (STDCAN_TX_QUEUE_SIZE > 1)
  34. /**
  35.  * The transmit queue.
  36.  */
  37. StdCan_Msg_t TxQ[STDCAN_TX_QUEUE_SIZE];
  38. unsigned char TxQ_Rd_idx; /**< Transmit queue read index. */
  39. unsigned char TxQ_Wr_idx; /**< Transmit queue write index. */
  40. #endif
  41.  
  42. #if (STDCAN_FILTER)
  43. /**
  44.  * The message acceptance filters.
  45.  */
  46. typedef struct {
  47.     char Active; /**< True if this filter should be used. */
  48.     unsigned long Id; /**< Match if id matches the message id in all bit locations that are not masked. */
  49.     unsigned long Mask; /**< Each bit specifies if the corresponding id bit must match (mask[n] = 1) or is Don't Care (mask[n] = 0). */
  50. } StdCan_Filter_t;
  51.  
  52. StdCan_Filter_t RxFilters[STDCAN_NUM_FILTERS];
  53. #endif
  54.  
  55. /**
  56.  * CAN message callback.
  57.  * Callback for when a message is received from the lower
  58.  * layer (BIOS or CAN driver).
  59.  */
  60. void Can_Process(Can_Message_t* msg)
  61. {
  62.     /* What will the next write index be if the push goes well? */
  63.     unsigned char Wr_next = RxQ_Wr_idx + 1;
  64.     if (Wr_next >= STDCAN_RX_QUEUE_SIZE + 1) Wr_next = 0;
  65.  
  66.     /* Check if there is room on the queue. */
  67.     if (Wr_next != RxQ_Rd_idx) {
  68.         unsigned char n;
  69. #if (STDCAN_FILTER)
  70.         /* Try to match each filter in turn. */
  71.         for (n = 0; n < STDCAN_NUM_FILTERS; n++) {
  72.             if (RxFilters[n].Active && !((msg->Id ^ RxFilters[n].Id) & RxFilters[n].Mask)) {
  73.                 RxQ[RxQ_Wr_idx].Match = n;
  74.                 break;
  75.             }
  76.         }
  77.  
  78.         if (n == STDCAN_NUM_FILTERS) return; // No match found, discard message.
  79. #endif
  80.         /* Copy the message from lower layer into the queue. */
  81.         RxQ[RxQ_Wr_idx].Id     = msg->Id;
  82.         RxQ[RxQ_Wr_idx].Length = msg->DataLength;
  83.         //TODO: This should be guarded against invalid DataLength.
  84.         for (n = 0; n < RxQ[RxQ_Wr_idx].Length; n++) {
  85.             RxQ[RxQ_Wr_idx].Data[n] = msg->Data.bytes[n];
  86.         }
  87.         /* Update write index. */
  88.         RxQ_Wr_idx = Wr_next;
  89.     } else {
  90.         /* Overflow, just drop the new message. In the future, some
  91.          * form of priority scheme could be used to drop another
  92.          * message in the queue.
  93.          */
  94.     }
  95. }
  96.  
  97. #ifdef MODULE_APPLICATION
  98. StdCan_Ret_t StdCan_Init(void)
  99. {
  100. #else
  101. StdCan_Ret_t StdCan_Init(Node_Desc_t* node_desc)
  102. {
  103. #endif
  104.     StdCan_Ret_t retval;
  105.  
  106.     /* Reset all queue variables. */
  107.     RxQ_Rd_idx = 0;
  108.     RxQ_Wr_idx = 0;
  109. #if (STDCAN_TX_QUEUE_SIZE > 1)
  110.     TxQ_Rd_idx = 0;
  111.     TxQ_Wr_idx = 0;
  112. #endif
  113.  
  114. #if defined(_AVRLIB_BIOS_)
  115.     /* Initialize BIOS' interface for CAN. */
  116.     BIOS_CanCallback = Can_Process;
  117.     retval = StdCan_Ret_OK;
  118. #else
  119.     /* Initialize CAN driver. */
  120.     if (Can_Init() == CAN_OK)
  121.         retval = StdCan_Ret_OK;
  122.     else
  123.         retval = StdCan_Ret_Fail;
  124. #endif
  125.  
  126.     //TODO: Do something with the Node Descriptor.
  127.     //(why have constants passed as parameters? they are defined at compiletime /arune)
  128. #if defined(_AVRLIB_BIOS_)
  129.     /* TODO: When a Tx queue is implemented, the startup message should
  130.      * be sent via StdCan_Put instead of directly to lower layer.
  131.      */
  132.     Can_Message_t Startup;
  133.  
  134.     /* Set up Startup message format. */
  135.     Startup.ExtendedFlag = 1;
  136.     Startup.RemoteFlag = 0;
  137.     Startup.DataLength = 4;
  138. #ifdef MODULE_APPLICATION
  139.     Startup.Id = (CAN_NMT << CAN_SHIFT_CLASS) | (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE);
  140.     Startup.Data.bytes[0] = BIOS_GetHwId()&0xff;
  141.     Startup.Data.bytes[1] = (BIOS_GetHwId()>>8)&0xff;
  142.     Startup.Data.bytes[2] = (BIOS_GetHwId()>>16)&0xff;
  143.     Startup.Data.bytes[3] = (BIOS_GetHwId()>>24)&0xff;
  144. #else
  145.     Startup.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
  146.     Startup.Data.bytes[1] = APP_TYPE&0xff;
  147.     Startup.Data.bytes[0] = (APP_TYPE>>8)&0xff;
  148.     Startup.Data.bytes[3] = APP_VERSION&0xff;
  149.     Startup.Data.bytes[2] = (APP_VERSION>>8)&0xff;
  150. #endif
  151.     /* Try to send it. */
  152.     Can_Send(&Startup);
  153. #endif
  154.  
  155.     return retval;
  156. }
  157.  
  158. StdCan_Ret_t StdCan_Get(StdCan_Msg_t* msg)
  159. {
  160.     unsigned char Wr_idx;
  161.     unsigned char Rd_idx;
  162.  
  163.     /* Read indices atomically into local copies. */
  164.     ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  165.         Wr_idx = *(volatile unsigned char*)&RxQ_Wr_idx;
  166.         Rd_idx = *(volatile unsigned char*)&RxQ_Rd_idx;
  167.     }
  168.  
  169.     /* Check if there's a message waiting. */
  170.     if (Rd_idx != Wr_idx) {
  171.         unsigned char n;
  172.  
  173.         /* Copy message to user buffer. */
  174.         msg->Id     = RxQ[Rd_idx].Id;
  175.         msg->Length = RxQ[Rd_idx].Length;
  176.         //TODO: Consider a mempcy() of the entire message.
  177.         for (n = 0; n < RxQ[Rd_idx].Length; n++) {
  178.             msg->Data[n] = RxQ[Rd_idx].Data[n];
  179.         }
  180.  
  181.         /* Update read index and store back atomically. */
  182.         if (++Rd_idx >= STDCAN_RX_QUEUE_SIZE + 1) Rd_idx = 0;
  183.         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  184.             *(volatile unsigned char*)&RxQ_Rd_idx = Rd_idx;
  185.         }
  186.  
  187.         return StdCan_Ret_OK;
  188.     } else {
  189.         /* Queue is empty. */
  190.         return StdCan_Ret_Empty;
  191.     }
  192. }
  193.  
  194. StdCan_Ret_t StdCan_Put(StdCan_Msg_t* msg)
  195. {
  196.     Can_Message_t Can_Msg;
  197.     unsigned char n;
  198.  
  199.     /* Validate message. */
  200.     if ((unsigned)msg->Length > 8) return StdCan_Ret_DataErr;
  201.  
  202.     /* Copy message directly to lower layer until a proper
  203.      * queue has been implemented.
  204.      * TODO: Implement a proper queue. This requires TX interrupt
  205.      * support in the driver and BIOS.
  206.      */
  207.     Can_Msg.ExtendedFlag = 1;
  208.     Can_Msg.RemoteFlag = 0;
  209.     Can_Msg.Id = msg->Id;
  210.     Can_Msg.DataLength = msg->Length;
  211.     for (n = 0; n < msg->Length; n++) {
  212.         Can_Msg.Data.bytes[n] = msg->Data[n];
  213.     }
  214.  
  215.     if (Can_Send(&Can_Msg) == CAN_OK) {
  216. #ifdef MODULE_APPLICATION
  217.         Can_Process(&Can_Msg);
  218. #endif
  219.         return StdCan_Ret_OK;
  220.     }
  221.     else
  222.         return StdCan_Ret_Full;
  223. }
  224.  
  225. void StdCan_SendHeartbeat(uint8_t n)
  226. {
  227.     /* TODO: When a Tx queue is implemented, the heartbeat should
  228.      * be sent via StdCan_Put instead of directly to lower layer.
  229.      */
  230.     Can_Message_t Heartbeat;
  231.  
  232.     /* Set up Heartbeat message format. */
  233.     Heartbeat.ExtendedFlag = 1;
  234.     Heartbeat.RemoteFlag = 0;
  235. #ifdef MODULE_APPLICATION
  236.     Heartbeat.DataLength = 5;
  237.     Heartbeat.Id = (CAN_NMT << CAN_SHIFT_CLASS) | (CAN_NMT_HEARTBEAT << CAN_SHIFT_NMT_TYPE);
  238.     uint32_t HwId=BIOS_GetHwId();
  239.     Heartbeat.Data.bytes[0] = HwId&0xff;
  240.     Heartbeat.Data.bytes[1] = (HwId>>8)&0xff;
  241.     Heartbeat.Data.bytes[2] = (HwId>>16)&0xff;
  242.     Heartbeat.Data.bytes[3] = (HwId>>24)&0xff;
  243.     Heartbeat.Data.bytes[4] = NUMBER_OF_MODULES;
  244. #else
  245.  
  246.  
  247.     Heartbeat.DataLength = 0;
  248.     Heartbeat.Id = (CAN_NMT << CAN_SHIFT_CLASS)
  249.                  | (CAN_NMT_HEARTBEAT << CAN_SHIFT_NMT_TYPE)
  250.                  | (NODE_ID << CAN_SHIFT_NMT_SID);
  251. #endif
  252.  
  253.     /* Try to send it. */
  254.     Can_Send(&Heartbeat);
  255. }
  256.  
  257. #if (STDCAN_FILTER)
  258. StdCan_Ret_t StdCan_EnableFilter(unsigned char filter, unsigned long id, unsigned long mask)
  259. {
  260.     if (filter < STDCAN_NUM_FILTERS) {
  261.         RxFilters[filter].Id = id;
  262.         RxFilters[filter].Mask = mask;
  263.         RxFilters[filter].Active = 1;
  264.         return StdCan_Ret_OK;
  265.     } else {
  266.         return StdCan_Ret_DataErr;
  267.     }
  268. }
  269.  
  270. StdCan_Ret_t StdCan_DisableFilter(unsigned char filter)
  271. {
  272.     if (filter < STDCAN_NUM_FILTERS) {
  273.         RxFilters[filter].Active = 0;
  274.         return StdCan_Ret_OK;
  275.     } else {
  276.         return StdCan_Ret_DataErr;
  277.     }
  278. }
  279. #endif
  280.