Subversion Repositories HomeAutomation

Rev

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

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