Subversion Repositories HomeAutomation

Rev

Rev 1909 | Rev 2150 | 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.  
  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 + 1];
  20. unsigned char RxQ_Rd_idx; /**< Receive queue read index. */
  21. unsigned char RxQ_Wr_idx; /**< Receive queue write index. */
  22.  
  23. #if (STDCAN_TX_QUEUE_SIZE > 1)
  24. /**
  25.  * The transmit queue.
  26.  */
  27. StdCan_Msg_t TxQ[STDCAN_TX_QUEUE_SIZE];
  28. unsigned char TxQ_Rd_idx; /**< Transmit queue read index. */
  29. unsigned char TxQ_Wr_idx; /**< Transmit queue write index. */
  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.     /* What will the next write index be if the push goes well? */
  53.     unsigned char Wr_next = RxQ_Wr_idx + 1;
  54.     if (Wr_next >= STDCAN_RX_QUEUE_SIZE + 1) Wr_next = 0;
  55.  
  56.     /* Check if there is room on the queue. */
  57.     if (Wr_next != RxQ_Rd_idx) {
  58.         unsigned char n;
  59. #if (STDCAN_FILTER)
  60.         /* Try to match each filter in turn. */
  61.         for (n = 0; n < STDCAN_NUM_FILTERS; n++) {
  62.             if (RxFilters[n].Active && !((msg->Id ^ RxFilters[n].Id) & RxFilters[n].Mask)) {
  63.                 RxQ[RxQ_Wr_idx].Match = n;
  64.                 break;
  65.             }
  66.         }
  67.  
  68.         if (n == STDCAN_NUM_FILTERS) return; // No match found, discard message.
  69. #endif
  70.         /* Copy the message from lower layer into the queue. */
  71.         RxQ[RxQ_Wr_idx].Id     = msg->Id;
  72.         RxQ[RxQ_Wr_idx].Length = msg->DataLength;
  73.         //TODO: This should be guarded against invalid DataLength.
  74.         for (n = 0; n < RxQ[RxQ_Wr_idx].Length; n++) {
  75.             RxQ[RxQ_Wr_idx].Data[n] = msg->Data.bytes[n];
  76.         }
  77.         /* Update write index. */
  78.         RxQ_Wr_idx = Wr_next;
  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. #if (STDCAN_TX_QUEUE_SIZE > 1)
  100.     TxQ_Rd_idx = 0;
  101.     TxQ_Wr_idx = 0;
  102. #endif
  103.  
  104. #if defined(_AVRLIB_BIOS_)
  105.     /* Initialize BIOS' interface for CAN. */
  106.     BIOS_CanCallback = Can_Process;
  107.     retval = StdCan_Ret_OK;
  108. #else
  109.     /* Initialize CAN driver. */
  110.     if (Can_Init() == CAN_OK)
  111.         retval = StdCan_Ret_OK;
  112.     else
  113.         retval = StdCan_Ret_Fail;
  114. #endif
  115.  
  116.     //TODO: Do something with the Node Descriptor.
  117.     //(why have constants passed as parameters? they are defined at compiletime /arune)
  118. #if defined(_AVRLIB_BIOS_)
  119.     /* TODO: When a Tx queue is implemented, the startup message should
  120.      * be sent via StdCan_Put instead of directly to lower layer.
  121.      */
  122.     Can_Message_t Startup;
  123.  
  124.     /* Set up Startup message format. */
  125.     Startup.ExtendedFlag = 1;
  126.     Startup.RemoteFlag = 0;
  127.     Startup.DataLength = 4;
  128. #ifdef MODULE_APPLICATION
  129.     Startup.Id = (CAN_NMT << CAN_SHIFT_CLASS) | (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE);
  130.     Startup.Data.bytes[0] = BIOS_GetHwId()&0xff;
  131.     Startup.Data.bytes[1] = (BIOS_GetHwId()>>8)&0xff;
  132.     Startup.Data.bytes[2] = (BIOS_GetHwId()>>16)&0xff;
  133.     Startup.Data.bytes[3] = (BIOS_GetHwId()>>24)&0xff;
  134. #else
  135.     Startup.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
  136.     Startup.Data.bytes[1] = APP_TYPE&0xff;
  137.     Startup.Data.bytes[0] = (APP_TYPE>>8)&0xff;
  138.     Startup.Data.bytes[3] = APP_VERSION&0xff;
  139.     Startup.Data.bytes[2] = (APP_VERSION>>8)&0xff;
  140. #endif
  141.     /* Try to send it. */
  142.     Can_Send(&Startup);
  143. #endif
  144.  
  145.     return retval;
  146. }
  147.  
  148. StdCan_Ret_t StdCan_Get(StdCan_Msg_t* msg)
  149. {
  150.     unsigned char Wr_idx;
  151.     unsigned char Rd_idx;
  152.  
  153.     /* Read indices atomically into local copies. */
  154.     ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  155.         Wr_idx = *(volatile unsigned char*)&RxQ_Wr_idx;
  156.         Rd_idx = *(volatile unsigned char*)&RxQ_Rd_idx;
  157.     }
  158.  
  159.     /* Check if there's a message waiting. */
  160.     if (Rd_idx != Wr_idx) {
  161.         unsigned char n;
  162.  
  163.         /* Copy message to user buffer. */
  164.         msg->Id     = RxQ[Rd_idx].Id;
  165.         msg->Length = RxQ[Rd_idx].Length;
  166.         //TODO: Consider a mempcy() of the entire message.
  167.         for (n = 0; n < RxQ[Rd_idx].Length; n++) {
  168.             msg->Data[n] = RxQ[Rd_idx].Data[n];
  169.         }
  170.  
  171.         /* Update read index and store back atomically. */
  172.         if (++Rd_idx >= STDCAN_RX_QUEUE_SIZE + 1) Rd_idx = 0;
  173.         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  174.             *(volatile unsigned char*)&RxQ_Rd_idx = Rd_idx;
  175.         }
  176.  
  177.         return StdCan_Ret_OK;
  178.     } else {
  179.         /* Queue is empty. */
  180.         return StdCan_Ret_Empty;
  181.     }
  182. }
  183.  
  184. StdCan_Ret_t StdCan_Put(StdCan_Msg_t* msg)
  185. {
  186.     Can_Message_t Can_Msg;
  187.     unsigned char n;
  188.  
  189.     /* Validate message. */
  190.     if ((unsigned)msg->Length > 8) return StdCan_Ret_DataErr;
  191.  
  192.     /* Copy message directly to lower layer until a proper
  193.      * queue has been implemented.
  194.      * TODO: Implement a proper queue. This requires TX interrupt
  195.      * support in the driver and BIOS.
  196.      */
  197.     Can_Msg.ExtendedFlag = 1;
  198.     Can_Msg.RemoteFlag = 0;
  199.     Can_Msg.Id = msg->Id;
  200.     Can_Msg.DataLength = msg->Length;
  201.     for (n = 0; n < msg->Length; n++) {
  202.         Can_Msg.Data.bytes[n] = msg->Data[n];
  203.     }
  204.  
  205.     if (Can_Send(&Can_Msg) == CAN_OK) {
  206. #ifdef MODULE_APPLICATION
  207.         Can_Process(&Can_Msg);
  208. #endif
  209.         return StdCan_Ret_OK;
  210.     }
  211.     else
  212.         return StdCan_Ret_Full;
  213. }
  214.  
  215. void StdCan_SendHeartbeat(uint8_t n)
  216. {
  217.     /* TODO: When a Tx queue is implemented, the heartbeat should
  218.      * be sent via StdCan_Put instead of directly to lower layer.
  219.      */
  220.     Can_Message_t Heartbeat;
  221.  
  222.     /* Set up Heartbeat message format. */
  223.     Heartbeat.ExtendedFlag = 1;
  224.     Heartbeat.RemoteFlag = 0;
  225. #ifdef MODULE_APPLICATION
  226.     Heartbeat.DataLength = 5;
  227.     Heartbeat.Id = (CAN_NMT << CAN_SHIFT_CLASS) | (CAN_NMT_HEARTBEAT << CAN_SHIFT_NMT_TYPE);
  228.     uint32_t HwId=BIOS_GetHwId();
  229.     Heartbeat.Data.bytes[0] = HwId&0xff;
  230.     Heartbeat.Data.bytes[1] = (HwId>>8)&0xff;
  231.     Heartbeat.Data.bytes[2] = (HwId>>16)&0xff;
  232.     Heartbeat.Data.bytes[3] = (HwId>>24)&0xff;
  233.     Heartbeat.Data.bytes[4] = NUMBER_OF_MODULES;
  234. #else
  235.  
  236.  
  237.     Heartbeat.DataLength = 0;
  238.     Heartbeat.Id = (CAN_NMT << CAN_SHIFT_CLASS)
  239.                  | (CAN_NMT_HEARTBEAT << CAN_SHIFT_NMT_TYPE)
  240.                  | (NODE_ID << CAN_SHIFT_NMT_SID);
  241. #endif
  242.  
  243.     /* Try to send it. */
  244.     Can_Send(&Heartbeat);
  245. }
  246.  
  247. #if (STDCAN_FILTER)
  248. StdCan_Ret_t StdCan_EnableFilter(unsigned char filter, unsigned long id, unsigned long mask)
  249. {
  250.     if (filter < STDCAN_NUM_FILTERS) {
  251.         RxFilters[filter].Id = id;
  252.         RxFilters[filter].Mask = mask;
  253.         RxFilters[filter].Active = 1;
  254.         return StdCan_Ret_OK;
  255.     } else {
  256.         return StdCan_Ret_DataErr;
  257.     }
  258. }
  259.  
  260. StdCan_Ret_t StdCan_DisableFilter(unsigned char filter)
  261. {
  262.     if (filter < STDCAN_NUM_FILTERS) {
  263.         RxFilters[filter].Active = 0;
  264.         return StdCan_Ret_OK;
  265.     } else {
  266.         return StdCan_Ret_DataErr;
  267.     }
  268. }
  269. #endif