Subversion Repositories HomeAutomation

Rev

Rev 2136 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. #include "stdcan.h"
  2. #if defined(_AVRLIB_BIOS_)
  3. #include <bios.h>
  4. #define Can_Send BIOS_CanSend
  5. #else
  6. #include <drivers/can/mcp2515/mcp2515.h>
  7. #endif
  8.  
  9. #include <avr/interrupt.h>
  10. #include <util/atomic.h>
  11. #if (STDCAN_TX_QUEUE_SIZE > 1)
  12. #error StdCan: Tx queue size longer than one msg not yet implemented.
  13. #endif
  14.  
  15. /**
  16.  * The receive queue.
  17.  */
  18. StdCan_Msg_t RxQ[STDCAN_RX_QUEUE_SIZE + 1];
  19. unsigned char RxQ_Rd_idx; /**< Receive queue read index. */
  20. unsigned char RxQ_Wr_idx; /**< Receive queue write index. */
  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. #endif
  30.  
  31. #if (STDCAN_FILTER)
  32. /**
  33.  * The message acceptance filters.
  34.  */
  35. typedef struct {
  36.     char Active; /**< True if this filter should be used. */
  37.     unsigned long Id; /**< Match if id matches the message id in all bit locations that are not masked. */
  38.     unsigned long Mask; /**< Each bit specifies if the corresponding id bit must match (mask[n] = 1) or is Don't Care (mask[n] = 0). */
  39. } StdCan_Filter_t;
  40.  
  41. StdCan_Filter_t RxFilters[STDCAN_NUM_FILTERS];
  42. #endif
  43.  
  44. /**
  45.  * CAN message callback.
  46.  * Callback for when a message is received from the lower
  47.  * layer (BIOS or CAN driver).
  48.  */
  49. void Can_Process(Can_Message_t* msg)
  50. {
  51.     /* What will the next write index be if the push goes well? */
  52.     unsigned char Wr_next = RxQ_Wr_idx + 1;
  53.     if (Wr_next >= STDCAN_RX_QUEUE_SIZE + 1) Wr_next = 0;
  54.  
  55.     /* Check if there is room on the queue. */
  56.     if (Wr_next != RxQ_Rd_idx) {
  57.         unsigned char n;
  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.         /* Update write index. */
  77.         RxQ_Wr_idx = Wr_next;
  78.     } else {
  79.         /* Overflow, just drop the new message. In the future, some
  80.          * form of priority scheme could be used to drop another
  81.          * message in the queue.
  82.          */
  83.     }
  84. }
  85.  
  86. #ifdef MODULE_APPLICATION
  87. StdCan_Ret_t StdCan_Init(void)
  88. {
  89. #else
  90. StdCan_Ret_t StdCan_Init(Node_Desc_t* node_desc)
  91. {
  92. #endif
  93.     StdCan_Ret_t retval;
  94.  
  95.     /* Reset all queue variables. */
  96.     RxQ_Rd_idx = 0;
  97.     RxQ_Wr_idx = 0;
  98. #if (STDCAN_TX_QUEUE_SIZE > 1)
  99.     TxQ_Rd_idx = 0;
  100.     TxQ_Wr_idx = 0;
  101. #endif
  102.  
  103. #if defined(_AVRLIB_BIOS_)
  104.     /* Initialize BIOS' interface for CAN. */
  105.     BIOS_CanCallback = Can_Process;
  106.     retval = StdCan_Ret_OK;
  107. #else
  108.     /* Initialize CAN driver. */
  109.     if (Can_Init() == CAN_OK)
  110.         retval = StdCan_Ret_OK;
  111.     else
  112.         retval = StdCan_Ret_Fail;
  113. #endif
  114.  
  115.     //TODO: Do something with the Node Descriptor.
  116.     //(why have constants passed as parameters? they are defined at compiletime /arune)
  117. #if defined(_AVRLIB_BIOS_)
  118.     /* TODO: When a Tx queue is implemented, the startup message should
  119.      * be sent via StdCan_Put instead of directly to lower layer.
  120.      */
  121.     Can_Message_t Startup;
  122.  
  123.     /* Set up Startup message format. */
  124.     Startup.ExtendedFlag = 1;
  125.     Startup.RemoteFlag = 0;
  126.     Startup.DataLength = 4;
  127. #ifdef MODULE_APPLICATION
  128.     Startup.Id = (CAN_NMT << CAN_SHIFT_CLASS) | (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE);
  129.     Startup.Data.bytes[0] = BIOS_GetHwId()&0xff;
  130.     Startup.Data.bytes[1] = (BIOS_GetHwId()>>8)&0xff;
  131.     Startup.Data.bytes[2] = (BIOS_GetHwId()>>16)&0xff;
  132.     Startup.Data.bytes[3] = (BIOS_GetHwId()>>24)&0xff;
  133. #else
  134.     Startup.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
  135.     Startup.Data.bytes[1] = APP_TYPE&0xff;
  136.     Startup.Data.bytes[0] = (APP_TYPE>>8)&0xff;
  137.     Startup.Data.bytes[3] = APP_VERSION&0xff;
  138.     Startup.Data.bytes[2] = (APP_VERSION>>8)&0xff;
  139. #endif
  140.     /* Try to send it. */
  141.     Can_Send(&Startup);
  142. #endif
  143.  
  144.     return retval;
  145. }
  146.  
  147. StdCan_Ret_t StdCan_Get(StdCan_Msg_t* msg)
  148. {
  149.     unsigned char Wr_idx;
  150.     unsigned char Rd_idx;
  151.  
  152.     /* Read indices atomically into local copies. */
  153.     ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  154.         Wr_idx = *(volatile unsigned char*)&RxQ_Wr_idx;
  155.         Rd_idx = *(volatile unsigned char*)&RxQ_Rd_idx;
  156.     }
  157.  
  158.     /* Check if there's a message waiting. */
  159.     if (Rd_idx != Wr_idx) {
  160.         unsigned char n;
  161.  
  162.         /* Copy message to user buffer. */
  163.         msg->Id     = RxQ[Rd_idx].Id;
  164.         msg->Length = RxQ[Rd_idx].Length;
  165.         //TODO: Consider a mempcy() of the entire message.
  166.         for (n = 0; n < RxQ[Rd_idx].Length; n++) {
  167.             msg->Data[n] = RxQ[Rd_idx].Data[n];
  168.         }
  169.  
  170.         /* Update read index and store back atomically. */
  171.         if (++Rd_idx >= STDCAN_RX_QUEUE_SIZE + 1) Rd_idx = 0;
  172.         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  173.             *(volatile unsigned char*)&RxQ_Rd_idx = Rd_idx;
  174.         }
  175.  
  176.         return StdCan_Ret_OK;
  177.     } else {
  178.         /* Queue is empty. */
  179.         return StdCan_Ret_Empty;
  180.     }
  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.     uint32_t HwId=BIOS_GetHwId();
  228.     Heartbeat.Data.bytes[0] = HwId&0xff;
  229.     Heartbeat.Data.bytes[1] = (HwId>>8)&0xff;
  230.     Heartbeat.Data.bytes[2] = (HwId>>16)&0xff;
  231.     Heartbeat.Data.bytes[3] = (HwId>>24)&0xff;
  232.     Heartbeat.Data.bytes[4] = NUMBER_OF_MODULES;
  233. #else
  234.  
  235.  
  236.     Heartbeat.DataLength = 0;
  237.     Heartbeat.Id = (CAN_NMT << CAN_SHIFT_CLASS)
  238.                  | (CAN_NMT_HEARTBEAT << CAN_SHIFT_NMT_TYPE)
  239.                  | (NODE_ID << CAN_SHIFT_NMT_SID);
  240. #endif
  241.  
  242.     /* Try to send it. */
  243.     Can_Send(&Heartbeat);
  244. }
  245.  
  246. #if (STDCAN_FILTER)
  247. StdCan_Ret_t StdCan_EnableFilter(unsigned char filter, unsigned long id, unsigned long mask)
  248. {
  249.     if (filter < STDCAN_NUM_FILTERS) {
  250.         RxFilters[filter].Id = id;
  251.         RxFilters[filter].Mask = mask;
  252.         RxFilters[filter].Active = 1;
  253.         return StdCan_Ret_OK;
  254.     } else {
  255.         return StdCan_Ret_DataErr;
  256.     }
  257. }
  258.  
  259. StdCan_Ret_t StdCan_DisableFilter(unsigned char filter)
  260. {
  261.     if (filter < STDCAN_NUM_FILTERS) {
  262.         RxFilters[filter].Active = 0;
  263.         return StdCan_Ret_OK;
  264.     } else {
  265.         return StdCan_Ret_DataErr;
  266.     }
  267. }
  268. #endif
  269.