@@ -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+
272313static 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