Rev 1909 | Rev 2136 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed
| Rev 1909 | Rev 2029 | ||
|---|---|---|---|
| Line 1... | Line -... | ||
| 1 | - | ||
| 2 | #include "stdcan.h" |
1 | #include "stdcan.h" |
| 3 | #if defined(_AVRLIB_BIOS_) |
2 | #if defined(_AVRLIB_BIOS_) |
| 4 | #include <bios.h> |
3 | #include <bios.h> |
| 5 | #define Can_Send BIOS_CanSend |
4 | #define Can_Send BIOS_CanSend |
| 6 | #else |
5 | #else |
| 7 | #include <drivers/can/mcp2515/mcp2515.h> |
6 | #include <drivers/can/mcp2515/mcp2515.h> |
| 8 | #endif |
7 | #endif |
| 9 | 8 | ||
| 10 | #include <avr/interrupt.h> |
9 | #include <avr/interrupt.h> |
| - | 10 | #include <util/atomic.h> |
|
| 11 | 11 | ||
| 12 | #if (STDCAN_TX_QUEUE_SIZE > 1) |
12 | #if (STDCAN_TX_QUEUE_SIZE > 1) |
| 13 | #error StdCan: Tx queue size longer than one msg not yet implemented. |
13 | #error StdCan: Tx queue size longer than one msg not yet implemented. |
| 14 | #endif |
14 | #endif |
| 15 | 15 | ||
| 16 | /** |
16 | /** |
| 17 | * The receive queue. |
17 | * The receive queue. |
| 18 | */ |
18 | */ |
| 19 | StdCan_Msg_t RxQ[STDCAN_RX_QUEUE_SIZE]; |
19 | StdCan_Msg_t RxQ[STDCAN_RX_QUEUE_SIZE + 1]; |
| 20 | unsigned char RxQ_Rd_idx; /**< Receive queue read index. */ |
20 | unsigned char RxQ_Rd_idx; /**< Receive queue read index. */ |
| 21 | unsigned char RxQ_Wr_idx; /**< Receive queue write index. */ |
21 | unsigned char RxQ_Wr_idx; /**< Receive queue write index. */ |
| 22 | unsigned char RxQ_Len; /**< Number of messages in receive queue. */ |
- | |
| 23 | 22 | ||
| 24 | #if (STDCAN_TX_QUEUE_SIZE > 1) |
23 | #if (STDCAN_TX_QUEUE_SIZE > 1) |
| 25 | /** |
24 | /** |
| 26 | * The transmit queue. |
25 | * The transmit queue. |
| 27 | */ |
26 | */ |
| 28 | StdCan_Msg_t TxQ[STDCAN_TX_QUEUE_SIZE]; |
27 | StdCan_Msg_t TxQ[STDCAN_TX_QUEUE_SIZE]; |
| 29 | unsigned char TxQ_Rd_idx; /**< Transmit queue read index. */ |
28 | unsigned char TxQ_Rd_idx; /**< Transmit queue read index. */ |
| 30 | unsigned char TxQ_Wr_idx; /**< Transmit queue write index. */ |
29 | unsigned char TxQ_Wr_idx; /**< Transmit queue write index. */ |
| 31 | unsigned char TxQ_Len; /**< Number of messages in transmit queue. */ |
- | |
| 32 | #endif |
30 | #endif |
| 33 | 31 | ||
| 34 | #if (STDCAN_FILTER) |
32 | #if (STDCAN_FILTER) |
| 35 | /** |
33 | /** |
| 36 | * The message acceptance filters. |
34 | * The message acceptance filters. |
| Line 38... | Line 36... | ||
| 38 | typedef struct { |
36 | typedef struct { |
| 39 | char Active; /**< True if this filter should be used. */ |
37 | 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. */ |
38 | 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). */ |
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). */ |
| 42 | } StdCan_Filter_t; |
40 | } StdCan_Filter_t; |
| 43 | 41 | ||
| 44 | StdCan_Filter_t RxFilters[STDCAN_NUM_FILTERS]; |
42 | StdCan_Filter_t RxFilters[STDCAN_NUM_FILTERS]; |
| 45 | #endif |
43 | #endif |
| 46 | 44 | ||
| 47 | /** |
45 | /** |
| 48 | * CAN message callback. |
46 | * CAN message callback. |
| 49 | * Callback for when a message is received from the lower |
47 | * Callback for when a message is received from the lower |
| 50 | * layer (BIOS or CAN driver). |
48 | * layer (BIOS or CAN driver). |
| 51 | */ |
49 | */ |
| 52 | void Can_Process(Can_Message_t* msg) |
50 | void Can_Process(Can_Message_t* msg) |
| 53 | { |
51 | { |
| 54 |
|
52 | /* What will the next write index be if the push goes well? */ |
| 55 |
|
53 | unsigned char Wr_next = RxQ_Wr_idx + 1; |
| 56 | if ( |
54 | if (Wr_next >= STDCAN_RX_QUEUE_SIZE + 1) Wr_next = 0; |
| 57 | 55 | ||
| - | 56 | /* Check if there is room on the queue. */ |
|
| - | 57 | if (Wr_next != RxQ_Rd_idx) { |
|
| - | 58 | unsigned char n; |
|
| 58 | #if (STDCAN_FILTER) |
59 | #if (STDCAN_FILTER) |
| 59 | /* Try to match each filter in turn. */ |
60 | /* Try to match each filter in turn. */ |
| 60 | for (n = 0; n < STDCAN_NUM_FILTERS; n++) { |
61 | for (n = 0; n < STDCAN_NUM_FILTERS; n++) { |
| 61 | if (RxFilters[n].Active && !((msg->Id ^ RxFilters[n].Id) & RxFilters[n].Mask)) { |
62 | if (RxFilters[n].Active && !((msg->Id ^ RxFilters[n].Id) & RxFilters[n].Mask)) { |
| 62 | RxQ[RxQ_Wr_idx].Match = n; |
63 | RxQ[RxQ_Wr_idx].Match = n; |
| 63 | break; |
64 | break; |
| 64 | } |
65 | } |
| 65 | } |
66 | } |
| 66 | 67 | ||
| 67 | if (n == STDCAN_NUM_FILTERS) return; // No match found, discard message. |
68 | if (n == STDCAN_NUM_FILTERS) return; // No match found, discard message. |
| 68 | #endif |
69 | #endif |
| 69 | /* Copy the message from lower layer into the queue. */ |
70 | /* Copy the message from lower layer into the queue. */ |
| 70 | RxQ[RxQ_Wr_idx].Id = msg->Id; |
71 | RxQ[RxQ_Wr_idx].Id = msg->Id; |
| 71 | RxQ[RxQ_Wr_idx].Length = msg->DataLength; |
72 | RxQ[RxQ_Wr_idx].Length = msg->DataLength; |
| 72 | //TODO: This should be guarded against invalid DataLength. |
73 | //TODO: This should be guarded against invalid DataLength. |
| 73 | for (n = 0; n < RxQ[RxQ_Wr_idx].Length; n++) { |
74 | for (n = 0; n < RxQ[RxQ_Wr_idx].Length; n++) { |
| 74 | RxQ[RxQ_Wr_idx].Data[n] = msg->Data.bytes[n]; |
75 | RxQ[RxQ_Wr_idx].Data[n] = msg->Data.bytes[n]; |
| 75 | } |
76 | } |
| 76 | /* |
77 | /* Update write index. */ |
| 77 | if (++RxQ_Wr_idx >= STDCAN_RX_QUEUE_SIZE) RxQ_Wr_idx = 0; |
- | |
| 78 |
|
78 | RxQ_Wr_idx = Wr_next; |
| 79 | } else { |
79 | } else { |
| 80 | /* Overflow, just drop the new message. In the future, some |
80 | /* Overflow, just drop the new message. In the future, some |
| 81 | * form of priority scheme could be used to drop another |
81 | * form of priority scheme could be used to drop another |
| 82 | * message in the queue. |
82 | * message in the queue. |
| 83 | */ |
83 | */ |
| 84 | } |
84 | } |
| 85 | } |
85 | } |
| 86 | 86 | ||
| 87 | #ifdef MODULE_APPLICATION |
87 | #ifdef MODULE_APPLICATION |
| 88 | StdCan_Ret_t StdCan_Init(void) |
88 | StdCan_Ret_t StdCan_Init(void) |
| 89 | { |
89 | { |
| 90 | #else |
90 | #else |
| 91 | StdCan_Ret_t StdCan_Init(Node_Desc_t* node_desc) |
91 | StdCan_Ret_t StdCan_Init(Node_Desc_t* node_desc) |
| Line 94... | Line 94... | ||
| 94 | StdCan_Ret_t retval; |
94 | StdCan_Ret_t retval; |
| 95 | 95 | ||
| 96 | /* Reset all queue variables. */ |
96 | /* Reset all queue variables. */ |
| 97 | RxQ_Rd_idx = 0; |
97 | RxQ_Rd_idx = 0; |
| 98 | RxQ_Wr_idx = 0; |
98 | RxQ_Wr_idx = 0; |
| 99 | RxQ_Len = 0; |
- | |
| 100 | #if (STDCAN_TX_QUEUE_SIZE > 1) |
99 | #if (STDCAN_TX_QUEUE_SIZE > 1) |
| 101 | TxQ_Rd_idx = 0; |
100 | TxQ_Rd_idx = 0; |
| 102 | TxQ_Wr_idx = 0; |
101 | TxQ_Wr_idx = 0; |
| 103 | TxQ_Len = 0; |
- | |
| 104 | #endif |
102 | #endif |
| 105 | 103 | ||
| 106 | #if defined(_AVRLIB_BIOS_) |
104 | #if defined(_AVRLIB_BIOS_) |
| 107 | /* Initialize BIOS' interface for CAN. */ |
105 | /* Initialize BIOS' interface for CAN. */ |
| 108 | BIOS_CanCallback = Can_Process; |
106 | BIOS_CanCallback = Can_Process; |
| Line 143... | Line 141... | ||
| 143 | /* Try to send it. */ |
141 | /* Try to send it. */ |
| 144 | Can_Send(&Startup); |
142 | Can_Send(&Startup); |
| 145 | #endif |
143 | #endif |
| 146 | 144 | ||
| 147 | return retval; |
145 | return retval; |
| 148 | } |
146 | } |
| 149 | 147 | ||
| 150 | StdCan_Ret_t StdCan_Get(StdCan_Msg_t* msg) |
148 | StdCan_Ret_t StdCan_Get(StdCan_Msg_t* msg) |
| 151 | { |
149 | { |
| - | 150 | unsigned char Wr_idx; |
|
| 152 | unsigned char |
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; |
|
| 153 |
|
157 | } |
| - | 158 | ||
| 154 | /* Check if there's a message waiting. */ |
159 | /* Check if there's a message waiting. */ |
| 155 | if ( |
160 | if (Rd_idx != Wr_idx) { |
| - | 161 | unsigned char n; |
|
| 156 | 162 | ||
| 157 | /* Copy message to user buffer. */ |
163 | /* Copy message to user buffer. */ |
| 158 | msg->Id = RxQ[ |
164 | msg->Id = RxQ[Rd_idx].Id; |
| 159 | msg->Length = RxQ[ |
165 | msg->Length = RxQ[Rd_idx].Length; |
| 160 | //TODO: Consider a mempcy() of the entire message. |
166 | //TODO: Consider a mempcy() of the entire message. |
| 161 | for (n = 0; n < RxQ[ |
167 | for (n = 0; n < RxQ[Rd_idx].Length; n++) { |
| 162 | msg->Data[n] = RxQ[ |
168 | msg->Data[n] = RxQ[Rd_idx].Data[n]; |
| 163 | } |
169 | } |
| 164 | 170 | ||
| 165 | /* |
171 | /* Update read index and store back atomically. */ |
| 166 | if (++ |
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; |
|
| 167 |
|
175 | } |
| 168 | 176 | ||
| 169 | sei(); |
- | |
| 170 | return StdCan_Ret_OK; |
177 | return StdCan_Ret_OK; |
| 171 | } else { |
178 | } else { |
| 172 | /* Queue is empty. */ |
179 | /* Queue is empty. */ |
| 173 | sei(); |
- | |
| 174 | return StdCan_Ret_Empty; |
180 | return StdCan_Ret_Empty; |
| 175 | } |
181 | } |
| 176 | } |
- | |
| 177 | - | ||
| 178 | unsigned char StdCan_Get_Pending(void) |
- | |
| 179 | { |
- | |
| 180 | return RxQ_Len; |
- | |
| 181 | } |
182 | } |
| 182 | 183 | ||
| 183 | StdCan_Ret_t StdCan_Put(StdCan_Msg_t* msg) |
184 | StdCan_Ret_t StdCan_Put(StdCan_Msg_t* msg) |
| 184 | { |
185 | { |
| 185 | Can_Message_t Can_Msg; |
186 | Can_Message_t Can_Msg; |