Subversion Repositories HomeAutomation

Rev

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