38 }; |
38 }; |
39 |
39 |
40 /*****************************************************************************/ |
40 /*****************************************************************************/ |
41 |
41 |
42 /** |
42 /** |
43 Konstruktor einer EtherCAT-Domäne. |
43 Domain constructor. |
44 */ |
44 \return 0 in case of success, else < 0 |
45 |
45 */ |
46 int ec_domain_init(ec_domain_t *domain, /**< Domäne */ |
46 |
47 ec_master_t *master, /**< Zugehöriger Master */ |
47 int ec_domain_init(ec_domain_t *domain, /**< EtherCAT domain */ |
48 unsigned int index /**< Domänen-Index */ |
48 ec_master_t *master, /**< owning master */ |
|
49 unsigned int index /**< domain index */ |
49 ) |
50 ) |
50 { |
51 { |
51 domain->master = master; |
52 domain->master = master; |
52 domain->index = index; |
53 domain->index = index; |
53 domain->data_size = 0; |
54 domain->data_size = 0; |
55 domain->response_count = 0xFFFFFFFF; |
56 domain->response_count = 0xFFFFFFFF; |
56 |
57 |
57 INIT_LIST_HEAD(&domain->field_regs); |
58 INIT_LIST_HEAD(&domain->field_regs); |
58 INIT_LIST_HEAD(&domain->commands); |
59 INIT_LIST_HEAD(&domain->commands); |
59 |
60 |
60 // Init kobject and add it to the hierarchy |
61 // init kobject and add it to the hierarchy |
61 memset(&domain->kobj, 0x00, sizeof(struct kobject)); |
62 memset(&domain->kobj, 0x00, sizeof(struct kobject)); |
62 kobject_init(&domain->kobj); |
63 kobject_init(&domain->kobj); |
63 domain->kobj.ktype = &ktype_ec_domain; |
64 domain->kobj.ktype = &ktype_ec_domain; |
64 domain->kobj.parent = &master->kobj; |
65 domain->kobj.parent = &master->kobj; |
65 if (kobject_set_name(&domain->kobj, "domain%i", index)) { |
66 if (kobject_set_name(&domain->kobj, "domain%i", index)) { |
71 } |
72 } |
72 |
73 |
73 /*****************************************************************************/ |
74 /*****************************************************************************/ |
74 |
75 |
75 /** |
76 /** |
76 Destruktor einer EtherCAT-Domäne. |
77 Domain destructor. |
77 */ |
78 */ |
78 |
79 |
79 void ec_domain_clear(struct kobject *kobj /**< Kobject der Domäne */) |
80 void ec_domain_clear(struct kobject *kobj /**< kobject of the domain */) |
80 { |
81 { |
81 ec_command_t *command, *next; |
82 ec_command_t *command, *next; |
82 ec_domain_t *domain; |
83 ec_domain_t *domain; |
83 |
84 |
84 domain = container_of(kobj, ec_domain_t, kobj); |
85 domain = container_of(kobj, ec_domain_t, kobj); |
96 } |
97 } |
97 |
98 |
98 /*****************************************************************************/ |
99 /*****************************************************************************/ |
99 |
100 |
100 /** |
101 /** |
101 Registriert ein Feld in einer Domäne. |
102 Registeres a data field in a domain. |
102 |
103 \return 0 in case of success, else < 0 |
103 \return 0 bei Erfolg, < 0 bei Fehler |
104 */ |
104 */ |
105 |
105 |
106 int ec_domain_reg_field(ec_domain_t *domain, /**< EtherCAT domain */ |
106 int ec_domain_reg_field(ec_domain_t *domain, /**< Domäne */ |
107 ec_slave_t *slave, /**< slave */ |
107 ec_slave_t *slave, /**< Slave */ |
108 const ec_sync_t *sync, /**< sync manager */ |
108 const ec_sync_t *sync, /**< Sync-Manager */ |
109 uint32_t field_offset, /**< data field offset */ |
109 uint32_t field_offset, /**< Datenfeld-Offset */ |
110 void **data_ptr /**< pointer to the process data |
110 void **data_ptr /**< Adresse des Prozessdatenzeigers */ |
111 pointer */ |
111 ) |
112 ) |
112 { |
113 { |
113 ec_field_reg_t *field_reg; |
114 ec_field_reg_t *field_reg; |
114 |
115 |
115 if (!(field_reg = |
116 if (!(field_reg = |
134 } |
135 } |
135 |
136 |
136 /*****************************************************************************/ |
137 /*****************************************************************************/ |
137 |
138 |
138 /** |
139 /** |
139 Gibt die Liste der registrierten Datenfelder frei. |
140 Clears the list of the registered data fields. |
140 */ |
141 */ |
141 |
142 |
142 void ec_domain_clear_field_regs(ec_domain_t *domain) |
143 void ec_domain_clear_field_regs(ec_domain_t *domain /**< EtherCAT domain */) |
143 { |
144 { |
144 ec_field_reg_t *field_reg, *next; |
145 ec_field_reg_t *field_reg, *next; |
145 |
146 |
146 list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) { |
147 list_for_each_entry_safe(field_reg, next, &domain->field_regs, list) { |
147 list_del(&field_reg->list); |
148 list_del(&field_reg->list); |
150 } |
151 } |
151 |
152 |
152 /*****************************************************************************/ |
153 /*****************************************************************************/ |
153 |
154 |
154 /** |
155 /** |
155 Alloziert ein Prozessdatenkommando und fügt es in die Liste ein. |
156 Allocates a process data command and appends it to the list. |
156 */ |
157 \return 0 in case of success, else < 0 |
157 |
158 */ |
158 int ec_domain_add_command(ec_domain_t *domain, /**< Domäne */ |
159 |
159 uint32_t offset, /**< Logisches Offset */ |
160 int ec_domain_add_command(ec_domain_t *domain, /**< EtherCAT domain */ |
160 size_t data_size /**< Größe der Kommando-Daten */ |
161 uint32_t offset, /**< logical offset */ |
|
162 size_t data_size /**< size of the command data */ |
161 ) |
163 ) |
162 { |
164 { |
163 ec_command_t *command; |
165 ec_command_t *command; |
164 |
166 |
165 if (!(command = kmalloc(sizeof(ec_command_t), GFP_KERNEL))) { |
167 if (!(command = kmalloc(sizeof(ec_command_t), GFP_KERNEL))) { |
179 } |
181 } |
180 |
182 |
181 /*****************************************************************************/ |
183 /*****************************************************************************/ |
182 |
184 |
183 /** |
185 /** |
184 Erzeugt eine Domäne. |
186 Creates a domain. |
185 |
187 Reserves domain memory, calculates the logical addresses of the |
186 Reserviert den Speicher einer Domäne, berechnet die logischen Adressen der |
188 corresponding FMMUs and sets the process data pointer of the registered |
187 FMMUs und setzt die Prozessdatenzeiger der registrierten Felder. |
189 data fields. |
188 |
190 \return 0 in case of success, else < 0 |
189 \return 0 bei Erfolg, < 0 bei Fehler |
191 */ |
190 */ |
192 |
191 |
193 int ec_domain_alloc(ec_domain_t *domain, /**< EtherCAT domain */ |
192 int ec_domain_alloc(ec_domain_t *domain, /**< Domäne */ |
|
193 uint32_t base_address /**< Logische Basisadresse */ |
194 uint32_t base_address /**< Logische Basisadresse */ |
194 ) |
195 ) |
195 { |
196 { |
196 ec_field_reg_t *field_reg; |
197 ec_field_reg_t *field_reg; |
197 ec_slave_t *slave; |
198 ec_slave_t *slave; |
274 } |
275 } |
275 |
276 |
276 /*****************************************************************************/ |
277 /*****************************************************************************/ |
277 |
278 |
278 /** |
279 /** |
279 Gibt die Anzahl der antwortenden Slaves aus. |
280 Sets the number of responding slaves and outputs it on demand. |
280 */ |
281 This number isn't really the number of responding slaves, but the sum of |
281 |
282 the working counters of all domain commands. Some slaves increase the |
282 void ec_domain_response_count(ec_domain_t *domain, /**< Domäne */ |
283 working counter by 2, some by 1. |
283 unsigned int count /**< Neue Anzahl */ |
284 */ |
|
285 |
|
286 void ec_domain_response_count(ec_domain_t *domain, /**< EtherCAT domain */ |
|
287 unsigned int count /**< new WC sum */ |
284 ) |
288 ) |
285 { |
289 { |
286 if (count != domain->response_count) { |
290 if (count != domain->response_count) { |
287 domain->response_count = count; |
291 domain->response_count = count; |
288 EC_INFO("Domain %i working counter change: %i\n", domain->index, count); |
292 EC_INFO("Domain %i working counter change: %i\n", domain->index, |
289 } |
293 count); |
290 } |
294 } |
291 |
295 } |
292 /*****************************************************************************/ |
296 |
293 |
297 /*****************************************************************************/ |
294 /** |
298 |
295 Formatiert Attribut-Daten für lesenden Zugriff im SysFS |
299 /** |
296 |
300 Formats attribute data for SysFS reading. |
297 \return Anzahl Bytes im Speicher |
301 \return number of bytes to read |
298 */ |
302 */ |
299 |
303 |
300 ssize_t ec_show_domain_attribute(struct kobject *kobj, /**< KObject */ |
304 ssize_t ec_show_domain_attribute(struct kobject *kobj, /**< kobject */ |
301 struct attribute *attr, /**< Attribut */ |
305 struct attribute *attr, /**< attribute */ |
302 char *buffer /**< Speicher für die Daten */ |
306 char *buffer /**< memory to store data in */ |
303 ) |
307 ) |
304 { |
308 { |
305 ec_domain_t *domain = container_of(kobj, ec_domain_t, kobj); |
309 ec_domain_t *domain = container_of(kobj, ec_domain_t, kobj); |
306 |
310 |
307 if (attr == &attr_data_size) { |
311 if (attr == &attr_data_size) { |
310 |
314 |
311 return 0; |
315 return 0; |
312 } |
316 } |
313 |
317 |
314 /****************************************************************************** |
318 /****************************************************************************** |
315 * |
319 * Realtime interface |
316 * Echtzeitschnittstelle |
|
317 * |
|
318 *****************************************************************************/ |
320 *****************************************************************************/ |
319 |
321 |
320 /** |
322 /** |
321 Registriert ein Datenfeld innerhalb einer Domäne. |
323 Registers a data field in a domain. |
322 |
324 - If \a data_ptr is NULL, the slave is only checked against its type. |
323 - Ist \a data_ptr NULL, so wird der Slave nur auf den Typ überprüft. |
325 - If \a field_count is 0, it is assumed that one data field is to be |
324 - Wenn \a field_count 0 ist, wird angenommen, dass 1 Feld registriert werden |
326 registered. |
325 soll. |
327 - If \a field_count is greater then 1, it is assumed that \a data_ptr |
326 - Wenn \a field_count größer als 1 ist, wird angenommen, dass \a data_ptr |
328 is an array of the respective size. |
327 auf ein entsprechend großes Array zeigt. |
329 \return pointer to the slave on success, else NULL |
328 |
|
329 \return Zeiger auf den Slave bei Erfolg, sonst NULL |
|
330 */ |
330 */ |
331 |
331 |
332 ec_slave_t *ecrt_domain_register_field(ec_domain_t *domain, |
332 ec_slave_t *ecrt_domain_register_field(ec_domain_t *domain, |
333 /**< Domäne */ |
333 /**< EtherCAT domain */ |
334 const char *address, |
334 const char *address, |
335 /**< ASCII-Addresse des Slaves, |
335 /**< ASCII address of the slave, |
336 siehe ecrt_master_get_slave() */ |
336 see ecrt_master_get_slave() */ |
337 const char *vendor_name, |
337 const char *vendor_name, |
338 /**< Herstellername */ |
338 /**< vendor name */ |
339 const char *product_name, |
339 const char *product_name, |
340 /**< Produktname */ |
340 /**< product name */ |
341 void **data_ptr, |
341 void **data_ptr, |
342 /**< Adresse des Zeigers auf die |
342 /**< address of the process data |
343 Prozessdaten */ |
343 pointer */ |
344 const char *field_name, |
344 const char *field_name, |
345 /**< Name des Datenfeldes */ |
345 /**< data field name */ |
346 unsigned int field_index, |
346 unsigned int field_index, |
347 /**< Gibt an, ab welchem Feld mit |
347 /**< offset of data fields with |
348 Typ \a field_type gezählt |
348 \a field_type */ |
349 werden soll. */ |
|
350 unsigned int field_count |
349 unsigned int field_count |
351 /**< Anzahl Felder selben Typs */ |
350 /**< number of data fields (with |
|
351 the same type) to register */ |
352 ) |
352 ) |
353 { |
353 { |
354 ec_slave_t *slave; |
354 ec_slave_t *slave; |
355 const ec_slave_type_t *type; |
355 const ec_slave_type_t *type; |
356 ec_master_t *master; |
356 ec_master_t *master; |
359 unsigned int field_counter, i, j, orig_field_index, orig_field_count; |
359 unsigned int field_counter, i, j, orig_field_index, orig_field_count; |
360 uint32_t field_offset; |
360 uint32_t field_offset; |
361 |
361 |
362 master = domain->master; |
362 master = domain->master; |
363 |
363 |
364 // Adresse übersetzen |
364 // translate address |
365 if (!(slave = ecrt_master_get_slave(master, address))) return NULL; |
365 if (!(slave = ecrt_master_get_slave(master, address))) return NULL; |
366 |
366 |
367 if (!(type = slave->type)) { |
367 if (!(type = slave->type)) { |
368 EC_ERR("Slave \"%s\" (position %i) has unknown type!\n", address, |
368 EC_ERR("Slave \"%s\" (position %i) has unknown type!\n", address, |
369 slave->ring_position); |
369 slave->ring_position); |
377 product_name, type->vendor_name, type->product_name); |
377 product_name, type->vendor_name, type->product_name); |
378 return NULL; |
378 return NULL; |
379 } |
379 } |
380 |
380 |
381 if (!data_ptr) { |
381 if (!data_ptr) { |
382 // Wenn data_ptr NULL, Slave als registriert ansehen (nicht warnen). |
382 // data_ptr is NULL => mark slave as "registered" (do not warn) |
383 slave->registered = 1; |
383 slave->registered = 1; |
384 } |
384 } |
385 |
385 |
386 if (!field_count) field_count = 1; |
386 if (!field_count) field_count = 1; |
387 orig_field_index = field_index; |
387 orig_field_index = field_index; |
413 } |
413 } |
414 |
414 |
415 /*****************************************************************************/ |
415 /*****************************************************************************/ |
416 |
416 |
417 /** |
417 /** |
418 Registriert eine ganze Liste von Datenfeldern innerhalb einer Domäne. |
418 Registeres a bunch of data fields. |
419 |
419 Caution! The list has to be terminated with a NULL structure ({})! |
420 Achtung: Die Liste muss mit einer NULL-Struktur ({}) abgeschlossen sein! |
420 \return 0 in case of success, else < 0 |
421 |
|
422 \return 0 bei Erfolg, sonst < 0 |
|
423 */ |
421 */ |
424 |
422 |
425 int ecrt_domain_register_field_list(ec_domain_t *domain, |
423 int ecrt_domain_register_field_list(ec_domain_t *domain, |
426 /**< Domäne */ |
424 /**< EtherCAT domain */ |
427 const ec_field_init_t *fields |
425 const ec_field_init_t *fields |
428 /**< Array mit Datenfeldern */ |
426 /**< array of data field registrations */ |
429 ) |
427 ) |
430 { |
428 { |
431 const ec_field_init_t *field; |
429 const ec_field_init_t *field; |
432 |
430 |
433 for (field = fields; field->slave_address; field++) |
431 for (field = fields; field->slave_address; field++) |
442 } |
440 } |
443 |
441 |
444 /*****************************************************************************/ |
442 /*****************************************************************************/ |
445 |
443 |
446 /** |
444 /** |
447 Setzt Prozessdaten-Kommandos in die Warteschlange des Masters. |
445 Places all process data commands in the masters command queue. |
448 */ |
446 */ |
449 |
447 |
450 void ecrt_domain_queue(ec_domain_t *domain /**< Domäne */) |
448 void ecrt_domain_queue(ec_domain_t *domain /**< EtherCAT domain */) |
451 { |
449 { |
452 ec_command_t *command; |
450 ec_command_t *command; |
453 |
451 |
454 list_for_each_entry(command, &domain->commands, list) { |
452 list_for_each_entry(command, &domain->commands, list) { |
455 ec_master_queue_command(domain->master, command); |
453 ec_master_queue_command(domain->master, command); |
457 } |
455 } |
458 |
456 |
459 /*****************************************************************************/ |
457 /*****************************************************************************/ |
460 |
458 |
461 /** |
459 /** |
462 Verarbeitet empfangene Prozessdaten. |
460 Processes received process data. |
463 */ |
461 */ |
464 |
462 |
465 void ecrt_domain_process(ec_domain_t *domain /**< Domäne */) |
463 void ecrt_domain_process(ec_domain_t *domain /**< EtherCAT domain */) |
466 { |
464 { |
467 unsigned int working_counter_sum; |
465 unsigned int working_counter_sum; |
468 ec_command_t *command; |
466 ec_command_t *command; |
469 |
467 |
470 working_counter_sum = 0; |
468 working_counter_sum = 0; |
479 } |
477 } |
480 |
478 |
481 /*****************************************************************************/ |
479 /*****************************************************************************/ |
482 |
480 |
483 /** |
481 /** |
484 Gibt den Status einer Domäne zurück. |
482 Returns the state of a domain. |
485 |
483 \return 0 if all commands were received, else -1. |
486 \return 0 wenn alle Kommandos empfangen wurden, sonst -1. |
484 */ |
487 */ |
485 |
488 |
486 int ecrt_domain_state(ec_domain_t *domain /**< EtherCAT domain */) |
489 int ecrt_domain_state(ec_domain_t *domain /**< Domäne */) |
|
490 { |
487 { |
491 ec_command_t *command; |
488 ec_command_t *command; |
492 |
489 |
493 list_for_each_entry(command, &domain->commands, list) { |
490 list_for_each_entry(command, &domain->commands, list) { |
494 if (command->state != EC_CMD_RECEIVED) return -1; |
491 if (command->state != EC_CMD_RECEIVED) return -1; |