CANopenNode: SDO Block Transfer

Hallo, I have a problem. I want to to use Object 0x1021 to store my eds file directly in the device firmware. To upload the file I use the follwing code:

const unsigned long eds_file_length = 0x00010A32;
const unsigned char eds_file[0x00010A32] = {};
static CO_SDO_abortCode_t CO_ODF_eds_file(CO_ODF_arg_t *ODF_arg)
{
    if (ODF_arg->reading)
    {
        if (ODF_arg->firstSegment)
            ODF_arg->dataLengthTotal = eds_file_length;

    	uint32_t remaining = ODF_arg->dataLengthTotal - ODF_arg->offset;

        if (remaining <= ODF_arg->dataLength)
        {
            ODF_arg->dataLength = remaining;
            ODF_arg->lastSegment = true;
        }
        else
            ODF_arg->lastSegment = false;

        

        memcpy(ODF_arg->data, &eds_file[ODF_arg->offset], ODF_arg->dataLength);

    }
    return CO_SDO_AB_NONE;
}

In segmented mode this works fine but in block transfer I get either : [0] ERROR:0x06070012 #Data type does not match, length of service parameter too high. or an CRC error when I do not set the explicit size. Could someone please check if the code is theoretically suitable for block transfer and if so whether the same error occurs in practice as with me?

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 20 (18 by maintainers)

Most upvoted comments

Finally SDO block transfer was systematically tested with different interfaces on real wires.

There was actually a problem with Linux socketCAN driver with CO_CANsend() function. When there was transmitted sequence of data (127 CAN messages in sequence), it happend, that Linux system socket for CAN tx was full and message was dropped. SDO block transfer is robust, so this was not always the problem. Linux driver was unclear at this point from the beginning.

CANopenNode uses CO_CANsend() without checking it’s return status, which is intended. If CO_CANsend() fails in the moment of call, missed message is marked with bufferFull flag (for each CANopen object separately). Missed message is sent later, after CANtx becomes available. In microcontrollers this is usually implemented with interrupts, but this was not possible in Linux.

However, now CO_CANsend() in Linux works according to the original principle: missed CANtx messages are marked with bufferFull flag. Then CO_CANmodule_process() tries to resend them automatically.

SDO server and SDO client wait, if bufferFull flag is set, so transmitting SDO sub-block now works without errors and without time delays.

I tested different CAN interfaces: PCAN-USB and CPC-USB works without detected errors. But cheap USBtin (slcand) doesn’t work well with block transfer (segmented transfer works always).

I tested newOD branch in all aspects. Current master (v2.0) has almost the same driver, epoll interface (which was widely renewed in v2.0) and SDO client and that was tested too. SDO server in v2.0 is quite the same as in v1.3 and was not tested.

There are automatic tests for running CANopen devices, for test results see: https://github.com/CANopenNode/CANopenSocket/blob/master/test/test_report.md