122 void ec_domain_add_fmmu_config( |
131 void ec_domain_add_fmmu_config( |
123 ec_domain_t *domain, /**< EtherCAT domain. */ |
132 ec_domain_t *domain, /**< EtherCAT domain. */ |
124 ec_fmmu_config_t *fmmu /**< FMMU configuration. */ |
133 ec_fmmu_config_t *fmmu /**< FMMU configuration. */ |
125 ) |
134 ) |
126 { |
135 { |
|
136 const ec_slave_config_t *sc; |
|
137 uint32_t logical_domain_offset; |
|
138 unsigned fmmu_data_size; |
|
139 |
127 fmmu->domain = domain; |
140 fmmu->domain = domain; |
128 |
141 sc = fmmu->sc; |
129 domain->data_size += fmmu->data_size; |
142 |
|
143 fmmu_data_size = ec_pdo_list_total_size( |
|
144 &sc->sync_configs[fmmu->sync_index].pdos); |
|
145 |
|
146 if (sc->allow_overlapping_pdos && (sc == domain->sc_in_work)) { |
|
147 // If we permit overlapped PDOs, and we already have an allocated FMMU |
|
148 // for this slave, allocate the subsequent FMMU offsets by direction |
|
149 logical_domain_offset = domain->offset_used[fmmu->dir]; |
|
150 } else { |
|
151 // otherwise, allocate to the furthest extent of any allocated |
|
152 // FMMU on this domain. |
|
153 logical_domain_offset = max(domain->offset_used[EC_DIR_INPUT], |
|
154 domain->offset_used[EC_DIR_OUTPUT]); |
|
155 // rebase the free offsets to the current position |
|
156 domain->offset_used[EC_DIR_INPUT] = logical_domain_offset; |
|
157 domain->offset_used[EC_DIR_OUTPUT] = logical_domain_offset; |
|
158 } |
|
159 domain->sc_in_work = sc; |
|
160 |
|
161 // consume the offset space for this FMMU's direction |
|
162 domain->offset_used[fmmu->dir] += fmmu_data_size; |
|
163 |
|
164 ec_fmmu_set_domain_offset_size(fmmu, logical_domain_offset, fmmu_data_size); |
|
165 |
130 list_add_tail(&fmmu->list, &domain->fmmu_configs); |
166 list_add_tail(&fmmu->list, &domain->fmmu_configs); |
131 |
167 |
|
168 // Determine domain size from furthest extent of FMMU data |
|
169 domain->data_size = max(domain->offset_used[EC_DIR_INPUT], |
|
170 domain->offset_used[EC_DIR_OUTPUT]); |
|
171 |
132 EC_MASTER_DBG(domain->master, 1, "Domain %u:" |
172 EC_MASTER_DBG(domain->master, 1, "Domain %u:" |
133 " Added %u bytes, total %zu.\n", |
173 " Added %u bytes at %u.\n", |
134 domain->index, fmmu->data_size, domain->data_size); |
174 domain->index, fmmu->data_size, logical_domain_offset); |
135 } |
175 } |
136 |
176 |
137 /*****************************************************************************/ |
177 /*****************************************************************************/ |
138 |
178 |
139 /** Allocates a domain datagram pair and appends it to the list. |
179 /** Allocates a domain datagram pair and appends it to the list. |
211 return 1; |
251 return 1; |
212 } |
252 } |
213 |
253 |
214 /*****************************************************************************/ |
254 /*****************************************************************************/ |
215 |
255 |
|
256 /** Domain finish helper function. |
|
257 * |
|
258 * Known boundaries for a datagram have been identified. Scans the datagram |
|
259 * FMMU boundaries for WKC counters and then creates the datagram_pair. |
|
260 * |
|
261 * \param domain The parent domain |
|
262 * \param datagram_begin_offset Datagram's logical beginning offset |
|
263 * \param datagram_end_offset Logical end offset (one past last byte) |
|
264 * \param datagram_first_fmmu The begin FMMU in the datagram |
|
265 * \param datagram_end_fmmu The end (one past last) FMMU |
|
266 * |
|
267 * \return Non-zero if error emplacing domain |
|
268 */ |
|
269 static int emplace_datagram(ec_domain_t *domain, |
|
270 uint32_t datagram_begin_offset, |
|
271 uint32_t datagram_end_offset, |
|
272 const ec_fmmu_config_t *datagram_first_fmmu, |
|
273 const ec_fmmu_config_t *datagram_end_fmmu |
|
274 ) |
|
275 { |
|
276 unsigned int datagram_used[EC_DIR_COUNT]; |
|
277 const ec_fmmu_config_t *curr_fmmu; |
|
278 size_t data_size; |
|
279 |
|
280 data_size = datagram_end_offset - datagram_begin_offset; |
|
281 |
|
282 memset(datagram_used, 0, sizeof(datagram_used)); |
|
283 for (curr_fmmu = datagram_first_fmmu; |
|
284 &curr_fmmu->list != &datagram_end_fmmu->list; |
|
285 curr_fmmu = list_next_entry(curr_fmmu, list)) { |
|
286 if (shall_count(curr_fmmu, datagram_first_fmmu)) { |
|
287 datagram_used[curr_fmmu->dir]++; |
|
288 } |
|
289 } |
|
290 |
|
291 return ec_domain_add_datagram_pair(domain, |
|
292 domain->logical_base_address + datagram_begin_offset, |
|
293 data_size, |
|
294 domain->data + datagram_begin_offset, |
|
295 datagram_used); |
|
296 } |
|
297 |
|
298 /*****************************************************************************/ |
|
299 |
216 /** Finishes a domain. |
300 /** Finishes a domain. |
217 * |
301 * |
218 * This allocates the necessary datagrams and writes the correct logical |
302 * This allocates the necessary datagrams and writes the correct logical |
219 * addresses to every configured FMMU. |
303 * addresses to every configured FMMU. |
220 * |
|
221 * \todo Check for FMMUs that do not fit into any datagram. |
|
222 * |
304 * |
223 * \retval 0 Success |
305 * \retval 0 Success |
224 * \retval <0 Error code. |
306 * \retval <0 Error code. |
225 */ |
307 */ |
226 int ec_domain_finish( |
308 int ec_domain_finish( |
227 ec_domain_t *domain, /**< EtherCAT domain. */ |
309 ec_domain_t *domain, /**< EtherCAT domain. */ |
228 uint32_t base_address /**< Logical base address. */ |
310 uint32_t base_address /**< Logical base address. */ |
229 ) |
311 ) |
230 { |
312 { |
231 uint32_t datagram_offset; |
313 uint32_t datagram_offset = 0; |
232 size_t datagram_size; |
314 unsigned int datagram_count = 0; |
233 unsigned int datagram_count; |
|
234 unsigned int datagram_used[EC_DIR_COUNT]; |
|
235 ec_fmmu_config_t *fmmu; |
315 ec_fmmu_config_t *fmmu; |
236 const ec_fmmu_config_t *datagram_first_fmmu = NULL; |
316 const ec_fmmu_config_t *datagram_first_fmmu = NULL; |
|
317 const ec_fmmu_config_t *valid_fmmu = NULL; |
|
318 unsigned candidate_start = 0; |
|
319 unsigned valid_start = 0; |
237 const ec_datagram_pair_t *datagram_pair; |
320 const ec_datagram_pair_t *datagram_pair; |
238 int ret; |
321 int ret; |
239 |
322 |
240 domain->logical_base_address = base_address; |
323 domain->logical_base_address = base_address; |
241 |
324 |
251 |
334 |
252 // Cycle through all domain FMMUs and |
335 // Cycle through all domain FMMUs and |
253 // - correct the logical base addresses |
336 // - correct the logical base addresses |
254 // - set up the datagrams to carry the process data |
337 // - set up the datagrams to carry the process data |
255 // - calculate the datagrams' expected working counters |
338 // - calculate the datagrams' expected working counters |
256 datagram_offset = 0; |
|
257 datagram_size = 0; |
|
258 datagram_count = 0; |
|
259 datagram_used[EC_DIR_OUTPUT] = 0; |
|
260 datagram_used[EC_DIR_INPUT] = 0; |
|
261 |
|
262 if (!list_empty(&domain->fmmu_configs)) { |
339 if (!list_empty(&domain->fmmu_configs)) { |
263 datagram_first_fmmu = |
340 datagram_first_fmmu = |
264 list_entry(domain->fmmu_configs.next, ec_fmmu_config_t, list); |
341 list_entry(domain->fmmu_configs.next, ec_fmmu_config_t, list); |
265 } |
342 } |
266 |
343 |
267 list_for_each_entry(fmmu, &domain->fmmu_configs, list) { |
344 list_for_each_entry(fmmu, &domain->fmmu_configs, list) { |
268 |
345 if (fmmu->data_size > EC_MAX_DATA_SIZE) { |
269 // Correct logical FMMU address |
346 EC_MASTER_ERR(domain->master, |
270 fmmu->logical_start_address += base_address; |
347 "FMMU size %u bytes exceeds maximum data size %u", |
271 |
348 fmmu->data_size, EC_MAX_DATA_SIZE); |
272 // Increment Input/Output counter to determine datagram types |
349 return -EINVAL; |
273 // and calculate expected working counters |
350 } |
274 if (shall_count(fmmu, datagram_first_fmmu)) { |
351 if (fmmu->logical_domain_offset >= candidate_start) { |
275 datagram_used[fmmu->dir]++; |
352 // As FMMU offsets increase monotonically, and candidate start |
276 } |
353 // offset has never been contradicted, it can now never be |
277 |
354 // contradicted, as no future FMMU can cross it. |
278 // If the current FMMU's data do not fit in the current datagram, |
355 // All FMMUs prior to this point approved for next datagram |
279 // allocate a new one. |
356 valid_fmmu = fmmu; |
280 if (datagram_size + fmmu->data_size > EC_MAX_DATA_SIZE) { |
357 valid_start = candidate_start; |
281 ret = ec_domain_add_datagram_pair(domain, |
358 if (fmmu->logical_domain_offset + fmmu->data_size - datagram_offset |
282 domain->logical_base_address + datagram_offset, |
359 > EC_MAX_DATA_SIZE) { |
283 datagram_size, domain->data + datagram_offset, |
360 // yet the new candidate exceeds the datagram size, so we |
284 datagram_used); |
361 // use the last known valid candidate to create the datagram |
285 if (ret < 0) |
362 ret = emplace_datagram(domain, datagram_offset, valid_start, |
286 return ret; |
363 datagram_first_fmmu, valid_fmmu); |
287 |
364 if (ret < 0) |
288 datagram_offset += datagram_size; |
365 return ret; |
289 datagram_size = 0; |
366 |
290 datagram_count++; |
367 datagram_offset = valid_start; |
291 datagram_used[EC_DIR_OUTPUT] = 0; |
368 datagram_count++; |
292 datagram_used[EC_DIR_INPUT] = 0; |
369 datagram_first_fmmu = fmmu; |
293 datagram_first_fmmu = fmmu; |
370 } |
294 } |
371 } |
295 |
372 if (fmmu->logical_domain_offset + fmmu->data_size > candidate_start) { |
296 datagram_size += fmmu->data_size; |
373 candidate_start = fmmu->logical_domain_offset + fmmu->data_size; |
|
374 } |
297 } |
375 } |
298 |
376 |
299 /* Allocate last datagram pair, if data are left (this is also the case if |
377 /* Allocate last datagram pair, if data are left (this is also the case if |
300 * the process data fit into a single datagram) */ |
378 * the process data fit into a single datagram) */ |
301 if (datagram_size) { |
379 if (domain->data_size > datagram_offset) { |
302 ret = ec_domain_add_datagram_pair(domain, |
380 ret = emplace_datagram(domain, datagram_offset, domain->data_size, |
303 domain->logical_base_address + datagram_offset, |
381 datagram_first_fmmu, fmmu); |
304 datagram_size, domain->data + datagram_offset, |
|
305 datagram_used); |
|
306 if (ret < 0) |
382 if (ret < 0) |
307 return ret; |
383 return ret; |
308 datagram_count++; |
384 datagram_count++; |
309 } |
385 } |
310 |
386 |
315 |
391 |
316 list_for_each_entry(datagram_pair, &domain->datagram_pairs, list) { |
392 list_for_each_entry(datagram_pair, &domain->datagram_pairs, list) { |
317 const ec_datagram_t *datagram = |
393 const ec_datagram_t *datagram = |
318 &datagram_pair->datagrams[EC_DEVICE_MAIN]; |
394 &datagram_pair->datagrams[EC_DEVICE_MAIN]; |
319 EC_MASTER_INFO(domain->master, " Datagram %s: Logical offset 0x%08x," |
395 EC_MASTER_INFO(domain->master, " Datagram %s: Logical offset 0x%08x," |
320 " %zu byte, type %s.\n", datagram->name, |
396 " %zu byte, type %s at %p.\n", datagram->name, |
321 EC_READ_U32(datagram->address), datagram->data_size, |
397 EC_READ_U32(datagram->address), datagram->data_size, |
322 ec_datagram_type_string(datagram)); |
398 ec_datagram_type_string(datagram), datagram); |
323 } |
399 } |
324 |
400 |
325 return 0; |
401 return 0; |
326 } |
402 } |
327 |
403 |
501 |
577 |
502 if (fmmu->dir != EC_DIR_INPUT) { |
578 if (fmmu->dir != EC_DIR_INPUT) { |
503 continue; |
579 continue; |
504 } |
580 } |
505 |
581 |
506 if (fmmu->logical_start_address >= |
582 if (fmmu->logical_domain_offset >= datagram_size) { |
507 logical_datagram_address + datagram_size) { |
|
508 // fmmu data contained in next datagram pair |
583 // fmmu data contained in next datagram pair |
509 break; |
584 break; |
510 } |
585 } |
511 |
586 |
512 datagram_offset = |
587 datagram_offset = fmmu->logical_domain_offset; |
513 fmmu->logical_start_address - logical_datagram_address; |
|
514 |
588 |
515 #if DEBUG_REDUNDANCY |
589 #if DEBUG_REDUNDANCY |
516 EC_MASTER_DBG(domain->master, 1, |
590 EC_MASTER_DBG(domain->master, 1, |
517 "input fmmu log=%u size=%u offset=%u\n", |
591 "input fmmu log_off=%u size=%u offset=%u\n", |
518 fmmu->logical_start_address, fmmu->data_size, |
592 fmmu->logical_domain_offset, fmmu->data_size, |
519 datagram_offset); |
593 datagram_offset); |
520 if (domain->master->debug_level > 0) { |
594 if (domain->master->debug_level > 0) { |
521 ec_print_data(pair->send_buffer + datagram_offset, |
595 ec_print_data(pair->send_buffer + datagram_offset, |
522 fmmu->data_size); |
596 fmmu->data_size); |
523 ec_print_data(main_datagram->data + datagram_offset, |
597 ec_print_data(main_datagram->data + datagram_offset, |