|
1 /****************************************************************************** |
|
2 * |
|
3 * m a i l b o x . c |
|
4 * |
|
5 * Mailbox-Funktionen |
|
6 * |
|
7 * $Id$ |
|
8 * |
|
9 *****************************************************************************/ |
|
10 |
|
11 #include <linux/slab.h> |
|
12 #include <linux/delay.h> |
|
13 |
|
14 #include "mailbox.h" |
|
15 #include "command.h" |
|
16 #include "master.h" |
|
17 |
|
18 /*****************************************************************************/ |
|
19 |
|
20 /** |
|
21 Bereitet ein Mailbox-Send-Kommando vor. |
|
22 */ |
|
23 |
|
24 uint8_t *ec_slave_mbox_prepare_send(ec_slave_t *slave, /**< Slave */ |
|
25 uint8_t type, /**< Mailbox-Protokoll */ |
|
26 size_t size /**< Datengröße */ |
|
27 ) |
|
28 { |
|
29 ec_command_t *command = &slave->mbox_command; |
|
30 size_t total_size; |
|
31 |
|
32 if (unlikely(!slave->sii_mailbox_protocols)) { |
|
33 EC_ERR("Slave %i does not support mailbox communication!\n", |
|
34 slave->ring_position); |
|
35 return NULL; |
|
36 } |
|
37 |
|
38 total_size = size + 6; |
|
39 if (unlikely(total_size > slave->sii_rx_mailbox_size)) { |
|
40 EC_ERR("Data size does not fit in mailbox!\n"); |
|
41 return NULL; |
|
42 } |
|
43 |
|
44 if (ec_command_npwr(command, slave->station_address, |
|
45 slave->sii_rx_mailbox_offset, |
|
46 slave->sii_rx_mailbox_size)) |
|
47 return NULL; |
|
48 |
|
49 EC_WRITE_U16(command->data, size); // Mailbox service data length |
|
50 EC_WRITE_U16(command->data + 2, slave->station_address); // Station address |
|
51 EC_WRITE_U8 (command->data + 4, 0x00); // Channel & priority |
|
52 EC_WRITE_U8 (command->data + 5, type); // Underlying protocol type |
|
53 |
|
54 return command->data + 6; |
|
55 } |
|
56 |
|
57 /*****************************************************************************/ |
|
58 |
|
59 /** |
|
60 Bereitet ein Kommando zum Abfragen des Mailbox-Zustandes vor. |
|
61 */ |
|
62 |
|
63 int ec_slave_mbox_prepare_check(ec_slave_t *slave /**< Slave */) |
|
64 { |
|
65 ec_command_t *command = &slave->mbox_command; |
|
66 |
|
67 // FIXME: Zweiter Sync-Manager nicht immer TX-Mailbox? |
|
68 if (ec_command_nprd(command, slave->station_address, 0x808, 8)) |
|
69 return -1; |
|
70 |
|
71 return 0; |
|
72 } |
|
73 |
|
74 /*****************************************************************************/ |
|
75 |
|
76 /** |
|
77 Liest den Mailbox-Zustand aus einem empfangenen Kommando. |
|
78 */ |
|
79 |
|
80 int ec_slave_mbox_check(const ec_slave_t *slave /**< Slave */) |
|
81 { |
|
82 return EC_READ_U8(slave->mbox_command.data + 5) & 8 ? 1 : 0; |
|
83 } |
|
84 |
|
85 /*****************************************************************************/ |
|
86 |
|
87 /** |
|
88 Bereitet ein Kommando zum Laden von Daten von der Mailbox vor. |
|
89 */ |
|
90 |
|
91 int ec_slave_mbox_prepare_fetch(ec_slave_t *slave /**< Slave */) |
|
92 { |
|
93 ec_command_t *command = &slave->mbox_command; |
|
94 |
|
95 if (ec_command_nprd(command, slave->station_address, |
|
96 slave->sii_tx_mailbox_offset, |
|
97 slave->sii_tx_mailbox_size)) return -1; |
|
98 return 0; |
|
99 } |
|
100 |
|
101 /*****************************************************************************/ |
|
102 |
|
103 /** |
|
104 Verarbeitet empfangene Mailbox-Daten. |
|
105 */ |
|
106 |
|
107 uint8_t *ec_slave_mbox_fetch(ec_slave_t *slave, /**< Slave */ |
|
108 uint8_t type, /**< Protokoll */ |
|
109 size_t *size /**< Größe der empfangenen |
|
110 Daten */ |
|
111 ) |
|
112 { |
|
113 ec_command_t *command = &slave->mbox_command; |
|
114 size_t data_size; |
|
115 |
|
116 if ((EC_READ_U8(command->data + 5) & 0x0F) != type) { |
|
117 EC_ERR("Unexpected mailbox protocol 0x%02X (exp.: 0x%02X) at" |
|
118 " slave %i!\n", EC_READ_U8(command->data + 5), type, |
|
119 slave->ring_position); |
|
120 return NULL; |
|
121 } |
|
122 |
|
123 if ((data_size = EC_READ_U16(command->data)) > |
|
124 slave->sii_tx_mailbox_size - 6) { |
|
125 EC_ERR("Currupt mailbox response detected!\n"); |
|
126 return NULL; |
|
127 } |
|
128 |
|
129 *size = data_size; |
|
130 return command->data + 6; |
|
131 } |
|
132 |
|
133 /*****************************************************************************/ |
|
134 |
|
135 /** |
|
136 Sendet und wartet auf den Empfang eines Mailbox-Kommandos. |
|
137 */ |
|
138 |
|
139 uint8_t *ec_slave_mbox_simple_io(ec_slave_t *slave, /**< Slave */ |
|
140 size_t *size /**< Größe der gelesenen |
|
141 Daten */ |
|
142 ) |
|
143 { |
|
144 uint8_t type; |
|
145 ec_command_t *command; |
|
146 |
|
147 command = &slave->mbox_command; |
|
148 type = EC_READ_U8(command->data + 5); |
|
149 |
|
150 if (unlikely(ec_master_simple_io(slave->master, command))) { |
|
151 EC_ERR("Mailbox checking failed on slave %i!\n", |
|
152 slave->ring_position); |
|
153 return NULL; |
|
154 } |
|
155 |
|
156 return ec_slave_mbox_simple_receive(slave, type, size); |
|
157 } |
|
158 |
|
159 /*****************************************************************************/ |
|
160 |
|
161 /** |
|
162 Wartet auf den Empfang eines Mailbox-Kommandos. |
|
163 */ |
|
164 |
|
165 uint8_t *ec_slave_mbox_simple_receive(ec_slave_t *slave, /**< Slave */ |
|
166 uint8_t type, /**< Protokoll */ |
|
167 size_t *size /**< Größe der gelesenen |
|
168 Daten */ |
|
169 ) |
|
170 { |
|
171 cycles_t start, end, timeout; |
|
172 ec_command_t *command; |
|
173 |
|
174 command = &slave->mbox_command; |
|
175 start = get_cycles(); |
|
176 timeout = (cycles_t) 100 * cpu_khz; // 100ms |
|
177 |
|
178 while (1) |
|
179 { |
|
180 if (ec_slave_mbox_prepare_check(slave)) return NULL; |
|
181 if (unlikely(ec_master_simple_io(slave->master, command))) { |
|
182 EC_ERR("Mailbox checking failed on slave %i!\n", |
|
183 slave->ring_position); |
|
184 return NULL; |
|
185 } |
|
186 |
|
187 end = get_cycles(); |
|
188 |
|
189 if (ec_slave_mbox_check(slave)) |
|
190 break; // Proceed with receiving data |
|
191 |
|
192 if ((end - start) >= timeout) { |
|
193 EC_ERR("Mailbox check - Slave %i timed out.\n", |
|
194 slave->ring_position); |
|
195 return NULL; |
|
196 } |
|
197 |
|
198 udelay(100); |
|
199 } |
|
200 |
|
201 if (ec_slave_mbox_prepare_fetch(slave)) return NULL; |
|
202 if (unlikely(ec_master_simple_io(slave->master, command))) { |
|
203 EC_ERR("Mailbox receiving failed on slave %i!\n", |
|
204 slave->ring_position); |
|
205 return NULL; |
|
206 } |
|
207 |
|
208 if (unlikely(slave->master->debug_level) > 1) |
|
209 EC_DBG("Mailbox receive took %ius.\n", ((u32) (end - start) * 1000 |
|
210 / cpu_khz)); |
|
211 |
|
212 return ec_slave_mbox_fetch(slave, type, size); |
|
213 } |
|
214 |
|
215 /*****************************************************************************/ |
|
216 |
|
217 #if 0 |
|
218 /** |
|
219 Sendet ein Mailbox-Kommando. |
|
220 */ |
|
221 |
|
222 int ec_slave_mbox_send(ec_slave_t *slave, /**< EtherCAT-Slave */ |
|
223 uint8_t type, /**< Unterliegendes Protokoll */ |
|
224 const uint8_t *prot_data, /**< Protokoll-Daten */ |
|
225 size_t size /**< Datengröße */ |
|
226 ) |
|
227 { |
|
228 uint8_t *data; |
|
229 ec_command_t command; |
|
230 |
|
231 |
|
232 } |
|
233 |
|
234 if (!(data = kmalloc(slave->sii_rx_mailbox_size, GFP_KERNEL))) { |
|
235 EC_ERR("Failed to allocate %i bytes of memory for mailbox data!\n", |
|
236 slave->sii_rx_mailbox_size); |
|
237 return -1; |
|
238 } |
|
239 |
|
240 memset(data, 0x00, slave->sii_rx_mailbox_size); |
|
241 EC_WRITE_U16(data, size); // Length of the Mailbox service data |
|
242 EC_WRITE_U16(data + 2, slave->station_address); // Station address |
|
243 EC_WRITE_U8 (data + 4, 0x00); // Channel & priority |
|
244 EC_WRITE_U8 (data + 5, type); // Underlying protocol type |
|
245 memcpy(data + 6, prot_data, size); |
|
246 |
|
247 ec_command_init_npwr(&command, slave->station_address, |
|
248 slave->sii_rx_mailbox_offset, |
|
249 slave->sii_rx_mailbox_size, data); |
|
250 if (unlikely(ec_master_simple_io(slave->master, &command))) { |
|
251 EC_ERR("Mailbox sending failed on slave %i!\n", slave->ring_position); |
|
252 kfree(data); |
|
253 return -1; |
|
254 } |
|
255 |
|
256 kfree(data); |
|
257 return 0; |
|
258 } |
|
259 |
|
260 /*****************************************************************************/ |
|
261 |
|
262 /** |
|
263 Sendet ein Mailbox-Kommando. |
|
264 */ |
|
265 |
|
266 int ec_slave_mailbox_receive(ec_slave_t *slave, /**< EtherCAT-Slave */ |
|
267 uint8_t type, /**< Unterliegendes Protokoll */ |
|
268 uint8_t *prot_data, /**< Protokoll-Daten */ |
|
269 size_t *size /**< Datengröße des Puffers, später |
|
270 Größe der gelesenen Daten */ |
|
271 ) |
|
272 { |
|
273 ec_command_t command; |
|
274 size_t data_size; |
|
275 cycles_t start, end, timeout; |
|
276 |
|
277 // Read "written bit" of Sync-Manager |
|
278 start = get_cycles(); |
|
279 timeout = (cycles_t) 100 * cpu_khz; // 100ms |
|
280 |
|
281 while (1) |
|
282 { |
|
283 // FIXME: Zweiter Sync-Manager nicht immer TX-Mailbox? |
|
284 ec_command_init_nprd(&command, slave->station_address, 0x808, 8); |
|
285 if (unlikely(ec_master_simple_io(slave->master, &command))) { |
|
286 EC_ERR("Mailbox checking failed on slave %i!\n", |
|
287 slave->ring_position); |
|
288 return -1; |
|
289 } |
|
290 |
|
291 end = get_cycles(); |
|
292 |
|
293 if (EC_READ_U8(command.data + 5) & 8) |
|
294 break; // Proceed with received data |
|
295 |
|
296 if ((end - start) >= timeout) { |
|
297 EC_ERR("Mailbox check - Slave %i timed out.\n", |
|
298 slave->ring_position); |
|
299 return -1; |
|
300 } |
|
301 |
|
302 udelay(100); |
|
303 } |
|
304 |
|
305 ec_command_init_nprd(&command, slave->station_address, |
|
306 slave->sii_tx_mailbox_offset, |
|
307 slave->sii_tx_mailbox_size); |
|
308 if (unlikely(ec_master_simple_io(slave->master, &command))) { |
|
309 EC_ERR("Mailbox receiving failed on slave %i!\n", |
|
310 slave->ring_position); |
|
311 return -1; |
|
312 } |
|
313 |
|
314 if ((EC_READ_U8(command.data + 5) & 0x0F) != type) { |
|
315 EC_ERR("Unexpected mailbox protocol 0x%02X (exp.: 0x%02X) at" |
|
316 " slave %i!\n", EC_READ_U8(command.data + 5), type, |
|
317 slave->ring_position); |
|
318 return -1; |
|
319 } |
|
320 |
|
321 if (unlikely(slave->master->debug_level) > 1) |
|
322 EC_DBG("Mailbox receive took %ius.\n", ((u32) (end - start) * 1000 |
|
323 / cpu_khz)); |
|
324 |
|
325 if ((data_size = EC_READ_U16(command.data)) > *size) { |
|
326 EC_ERR("Mailbox service data does not fit into buffer (%i > %i).\n", |
|
327 data_size, *size); |
|
328 return -1; |
|
329 } |
|
330 |
|
331 if (data_size > slave->sii_tx_mailbox_size - 6) { |
|
332 EC_ERR("Currupt mailbox response detected!\n"); |
|
333 return -1; |
|
334 } |
|
335 |
|
336 memcpy(prot_data, command.data + 6, data_size); |
|
337 *size = data_size; |
|
338 return 0; |
|
339 } |
|
340 |
|
341 /*****************************************************************************/ |
|
342 |
|
343 uint8_t *ec_slave_init_mbox_send_cmd(ec_slave_t *slave, /**< EtherCAT-Slave */ |
|
344 ec_command_t *command, /**< Kommando */ |
|
345 uint8_t type, /**< Protokolltyp */ |
|
346 size_t size /**< Datengröße */ |
|
347 ) |
|
348 { |
|
349 size_t total_size; |
|
350 uint8_t *data; |
|
351 |
|
352 if (unlikely(!slave->sii_mailbox_protocols)) { |
|
353 EC_ERR("Slave %i does not support mailbox communication!\n", |
|
354 slave->ring_position); |
|
355 return NULL; |
|
356 } |
|
357 |
|
358 total_size = size + 6; |
|
359 if (unlikely(total_size > slave->sii_rx_mailbox_size)) { |
|
360 EC_ERR("Data size does not fit into mailbox of slave %i!\n", |
|
361 slave->ring_position); |
|
362 return NULL; |
|
363 } |
|
364 |
|
365 data = command->data; |
|
366 |
|
367 memset(data, 0x00, slave->sii_rx_mailbox_size); |
|
368 EC_WRITE_U16(data, size); // Length of the Mailbox service data |
|
369 EC_WRITE_U16(data + 2, slave->station_address); // Station address |
|
370 EC_WRITE_U8 (data + 4, 0x00); // Channel & priority |
|
371 EC_WRITE_U8 (data + 5, type); // Underlying protocol type |
|
372 |
|
373 return data + 6; |
|
374 } |
|
375 #endif |
|
376 |
|
377 /*****************************************************************************/ |