Skip to content

Commit 32bb524

Browse files
author
Daniel Udd
committed
Fix segmented download of objects larger than 64 bits
The notification callback was not being triggered for downloads of objects larger than 64 bits. Changed default timeout to 200ms for ongoing SDO transfers.
1 parent 5195c48 commit 32bb524

File tree

2 files changed

+143
-62
lines changed

2 files changed

+143
-62
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ set(MAX_RX_PDO "4"
106106
set(MAX_ERRORS "4"
107107
CACHE STRING "max size of error list")
108108

109-
set(SDO_TIMEOUT "100"
109+
set(SDO_TIMEOUT "200"
110110
CACHE STRING "timeout in ms for ongoing SDO transfers")
111111

112112
set(CO_THREAD_PRIO "10"

src/co_sdo_server.c

Lines changed: 142 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,7 @@ static int co_sdo_rx_upload_init_req (
162162
if (job->sdo.remain <= sizeof (job->sdo.value))
163163
{
164164
/* Object values up to 64 bits are fetched atomically */
165-
abort =
166-
co_od_get_value (net, obj, entry, job->sdo.subindex, &job->sdo.value);
165+
abort = co_od_get_value (net, obj, entry, job->sdo.subindex, &job->sdo.value);
167166
job->sdo.data = (uint8_t *)&job->sdo.value;
168167
}
169168
else
@@ -269,6 +268,48 @@ static int co_sdo_rx_upload_seg_req (
269268
return 0;
270269
}
271270

271+
static bool co_is_datatype_atomic (co_dtype_t datatype)
272+
{
273+
switch (datatype)
274+
{
275+
case DTYPE_BOOLEAN:
276+
case DTYPE_INTEGER8:
277+
case DTYPE_INTEGER16:
278+
case DTYPE_INTEGER32:
279+
case DTYPE_UNSIGNED8:
280+
case DTYPE_UNSIGNED16:
281+
case DTYPE_UNSIGNED32:
282+
case DTYPE_REAL32:
283+
case DTYPE_REAL64:
284+
case DTYPE_INTEGER64:
285+
case DTYPE_UNSIGNED64:
286+
return true;
287+
288+
case DTYPE_VISIBLE_STRING:
289+
case DTYPE_OCTET_STRING:
290+
case DTYPE_UNICODE_STRING:
291+
case DTYPE_TIME_OF_DAY:
292+
case DTYPE_TIME_DIFFERENCE:
293+
case DTYPE_DOMAIN:
294+
case DTYPE_INTEGER24:
295+
case DTYPE_INTEGER40:
296+
case DTYPE_INTEGER48:
297+
case DTYPE_INTEGER56:
298+
case DTYPE_UNSIGNED24:
299+
case DTYPE_UNSIGNED40:
300+
case DTYPE_UNSIGNED48:
301+
case DTYPE_UNSIGNED56:
302+
case DTYPE_PDO_COMM_PARAM:
303+
case DTYPE_PDO_MAPPING:
304+
case DTYPE_SDO_PARAM:
305+
case DTYPE_IDENTITY:
306+
return false;
307+
308+
default:
309+
return false;
310+
}
311+
}
312+
272313
static int co_sdo_rx_download_init_req (
273314
co_net_t * net,
274315
uint8_t node,
@@ -327,40 +368,13 @@ static int co_sdo_rx_download_init_req (
327368
return -1;
328369
}
329370

330-
job->sdo.remain = CO_BYTELENGTH (entry->bitlength);
331-
job->sdo.toggle = 0;
332-
333-
if (job->sdo.remain <= sizeof (job->sdo.value))
334-
{
335-
/* Object values up to 64 bits are cached so that we can set
336-
them atomically when the transfer is complete */
337-
job->sdo.data = (uint8_t *)&job->sdo.value;
338-
job->sdo.cached = true;
339-
}
340-
else
341-
{
342-
/* Otherwise a pointer is used to access object */
343-
abort = co_od_get_ptr (net, obj, entry, job->sdo.subindex, &job->sdo.data);
344-
if (abort)
345-
{
346-
co_sdo_abort (
347-
net,
348-
0x580 + net->node,
349-
job->sdo.index,
350-
job->sdo.subindex,
351-
abort);
352-
return -1;
353-
}
354-
}
355-
356371
/* Check for expedited download */
357372
if (type & CO_SDO_E)
358373
{
359374
size_t size = (type & CO_SDO_S) ? 4 - CO_SDO_N (type) : 4;
360-
uint32_t value;
361375

362376
/* Validate size */
363-
if (size != job->sdo.remain)
377+
if (size > CO_BYTELENGTH (entry->bitlength))
364378
{
365379
co_sdo_abort (
366380
net,
@@ -371,11 +385,35 @@ static int co_sdo_rx_download_init_req (
371385
return -1;
372386
}
373387

374-
/* Fetch value */
375-
value = co_fetch_uint32 (&data[4]);
388+
if (co_is_datatype_atomic (entry->datatype))
389+
{
390+
uint32_t value;
376391

377-
/* Atomically set value */
378-
abort = co_od_set_value (net, obj, entry, job->sdo.subindex, value);
392+
/* Fetch value */
393+
value = co_fetch_uint32 (&data[4]);
394+
395+
/* Atomically set value */
396+
abort = co_od_set_value (net, obj, entry, job->sdo.subindex, value);
397+
}
398+
else
399+
{
400+
/* Pointer is used to access object */
401+
abort = co_od_get_ptr (net, obj, entry, job->sdo.subindex, &job->sdo.data);
402+
if (abort)
403+
{
404+
co_sdo_abort (
405+
net,
406+
0x580 + net->node,
407+
job->sdo.index,
408+
job->sdo.subindex,
409+
abort);
410+
return -1;
411+
}
412+
413+
memcpy (job->sdo.data, &data[4], size);
414+
415+
co_od_notify (net, obj, entry, job->sdo.subindex, OD_NOTIFY_SDO_RECEIVED, size);
416+
}
379417

380418
/* Done */
381419
job->type = CO_JOB_NONE;
@@ -391,6 +429,46 @@ static int co_sdo_rx_download_init_req (
391429
return -1;
392430
}
393431
}
432+
else
433+
{
434+
job->sdo.total = co_fetch_uint32 (&data[4]);
435+
job->sdo.remain = job->sdo.total;
436+
437+
if (job->sdo.remain > CO_BYTELENGTH (entry->bitlength))
438+
{
439+
co_sdo_abort (
440+
net,
441+
0x580 + net->node,
442+
job->sdo.index,
443+
job->sdo.subindex,
444+
CO_SDO_ABORT_LENGTH);
445+
return -1;
446+
}
447+
job->sdo.toggle = 0;
448+
449+
if (co_is_datatype_atomic (entry->datatype))
450+
{
451+
/* Datatypes with atomic functions are cached in job->sdo.value
452+
* so they can be set atomically when the transfer is complete */
453+
job->sdo.data = (uint8_t *)&job->sdo.value;
454+
job->sdo.cached = true;
455+
}
456+
else
457+
{
458+
/* Otherwise a pointer is used to access object */
459+
abort = co_od_get_ptr (net, obj, entry, job->sdo.subindex, &job->sdo.data);
460+
if (abort)
461+
{
462+
co_sdo_abort (
463+
net,
464+
0x580 + net->node,
465+
job->sdo.index,
466+
job->sdo.subindex,
467+
abort);
468+
return -1;
469+
}
470+
}
471+
}
394472

395473
/* Dictionary has been written to and is now dirty */
396474
net->config_dirty = 1;
@@ -447,37 +525,36 @@ static int co_sdo_rx_download_seg_req (
447525
/* Write complete */
448526
job->type = CO_JOB_NONE;
449527

450-
if (job->sdo.cached)
528+
/* Find requested object */
529+
obj = co_obj_find (net, job->sdo.index);
530+
if (obj == NULL)
451531
{
452-
/* Find requested object */
453-
obj = co_obj_find (net, job->sdo.index);
454-
if (obj == NULL)
455-
{
456-
co_sdo_abort (
457-
net,
458-
0x580 + net->node,
459-
job->sdo.index,
460-
job->sdo.subindex,
461-
CO_SDO_ABORT_BAD_INDEX);
462-
return -1;
463-
}
532+
co_sdo_abort (
533+
net,
534+
0x580 + net->node,
535+
job->sdo.index,
536+
job->sdo.subindex,
537+
CO_SDO_ABORT_BAD_INDEX);
538+
return -1;
539+
}
464540

465-
/* Find requested subindex */
466-
entry = co_entry_find (net, obj, job->sdo.subindex);
467-
if (entry == NULL)
468-
{
469-
co_sdo_abort (
470-
net,
471-
0x580 + net->node,
472-
job->sdo.index,
473-
job->sdo.subindex,
474-
CO_SDO_ABORT_BAD_SUBINDEX);
475-
return -1;
476-
}
541+
/* Find requested subindex */
542+
entry = co_entry_find (net, obj, job->sdo.subindex);
543+
if (entry == NULL)
544+
{
545+
co_sdo_abort (
546+
net,
547+
0x580 + net->node,
548+
job->sdo.index,
549+
job->sdo.subindex,
550+
CO_SDO_ABORT_BAD_SUBINDEX);
551+
return -1;
552+
}
477553

554+
if (job->sdo.cached)
555+
{
478556
/* Atomically set value */
479-
abort =
480-
co_od_set_value (net, obj, entry, job->sdo.subindex, job->sdo.value);
557+
abort = co_od_set_value (net, obj, entry, job->sdo.subindex, job->sdo.value);
481558
if (abort)
482559
{
483560
co_sdo_abort (
@@ -489,6 +566,10 @@ static int co_sdo_rx_download_seg_req (
489566
return -1;
490567
}
491568
}
569+
else
570+
{
571+
co_od_notify (net, obj, entry, job->sdo.subindex, OD_NOTIFY_SDO_RECEIVED, job->sdo.total);
572+
}
492573
}
493574

494575
/* Segmented response */

0 commit comments

Comments
 (0)