50 |
50 |
51 extern const ec_code_msg_t al_status_messages[]; |
51 extern const ec_code_msg_t al_status_messages[]; |
52 |
52 |
53 /*****************************************************************************/ |
53 /*****************************************************************************/ |
54 |
54 |
|
55 void ec_slave_clear(struct kobject *); |
|
56 void ec_slave_sdos_clear(struct kobject *); |
55 ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *); |
57 ssize_t ec_show_slave_attribute(struct kobject *, struct attribute *, char *); |
56 ssize_t ec_store_slave_attribute(struct kobject *, struct attribute *, |
58 ssize_t ec_store_slave_attribute(struct kobject *, struct attribute *, |
57 const char *, size_t); |
59 const char *, size_t); |
58 |
60 |
59 /*****************************************************************************/ |
61 /*****************************************************************************/ |
100 unsigned int i; |
106 unsigned int i; |
101 |
107 |
102 slave->ring_position = ring_position; |
108 slave->ring_position = ring_position; |
103 slave->station_address = station_address; |
109 slave->station_address = station_address; |
104 |
110 |
105 // init kobject and add it to the hierarchy |
|
106 memset(&slave->kobj, 0x00, sizeof(struct kobject)); |
|
107 kobject_init(&slave->kobj); |
|
108 slave->kobj.ktype = &ktype_ec_slave; |
|
109 slave->kobj.parent = &master->kobj; |
|
110 if (kobject_set_name(&slave->kobj, "slave%03i", slave->ring_position)) { |
|
111 EC_ERR("Failed to set kobject name.\n"); |
|
112 kobject_put(&slave->kobj); |
|
113 return -1; |
|
114 } |
|
115 |
|
116 slave->master = master; |
111 slave->master = master; |
117 |
112 |
118 slave->requested_state = EC_SLAVE_STATE_UNKNOWN; |
113 slave->requested_state = EC_SLAVE_STATE_UNKNOWN; |
119 slave->current_state = EC_SLAVE_STATE_UNKNOWN; |
114 slave->current_state = EC_SLAVE_STATE_UNKNOWN; |
|
115 slave->configured = 0; |
120 slave->error_flag = 0; |
116 slave->error_flag = 0; |
121 slave->online = 1; |
117 slave->online = 1; |
122 slave->fmmu_count = 0; |
118 slave->fmmu_count = 0; |
123 slave->registered = 0; |
|
124 |
119 |
125 slave->coupler_index = 0; |
120 slave->coupler_index = 0; |
126 slave->coupler_subindex = 0xFFFF; |
121 slave->coupler_subindex = 0xFFFF; |
127 |
122 |
128 slave->base_type = 0; |
123 slave->base_type = 0; |
154 INIT_LIST_HEAD(&slave->sii_strings); |
149 INIT_LIST_HEAD(&slave->sii_strings); |
155 INIT_LIST_HEAD(&slave->sii_syncs); |
150 INIT_LIST_HEAD(&slave->sii_syncs); |
156 INIT_LIST_HEAD(&slave->sii_pdos); |
151 INIT_LIST_HEAD(&slave->sii_pdos); |
157 INIT_LIST_HEAD(&slave->sdo_dictionary); |
152 INIT_LIST_HEAD(&slave->sdo_dictionary); |
158 INIT_LIST_HEAD(&slave->sdo_confs); |
153 INIT_LIST_HEAD(&slave->sdo_confs); |
159 INIT_LIST_HEAD(&slave->varsize_fields); |
154 |
|
155 slave->sdo_dictionary_fetched = 0; |
|
156 slave->jiffies_preop = 0; |
160 |
157 |
161 for (i = 0; i < 4; i++) { |
158 for (i = 0; i < 4; i++) { |
162 slave->dl_link[i] = 0; |
159 slave->dl_link[i] = 0; |
163 slave->dl_loop[i] = 0; |
160 slave->dl_loop[i] = 0; |
164 slave->dl_signal[i] = 0; |
161 slave->dl_signal[i] = 0; |
165 slave->sii_physical_layer[i] = 0xFF; |
162 slave->sii_physical_layer[i] = 0xFF; |
166 } |
163 } |
167 |
164 |
|
165 // init kobject and add it to the hierarchy |
|
166 memset(&slave->kobj, 0x00, sizeof(struct kobject)); |
|
167 kobject_init(&slave->kobj); |
|
168 slave->kobj.ktype = &ktype_ec_slave; |
|
169 slave->kobj.parent = &master->kobj; |
|
170 if (kobject_set_name(&slave->kobj, "slave%03i", slave->ring_position)) { |
|
171 EC_ERR("Failed to set kobject name.\n"); |
|
172 goto out_slave_put; |
|
173 } |
|
174 if (kobject_add(&slave->kobj)) { |
|
175 EC_ERR("Failed to add slave's kobject.\n"); |
|
176 goto out_slave_put; |
|
177 } |
|
178 |
|
179 // init SDO kobject and add it to the hierarchy |
|
180 memset(&slave->sdo_kobj, 0x00, sizeof(struct kobject)); |
|
181 kobject_init(&slave->sdo_kobj); |
|
182 slave->sdo_kobj.ktype = &ktype_ec_slave_sdos; |
|
183 slave->sdo_kobj.parent = &slave->kobj; |
|
184 if (kobject_set_name(&slave->sdo_kobj, "sdos")) { |
|
185 EC_ERR("Failed to set kobject name.\n"); |
|
186 goto out_sdo_put; |
|
187 } |
|
188 if (kobject_add(&slave->sdo_kobj)) { |
|
189 EC_ERR("Failed to add SDOs kobject.\n"); |
|
190 goto out_sdo_put; |
|
191 } |
|
192 |
168 return 0; |
193 return 0; |
|
194 |
|
195 out_sdo_put: |
|
196 kobject_put(&slave->sdo_kobj); |
|
197 kobject_del(&slave->kobj); |
|
198 out_slave_put: |
|
199 kobject_put(&slave->kobj); |
|
200 return -1; |
169 } |
201 } |
170 |
202 |
171 /*****************************************************************************/ |
203 /*****************************************************************************/ |
172 |
204 |
173 /** |
205 /** |
174 Slave destructor. |
206 Slave destructor. |
|
207 Clears and frees a slave object. |
|
208 */ |
|
209 |
|
210 void ec_slave_destroy(ec_slave_t *slave /**< EtherCAT slave */) |
|
211 { |
|
212 ec_sdo_t *sdo, *next_sdo; |
|
213 |
|
214 // free all SDOs |
|
215 list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) { |
|
216 list_del(&sdo->list); |
|
217 ec_sdo_destroy(sdo); |
|
218 } |
|
219 |
|
220 // free SDO kobject |
|
221 kobject_del(&slave->sdo_kobj); |
|
222 kobject_put(&slave->sdo_kobj); |
|
223 |
|
224 // destroy self |
|
225 kobject_del(&slave->kobj); |
|
226 kobject_put(&slave->kobj); |
|
227 } |
|
228 |
|
229 /*****************************************************************************/ |
|
230 |
|
231 /** |
|
232 Clear and free slave. |
|
233 This method is called by the kobject, |
|
234 once there are no more references to it. |
175 */ |
235 */ |
176 |
236 |
177 void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) |
237 void ec_slave_clear(struct kobject *kobj /**< kobject of the slave */) |
178 { |
238 { |
179 ec_slave_t *slave; |
239 ec_slave_t *slave; |
180 ec_sii_string_t *string, *next_str; |
240 ec_sii_string_t *string, *next_str; |
181 ec_sii_sync_t *sync, *next_sync; |
241 ec_sii_sync_t *sync, *next_sync; |
182 ec_sii_pdo_t *pdo, *next_pdo; |
242 ec_sii_pdo_t *pdo, *next_pdo; |
183 ec_sii_pdo_entry_t *entry, *next_ent; |
243 ec_sii_pdo_entry_t *entry, *next_ent; |
184 ec_sdo_t *sdo, *next_sdo; |
|
185 ec_sdo_entry_t *en, *next_en; |
|
186 ec_sdo_data_t *sdodata, *next_sdodata; |
244 ec_sdo_data_t *sdodata, *next_sdodata; |
187 ec_varsize_t *var, *next_var; |
|
188 |
245 |
189 slave = container_of(kobj, ec_slave_t, kobj); |
246 slave = container_of(kobj, ec_slave_t, kobj); |
190 |
247 |
191 // free all string objects |
248 // free all string objects |
192 list_for_each_entry_safe(string, next_str, &slave->sii_strings, list) { |
249 list_for_each_entry_safe(string, next_str, &slave->sii_strings, list) { |
218 if (slave->sii_group) kfree(slave->sii_group); |
275 if (slave->sii_group) kfree(slave->sii_group); |
219 if (slave->sii_image) kfree(slave->sii_image); |
276 if (slave->sii_image) kfree(slave->sii_image); |
220 if (slave->sii_order) kfree(slave->sii_order); |
277 if (slave->sii_order) kfree(slave->sii_order); |
221 if (slave->sii_name) kfree(slave->sii_name); |
278 if (slave->sii_name) kfree(slave->sii_name); |
222 |
279 |
223 // free all SDOs |
|
224 list_for_each_entry_safe(sdo, next_sdo, &slave->sdo_dictionary, list) { |
|
225 list_del(&sdo->list); |
|
226 if (sdo->name) kfree(sdo->name); |
|
227 |
|
228 // free all SDO entries |
|
229 list_for_each_entry_safe(en, next_en, &sdo->entries, list) { |
|
230 list_del(&en->list); |
|
231 kfree(en); |
|
232 } |
|
233 kfree(sdo); |
|
234 } |
|
235 |
|
236 // free all SDO configurations |
280 // free all SDO configurations |
237 list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) { |
281 list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) { |
238 list_del(&sdodata->list); |
282 list_del(&sdodata->list); |
239 kfree(sdodata->data); |
283 kfree(sdodata->data); |
240 kfree(sdodata); |
284 kfree(sdodata); |
241 } |
285 } |
242 |
286 |
243 // free information about variable sized data fields |
|
244 list_for_each_entry_safe(var, next_var, &slave->varsize_fields, list) { |
|
245 list_del(&var->list); |
|
246 kfree(var); |
|
247 } |
|
248 |
|
249 if (slave->eeprom_data) kfree(slave->eeprom_data); |
287 if (slave->eeprom_data) kfree(slave->eeprom_data); |
250 if (slave->new_eeprom_data) kfree(slave->new_eeprom_data); |
288 if (slave->new_eeprom_data) kfree(slave->new_eeprom_data); |
|
289 |
|
290 kfree(slave); |
|
291 } |
|
292 |
|
293 /*****************************************************************************/ |
|
294 |
|
295 /** |
|
296 */ |
|
297 |
|
298 void ec_slave_sdos_clear(struct kobject *kobj /**< kobject for SDOs */) |
|
299 { |
|
300 } |
|
301 |
|
302 /*****************************************************************************/ |
|
303 |
|
304 /** |
|
305 Reset slave from operation mode. |
|
306 */ |
|
307 |
|
308 void ec_slave_reset(ec_slave_t *slave /**< EtherCAT slave */) |
|
309 { |
|
310 ec_sdo_data_t *sdodata, *next_sdodata; |
|
311 ec_sii_sync_t *sync; |
|
312 |
|
313 // remove FMMU configurations |
|
314 slave->fmmu_count = 0; |
|
315 |
|
316 // free all SDO configurations |
|
317 list_for_each_entry_safe(sdodata, next_sdodata, &slave->sdo_confs, list) { |
|
318 list_del(&sdodata->list); |
|
319 kfree(sdodata->data); |
|
320 kfree(sdodata); |
|
321 } |
|
322 |
|
323 // remove estimated sync manager sizes |
|
324 list_for_each_entry(sync, &slave->sii_syncs, list) { |
|
325 sync->est_length = 0; |
|
326 } |
|
327 } |
|
328 |
|
329 /*****************************************************************************/ |
|
330 |
|
331 /** |
|
332 */ |
|
333 |
|
334 void ec_slave_request_state(ec_slave_t *slave, /**< ETherCAT slave */ |
|
335 ec_slave_state_t state /**< new state */ |
|
336 ) |
|
337 { |
|
338 slave->requested_state = state; |
|
339 slave->error_flag = 0; |
251 } |
340 } |
252 |
341 |
253 /*****************************************************************************/ |
342 /*****************************************************************************/ |
254 |
343 |
255 /** |
344 /** |
476 const ec_domain_t *domain, /**< domain */ |
569 const ec_domain_t *domain, /**< domain */ |
477 const ec_sii_sync_t *sync /**< sync manager */ |
570 const ec_sii_sync_t *sync /**< sync manager */ |
478 ) |
571 ) |
479 { |
572 { |
480 unsigned int i; |
573 unsigned int i; |
|
574 ec_fmmu_t *fmmu; |
481 |
575 |
482 // FMMU configuration already prepared? |
576 // FMMU configuration already prepared? |
483 for (i = 0; i < slave->fmmu_count; i++) |
577 for (i = 0; i < slave->fmmu_count; i++) { |
484 if (slave->fmmus[i].domain == domain && slave->fmmus[i].sync == sync) |
578 fmmu = &slave->fmmus[i]; |
|
579 if (fmmu->domain == domain && fmmu->sync == sync) |
485 return 0; |
580 return 0; |
|
581 } |
486 |
582 |
487 // reserve new FMMU... |
583 // reserve new FMMU... |
488 |
584 |
489 if (slave->fmmu_count >= slave->base_fmmu_count) { |
585 if (slave->fmmu_count >= slave->base_fmmu_count) { |
490 EC_ERR("Slave %i FMMU limit reached!\n", slave->ring_position); |
586 EC_ERR("Slave %i FMMU limit reached!\n", slave->ring_position); |
491 return -1; |
587 return -1; |
492 } |
588 } |
493 |
589 |
494 slave->fmmus[slave->fmmu_count].domain = domain; |
590 fmmu = &slave->fmmus[slave->fmmu_count]; |
495 slave->fmmus[slave->fmmu_count].sync = sync; |
591 |
496 slave->fmmus[slave->fmmu_count].logical_start_address = 0; |
592 fmmu->index = slave->fmmu_count; |
|
593 fmmu->domain = domain; |
|
594 fmmu->sync = sync; |
|
595 fmmu->logical_start_address = 0; |
|
596 |
497 slave->fmmu_count++; |
597 slave->fmmu_count++; |
498 slave->registered = 1; |
|
499 |
598 |
500 return 0; |
599 return 0; |
501 } |
600 } |
502 |
601 |
503 /*****************************************************************************/ |
602 /*****************************************************************************/ |
526 off += sprintf(buffer + off, "Product code: 0x%08X\n\n", |
627 off += sprintf(buffer + off, "Product code: 0x%08X\n\n", |
527 slave->sii_product_code); |
628 slave->sii_product_code); |
528 |
629 |
529 off += sprintf(buffer + off, "State: "); |
630 off += sprintf(buffer + off, "State: "); |
530 off += ec_state_string(slave->current_state, buffer + off); |
631 off += ec_state_string(slave->current_state, buffer + off); |
531 off += sprintf(buffer + off, "\nRing position: %i\n", |
632 off += sprintf(buffer + off, "\nFlags: %s, %s\n", |
|
633 slave->online ? "online" : "OFFLINE", |
|
634 slave->error_flag ? "ERROR" : "ok"); |
|
635 off += sprintf(buffer + off, "Ring position: %i\n", |
532 slave->ring_position); |
636 slave->ring_position); |
533 off += sprintf(buffer + off, "Advanced position: %i:%i\n", |
637 off += sprintf(buffer + off, "Advanced position: %i:%i\n", |
534 slave->coupler_index, slave->coupler_subindex); |
638 slave->coupler_index, slave->coupler_subindex); |
535 off += sprintf(buffer + off, "Coupler: %s\n\n", |
639 off += sprintf(buffer + off, "Coupler: %s\n\n", |
536 ec_slave_is_coupler(slave) ? "yes" : "no"); |
640 ec_slave_is_coupler(slave) ? "yes" : "no"); |
641 pdo_entry->index, pdo_entry->subindex, |
745 pdo_entry->index, pdo_entry->subindex, |
642 pdo_entry->bit_length); |
746 pdo_entry->bit_length); |
643 } |
747 } |
644 } |
748 } |
645 |
749 |
|
750 if (!list_empty(&slave->sdo_confs)) |
|
751 off += sprintf(buffer + off, "\nSDO configurations:\n"); |
|
752 |
|
753 list_for_each_entry(sdodata, &slave->sdo_confs, list) { |
|
754 switch (sdodata->size) { |
|
755 case 1: sprintf(str, "%i", EC_READ_U8(sdodata->data)); break; |
|
756 case 2: sprintf(str, "%i", EC_READ_U16(sdodata->data)); break; |
|
757 case 4: sprintf(str, "%i", EC_READ_U32(sdodata->data)); break; |
|
758 default: sprintf(str, "(invalid size)"); break; |
|
759 } |
|
760 off += sprintf(buffer + off, " 0x%04X:%-3i -> %s\n", |
|
761 sdodata->index, sdodata->subindex, str); |
|
762 } |
|
763 |
646 off += sprintf(buffer + off, "\n"); |
764 off += sprintf(buffer + off, "\n"); |
647 |
765 |
648 return off; |
766 return off; |
649 } |
767 } |
650 |
768 |
787 ) |
905 ) |
788 { |
906 { |
789 ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj); |
907 ec_slave_t *slave = container_of(kobj, ec_slave_t, kobj); |
790 |
908 |
791 if (attr == &attr_state) { |
909 if (attr == &attr_state) { |
792 char state[25]; |
910 char state[EC_STATE_STRING_SIZE]; |
793 if (!strcmp(buffer, "INIT\n")) |
911 if (!strcmp(buffer, "INIT\n")) |
794 slave->requested_state = EC_SLAVE_STATE_INIT; |
912 ec_slave_request_state(slave, EC_SLAVE_STATE_INIT); |
795 else if (!strcmp(buffer, "PREOP\n")) |
913 else if (!strcmp(buffer, "PREOP\n")) |
796 slave->requested_state = EC_SLAVE_STATE_PREOP; |
914 ec_slave_request_state(slave, EC_SLAVE_STATE_PREOP); |
797 else if (!strcmp(buffer, "SAVEOP\n")) |
915 else if (!strcmp(buffer, "SAVEOP\n")) |
798 slave->requested_state = EC_SLAVE_STATE_SAVEOP; |
916 ec_slave_request_state(slave, EC_SLAVE_STATE_SAVEOP); |
799 else if (!strcmp(buffer, "OP\n")) |
917 else if (!strcmp(buffer, "OP\n")) |
800 slave->requested_state = EC_SLAVE_STATE_OP; |
918 ec_slave_request_state(slave, EC_SLAVE_STATE_OP); |
801 else { |
919 else { |
802 EC_ERR("Invalid slave state \"%s\"!\n", buffer); |
920 EC_ERR("Invalid slave state \"%s\"!\n", buffer); |
803 return -EINVAL; |
921 return -EINVAL; |
804 } |
922 } |
805 |
923 |
806 ec_state_string(slave->requested_state, state); |
924 ec_state_string(slave->requested_state, state); |
807 EC_INFO("Accepted new state %s for slave %i.\n", |
925 EC_INFO("Accepted new state %s for slave %i.\n", |
808 state, slave->ring_position); |
926 state, slave->ring_position); |
809 slave->error_flag = 0; |
|
810 return size; |
927 return size; |
811 } |
928 } |
812 else if (attr == &attr_eeprom) { |
929 else if (attr == &attr_eeprom) { |
813 if (!ec_slave_write_eeprom(slave, buffer, size)) |
930 if (!ec_slave_write_eeprom(slave, buffer, size)) |
814 return size; |
931 return size; |
913 memcpy(sdodata->data, data, size); |
1033 memcpy(sdodata->data, data, size); |
914 sdodata->size = size; |
1034 sdodata->size = size; |
915 |
1035 |
916 list_add_tail(&sdodata->list, &slave->sdo_confs); |
1036 list_add_tail(&sdodata->list, &slave->sdo_confs); |
917 return 0; |
1037 return 0; |
|
1038 } |
|
1039 |
|
1040 /*****************************************************************************/ |
|
1041 |
|
1042 /** |
|
1043 \return 0 in case of success, else < 0 |
|
1044 */ |
|
1045 |
|
1046 int ec_slave_validate(const ec_slave_t *slave, /**< EtherCAT slave */ |
|
1047 uint32_t vendor_id, /**< vendor ID */ |
|
1048 uint32_t product_code /**< product code */ |
|
1049 ) |
|
1050 { |
|
1051 if (vendor_id != slave->sii_vendor_id || |
|
1052 product_code != slave->sii_product_code) { |
|
1053 EC_ERR("Invalid slave type at position %i - Requested: 0x%08X 0x%08X," |
|
1054 " found: 0x%08X 0x%08X\".\n", slave->ring_position, vendor_id, |
|
1055 product_code, slave->sii_vendor_id, slave->sii_product_code); |
|
1056 return -1; |
|
1057 } |
|
1058 return 0; |
|
1059 } |
|
1060 |
|
1061 /*****************************************************************************/ |
|
1062 |
|
1063 /** |
|
1064 Counts the total number of SDOs and entries in the dictionary. |
|
1065 */ |
|
1066 |
|
1067 void ec_slave_sdo_dict_info(const ec_slave_t *slave, /**< EtherCAT slave */ |
|
1068 unsigned int *sdo_count, /**< number of SDOs */ |
|
1069 unsigned int *entry_count /**< total number of |
|
1070 entries */ |
|
1071 ) |
|
1072 { |
|
1073 unsigned int sdos = 0, entries = 0; |
|
1074 ec_sdo_t *sdo; |
|
1075 ec_sdo_entry_t *entry; |
|
1076 |
|
1077 list_for_each_entry(sdo, &slave->sdo_dictionary, list) { |
|
1078 sdos++; |
|
1079 list_for_each_entry(entry, &sdo->entries, list) { |
|
1080 entries++; |
|
1081 } |
|
1082 } |
|
1083 |
|
1084 *sdo_count = sdos; |
|
1085 *entry_count = entries; |
918 } |
1086 } |
919 |
1087 |
920 /****************************************************************************** |
1088 /****************************************************************************** |
921 * Realtime interface |
1089 * Realtime interface |
922 *****************************************************************************/ |
1090 *****************************************************************************/ |