137 } |
150 } |
138 } |
151 } |
139 |
152 |
140 if (!domain->data_size) { |
153 if (!domain->data_size) { |
141 EC_WARN("Domain 0x%08X contains no data!\n", (u32) domain); |
154 EC_WARN("Domain 0x%08X contains no data!\n", (u32) domain); |
142 } |
155 ec_domain_clear_field_regs(domain); |
143 else { |
156 return 0; |
144 // Prozessdaten allozieren |
157 } |
145 if (!(domain->data = kmalloc(domain->data_size, GFP_KERNEL))) { |
158 |
146 EC_ERR("Failed to allocate domain data!\n"); |
159 // Prozessdaten allozieren |
|
160 if (!(domain->data = kmalloc(domain->data_size, GFP_KERNEL))) { |
|
161 EC_ERR("Failed to allocate domain data!\n"); |
|
162 return -1; |
|
163 } |
|
164 |
|
165 // Prozessdaten mit Nullen vorbelegen |
|
166 memset(domain->data, 0x00, domain->data_size); |
|
167 |
|
168 // Alle Prozessdatenzeiger setzen |
|
169 list_for_each_entry(field_reg, &domain->field_regs, list) { |
|
170 found = 0; |
|
171 for (i = 0; i < field_reg->slave->fmmu_count; i++) { |
|
172 fmmu = &field_reg->slave->fmmus[i]; |
|
173 if (fmmu->domain == domain && fmmu->sync == field_reg->sync) { |
|
174 data_offset = fmmu->logical_start_address - base_address |
|
175 + field_reg->field_offset; |
|
176 *field_reg->data_ptr = domain->data + data_offset; |
|
177 found = 1; |
|
178 break; |
|
179 } |
|
180 } |
|
181 |
|
182 if (!found) { // Sollte nie passieren |
|
183 EC_ERR("FMMU not found. Please report!\n"); |
147 return -1; |
184 return -1; |
148 } |
185 } |
149 |
186 } |
150 // Prozessdaten mit Nullen vorbelegen |
187 |
151 memset(domain->data, 0x00, domain->data_size); |
188 // Kommando-Array erzeugen |
152 |
189 domain->command_count = domain->data_size / EC_MAX_DATA_SIZE + 1; |
153 // Alle Prozessdatenzeiger setzen |
190 if (!(domain->commands = (ec_command_t *) kmalloc(sizeof(ec_command_t) |
154 list_for_each_entry(field_reg, &domain->field_regs, list) { |
191 * domain->command_count, |
155 found = 0; |
192 GFP_KERNEL))) { |
156 for (i = 0; i < field_reg->slave->fmmu_count; i++) { |
193 EC_ERR("Failed to allocate domain command array!\n"); |
157 fmmu = &field_reg->slave->fmmus[i]; |
194 return -1; |
158 if (fmmu->domain == domain && fmmu->sync == field_reg->sync) { |
195 } |
159 data_offset = fmmu->logical_start_address - base_address |
196 |
160 + field_reg->field_offset; |
197 EC_INFO("Domain %X - Allocated %i bytes in %i command(s)\n", |
161 *field_reg->data_ptr = domain->data + data_offset; |
198 (u32) domain, domain->data_size, domain->command_count); |
162 found = 1; |
199 |
163 break; |
200 ec_domain_clear_field_regs(domain); |
164 } |
|
165 } |
|
166 |
|
167 if (!found) { // Sollte nie passieren |
|
168 EC_ERR("FMMU not found. Please report!\n"); |
|
169 return -1; |
|
170 } |
|
171 } |
|
172 } |
|
173 |
|
174 // Registrierungsliste wird jetzt nicht mehr gebraucht. |
|
175 list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) { |
|
176 kfree(field_reg); |
|
177 } |
|
178 INIT_LIST_HEAD(&domain->field_regs); // wichtig! |
|
179 |
201 |
180 return 0; |
202 return 0; |
181 } |
203 } |
182 |
204 |
183 /*****************************************************************************/ |
205 /*****************************************************************************/ |
207 Registriert ein Datenfeld innerhalb einer Domäne. |
229 Registriert ein Datenfeld innerhalb einer Domäne. |
208 |
230 |
209 \return Zeiger auf den Slave bei Erfolg, sonst NULL |
231 \return Zeiger auf den Slave bei Erfolg, sonst NULL |
210 */ |
232 */ |
211 |
233 |
212 ec_slave_t *EtherCAT_rt_register_slave_field( |
234 ec_slave_t *EtherCAT_rt_register_slave_field(ec_domain_t *domain, |
213 ec_domain_t *domain, /**< Domäne */ |
235 /**< Domäne */ |
214 const char *address, /**< ASCII-Addresse des Slaves, siehe ec_address() */ |
236 const char *address, |
215 const char *vendor_name, /**< Herstellername */ |
237 /**< ASCII-Addresse des Slaves, |
216 const char *product_name, /**< Produktname */ |
238 siehe ec_master_slave_address() |
217 void **data_ptr, /**< Adresse des Zeigers auf die Prozessdaten */ |
239 */ |
218 ec_field_type_t field_type, /**< Typ des Datenfeldes */ |
240 const char *vendor_name, |
219 unsigned int field_index, /**< Gibt an, ab welchem Feld mit Typ |
241 /**< Herstellername */ |
220 \a field_type gezählt werden soll. */ |
242 const char *product_name, |
221 unsigned int field_count /**< Anzahl Felder des selben Typs */ |
243 /**< Produktname */ |
222 ) |
244 void **data_ptr, |
|
245 /**< Adresse des Zeigers auf die |
|
246 Prozessdaten */ |
|
247 ec_field_type_t field_type, |
|
248 /**< Typ des Datenfeldes */ |
|
249 unsigned int field_index, |
|
250 /**< Gibt an, ab welchem Feld mit |
|
251 Typ \a field_type gezählt |
|
252 werden soll. */ |
|
253 unsigned int field_count |
|
254 /**< Anzahl Felder selben Typs */ |
|
255 ) |
223 { |
256 { |
224 ec_slave_t *slave; |
257 ec_slave_t *slave; |
225 const ec_slave_type_t *type; |
258 const ec_slave_type_t *type; |
226 ec_master_t *master; |
259 ec_master_t *master; |
227 const ec_sync_t *sync; |
260 const ec_sync_t *sync; |
278 } |
311 } |
279 |
312 |
280 /*****************************************************************************/ |
313 /*****************************************************************************/ |
281 |
314 |
282 /** |
315 /** |
283 Sendet und empfängt Prozessdaten der angegebenen Domäne. |
316 Registriert eine ganze Liste von Datenfeldern innerhalb einer Domäne. |
|
317 |
|
318 Achtung: Die Liste muss mit einer NULL-Struktur ({}) abgeschlossen sein! |
284 |
319 |
285 \return 0 bei Erfolg, sonst < 0 |
320 \return 0 bei Erfolg, sonst < 0 |
286 */ |
321 */ |
287 |
322 |
288 int EtherCAT_rt_domain_xio(ec_domain_t *domain /**< Domäne */) |
323 int EtherCAT_rt_register_domain_fields(ec_domain_t *domain, |
289 { |
324 /**< Domäne */ |
290 unsigned int offset, size, working_counter_sum; |
325 ec_field_init_t *fields |
291 unsigned long start_ticks, end_ticks, timeout_ticks; |
326 /**< Array mit Datenfeldern */ |
292 ec_master_t *master; |
327 ) |
293 ec_frame_t *frame; |
328 { |
294 |
329 ec_field_init_t *field; |
295 master = domain->master; |
330 |
296 frame = &domain->frame; |
331 for (field = fields; field->data; field++) { |
297 working_counter_sum = 0; |
332 if (!EtherCAT_rt_register_slave_field(domain, field->address, |
298 |
333 field->vendor, field->product, |
299 ec_cyclic_output(master); |
334 field->data, field->field_type, |
300 |
335 field->field_index, |
301 if (unlikely(!master->device.link_state)) { |
336 field->field_count)) { |
302 ec_domain_response_count(domain, working_counter_sum); |
337 return -1; |
303 ec_device_call_isr(&master->device); |
338 } |
304 return -1; |
339 } |
305 } |
340 |
306 |
341 return 0; |
307 rdtscl(start_ticks); // Sendezeit nehmen |
342 } |
308 timeout_ticks = domain->timeout_us * cpu_khz / 1000; |
343 |
|
344 /*****************************************************************************/ |
|
345 |
|
346 /** |
|
347 Setzt Prozessdaten-Kommandos in die Warteschlange des Masters. |
|
348 */ |
|
349 |
|
350 void EtherCAT_rt_domain_queue(ec_domain_t *domain /**< Domäne */) |
|
351 { |
|
352 unsigned int offset, i; |
|
353 size_t size; |
309 |
354 |
310 offset = 0; |
355 offset = 0; |
311 while (offset < domain->data_size) |
356 for (i = 0; i < domain->command_count; i++) { |
312 { |
|
313 size = domain->data_size - offset; |
357 size = domain->data_size - offset; |
314 if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE; |
358 if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE; |
315 |
359 ec_command_init_lrw(domain->commands + i, |
316 ec_frame_init_lrw(frame, master, domain->base_address + offset, size, |
360 domain->base_address + offset, size, |
317 domain->data + offset); |
361 domain->data + offset); |
318 |
362 ec_master_queue_command(domain->master, domain->commands + i); |
319 if (unlikely(ec_frame_send(frame) < 0)) { |
|
320 master->device.state = EC_DEVICE_STATE_READY; |
|
321 master->frames_lost++; |
|
322 ec_cyclic_output(master); |
|
323 ec_domain_response_count(domain, working_counter_sum); |
|
324 return -1; |
|
325 } |
|
326 |
|
327 // Warten |
|
328 do { |
|
329 ec_device_call_isr(&master->device); |
|
330 rdtscl(end_ticks); // Empfangszeit nehmen |
|
331 } |
|
332 while (unlikely(master->device.state == EC_DEVICE_STATE_SENT |
|
333 && end_ticks - start_ticks < timeout_ticks)); |
|
334 |
|
335 master->bus_time = (end_ticks - start_ticks) * 1000 / cpu_khz; |
|
336 |
|
337 if (unlikely(end_ticks - start_ticks >= timeout_ticks)) { |
|
338 if (master->device.state == EC_DEVICE_STATE_RECEIVED) { |
|
339 master->frames_delayed++; |
|
340 ec_cyclic_output(master); |
|
341 } |
|
342 else { |
|
343 master->device.state = EC_DEVICE_STATE_READY; |
|
344 master->frames_lost++; |
|
345 ec_cyclic_output(master); |
|
346 ec_domain_response_count(domain, working_counter_sum); |
|
347 return -1; |
|
348 } |
|
349 } |
|
350 |
|
351 if (unlikely(ec_frame_receive(frame) < 0)) { |
|
352 ec_domain_response_count(domain, working_counter_sum); |
|
353 return -1; |
|
354 } |
|
355 |
|
356 working_counter_sum += frame->working_counter; |
|
357 |
|
358 // Daten vom Rahmen in den Prozessdatenspeicher kopieren |
|
359 memcpy(domain->data + offset, frame->data, size); |
|
360 |
|
361 offset += size; |
363 offset += size; |
362 } |
364 } |
|
365 } |
|
366 |
|
367 /*****************************************************************************/ |
|
368 |
|
369 /** |
|
370 Verarbeitet empfangene Prozessdaten. |
|
371 */ |
|
372 |
|
373 void EtherCAT_rt_domain_process(ec_domain_t *domain /**< Domäne */) |
|
374 { |
|
375 unsigned int offset, working_counter_sum, i; |
|
376 ec_command_t *command; |
|
377 size_t size; |
|
378 |
|
379 working_counter_sum = 0; |
|
380 |
|
381 offset = 0; |
|
382 for (i = 0; i < domain->command_count; i++) { |
|
383 command = domain->commands + i; |
|
384 size = domain->data_size - offset; |
|
385 if (size > EC_MAX_DATA_SIZE) size = EC_MAX_DATA_SIZE; |
|
386 if (command->state == EC_CMD_RECEIVED) { |
|
387 // Daten vom Kommando- in den Prozessdatenspeicher kopieren |
|
388 memcpy(domain->data + offset, command->data, size); |
|
389 working_counter_sum += command->working_counter; |
|
390 } |
|
391 else if (unlikely(domain->master->debug_level)) { |
|
392 EC_DBG("process data command not received!\n"); |
|
393 } |
|
394 offset += size; |
|
395 } |
363 |
396 |
364 ec_domain_response_count(domain, working_counter_sum); |
397 ec_domain_response_count(domain, working_counter_sum); |
365 |
|
366 return 0; |
|
367 } |
398 } |
368 |
399 |
369 /*****************************************************************************/ |
400 /*****************************************************************************/ |
370 |
401 |
371 EXPORT_SYMBOL(EtherCAT_rt_register_slave_field); |
402 EXPORT_SYMBOL(EtherCAT_rt_register_slave_field); |
372 EXPORT_SYMBOL(EtherCAT_rt_domain_xio); |
403 EXPORT_SYMBOL(EtherCAT_rt_register_domain_fields); |
|
404 EXPORT_SYMBOL(EtherCAT_rt_domain_queue); |
|
405 EXPORT_SYMBOL(EtherCAT_rt_domain_process); |
373 |
406 |
374 /*****************************************************************************/ |
407 /*****************************************************************************/ |
375 |
408 |
376 /* Emacs-Konfiguration |
409 /* Emacs-Konfiguration |
377 ;;; Local Variables: *** |
410 ;;; Local Variables: *** |