Subversion Repositories HomeAutomation

Rev

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

  1. /**
  2.  * High level functions for bus communication and standard node behaviour.
  3.  *
  4.  * @author  Andreas Fritiofson
  5.  *
  6.  * @date    2007-10-24
  7.  */
  8.  
  9. #include <config.h>
  10. #include "stdcan.h"
  11. #if defined(_AVRLIB_BIOS_)
  12. #include <bios.h>
  13. #define Can_Send BIOS_CanSend
  14. #else
  15. #include <drivers/can/mcp2515/mcp2515.h>
  16. #endif
  17.  
  18. #if (STDCAN_TX_QUEUE_SIZE > 1)
  19. #error StdCan: Tx queue size longer than one msg not yet implemented.
  20. #endif
  21.  
  22. /**
  23.  * The receive queue.
  24.  */
  25. StdCan_Msg_t RxQ[STDCAN_RX_QUEUE_SIZE];
  26. unsigned char RxQ_Rd_idx; /**< Receive queue read index. */
  27. unsigned char RxQ_Wr_idx; /**< Receive queue write index. */
  28. unsigned char RxQ_Len; /**< Number of messages in receive queue. */
  29.  
  30. #if (STDCAN_TX_QUEUE_SIZE > 1)
  31. /**
  32.  * The transmit queue.
  33.  */
  34. StdCan_Msg_t TxQ[STDCAN_TX_QUEUE_SIZE];
  35. unsigned char TxQ_Rd_idx; /**< Transmit queue read index. */
  36. unsigned char TxQ_Wr_idx; /**< Transmit queue write index. */
  37. unsigned char TxQ_Len; /**< Number of messages in transmit queue. */
  38. #endif
  39.  
  40. /**
  41.  * CAN message callback.
  42.  * Callback for when a message is received from the lower
  43.  * layer (BIOS or CAN driver).
  44.  */
  45. void Can_Process(Can_Message_t* msg)
  46. {
  47.     unsigned char n;
  48.     /* Check if there is room on the queue. */
  49.     if (RxQ_Len < STDCAN_RX_QUEUE_SIZE) {
  50.         /* Copy the message from lower layer into the queue. */
  51.         RxQ[RxQ_Wr_idx].Id     = msg->Id;
  52.         RxQ[RxQ_Wr_idx].Length = msg->DataLength;
  53.         //TODO: This should be guarded against invalid DataLength.
  54.         for (n = 0; n < RxQ[RxQ_Wr_idx].Length; n++) {
  55.             RxQ[RxQ_Wr_idx].Data[n] = msg->Data.bytes[n];
  56.         }
  57.         /* Increment write index and queue length. */
  58.         if (++RxQ_Wr_idx >= STDCAN_RX_QUEUE_SIZE) RxQ_Wr_idx = 0;
  59.         RxQ_Len++;
  60.     } else {
  61.         /* Overflow, just drop the new message. In the future, some
  62.          * form of priority scheme could be used to drop another
  63.          * message in the queue.
  64.          */
  65.     }
  66. }
  67.  
  68. StdCan_Ret_t StdCan_Init(Node_Desc_t* node_desc)
  69. {
  70.     StdCan_Ret_t retval;
  71.    
  72.     /* Reset all queue variables. */
  73.     RxQ_Rd_idx = 0;
  74.     RxQ_Wr_idx = 0;
  75.     RxQ_Len    = 0;
  76.     TxQ_Rd_idx = 0;
  77.     TxQ_Wr_idx = 0;
  78.     TxQ_Len    = 0;
  79.    
  80. #if defined(_AVRLIB_BIOS_)
  81.     /* Initialize BIOS' interface for CAN. */
  82.     BIOS_CanCallback = Can_Process;
  83.     retval = StdCan_Ret_OK;
  84. #else
  85.     /* Initialize CAN driver. */
  86.     if (Can_Init() == CAN_OK)
  87.         retval = StdCan_Ret_OK;
  88.     else
  89.         retval = StdCan_Ret_Fail;
  90. #endif
  91.    
  92.     //TODO: Do something with the Node Descriptor.
  93.    
  94.     return retval;
  95. }
  96.  
  97. StdCan_Ret_t StdCan_Get(StdCan_Msg_t* msg)
  98. {
  99.     unsigned char n;
  100.    
  101.     /* Check if there's a message waiting. */
  102.     if (RxQ_Len) {
  103.        
  104.         /* Copy message to user buffer. */
  105.         msg->Id     = RxQ[RxQ_Rd_idx].Id;
  106.         msg->Length = RxQ[RxQ_Rd_idx].Length;
  107.         //TODO: Consider a mempcy() of the entire message.
  108.         for (n = 0; n < RxQ[RxQ_Rd_idx].Length; n++) {
  109.             msg->Data[n] = RxQ[RxQ_Rd_idx].Data[n];
  110.         }
  111.        
  112.         /* Increment read index and decrease queue length. */
  113.         if (++RxQ_Rd_idx >= STDCAN_RX_QUEUE_SIZE) RxQ_Rd_idx = 0;
  114.         RxQ_Len--;
  115.        
  116.         return StdCan_Ret_OK;
  117.     } else {
  118.         /* Queue is empty. */
  119.         return StdCan_Ret_Empty;
  120.     }
  121. }
  122.  
  123. StdCan_Ret_t StdCan_Put(StdCan_Msg_t* msg)
  124. {
  125.     Can_Message_t Can_Msg;
  126.     unsigned char n;
  127.    
  128.     /* Validate message. */
  129.     if ((unsigned)msg->Length > 8) return StdCan_Ret_DataErr;
  130.    
  131.     /* Copy message directly to lower layer until a proper
  132.      * queue has been implemented.
  133.      * TODO: Implement a proper queue. This requires TX interrupt
  134.      * support in the driver and BIOS.
  135.      */
  136.     Can_Msg.ExtendedFlag = 1;
  137.     Can_Msg.RemoteFlag = 0;
  138.     Can_Msg.Id = msg->Id;
  139.     Can_Msg.DataLength = msg->Length;
  140.     for (n = 0; n < msg->Length; n++) {
  141.         Can_Msg->Data.bytes[n] = msg->Data[n];
  142.     }
  143.    
  144.     if (Can_Send(&Can_Msg) == CAN_OK)
  145.         return StdCan_Ret_OK;
  146.     else
  147.         return StdCan_Ret_Full;
  148. }
  149.  
  150. void StdCan_SendHeartbeat(uint8_t n)
  151. {
  152.     /* TODO: When a Tx queue is implemented, the heartbeat should
  153.      * be sent via StdCan_Put instead of directly to lower layer.
  154.      */
  155.     Can_Message_t Heartbeat;
  156.    
  157.     /* Set up Heartbeat message format. */
  158.     Heartbeat.ExtendedFlag = 1;
  159.     Heartbeat.RemoteFlag = 0;
  160.     Heartbeat.DataLength = 0;
  161.     Heartbeat.Id = (CAN_NMT << CAN_SHIFT_CLASS)
  162.                  | (CAN_NMT_HEARTBEAT << CAN_SHIFT_NMT_TYPE)
  163.                  | (NODE_ID << CAN_SHIFT_NMT_SID);
  164.    
  165.     /* Try to send it. */
  166.     Can_Send(&Heartbeat);
  167. }
  168.