Skip to content

SDO OCTET_STRING is changed to DOMAIN when saving the xdd file. #221

Open

Description

@henri62

Describe the bug
If I enter an SDO with OCTED_STRING, save it and later open it, it is changed to DOMAIN!

To Reproduce

  1. Create an SDO with a data type OCTET_STRING and save the xdd file.
  2. Close the project and reopen it.
  3. The SDO data type has been changed to "DOMAIN".

Version used
4.2.3-*

Expected behavior
It shall still keep the original definition "OCTET_STRING".

Activity

  1. trojanobelix commented on Jun 12, 2026

    @trojanobelix
    Collaborator
    Image

    Were you able to reproduce the bug with “our” version 2.4.xx? I couldn't!?

  2. henri62 commented on Jun 12, 2026

    @henri62
    Author

    Both the version you can download and the version you sent me with the 0 byte mapping fix. #220
    Maybe set access PDO to yes or something?

  3. trojanobelix commented on Jun 12, 2026

    @trojanobelix
    Collaborator

    The easiest thing is always when I get an xdd file that lets me reproduce the error. That way, I don't have to go digging around to figure out your current settings.

  4. trojanobelix commented on Jun 13, 2026

    @trojanobelix
    Collaborator

    Dig into that and found out: To reproduce the default value of an OCTET_STRING must be empty in CANopenNodeEditor.

    In private DataType ConvertDataType(Items1ChoiceType choiceType, string defaultValue)

    the case for BITSTRING

    case Items1ChoiceType.BITSTRING: return defaultValue == "" ? DataType.DOMAIN : DataType.OCTET_STRING;

    With a valid default value of “”, which is permitted for OCTET_STRING, a valid OCTET_STRING is converted to DOMAIN.
    In my opinion, there is not enough information to determine whether BITSTRING is a DOMAIN or an OCTET_STRING type.

    A workaround is to set a default value, which is a good idea if the object is indeed intended to hold an OCTET_STRING. Maybe @nimrof or @CANopenNode can give more details to this problem.

  5. henri62 commented on Jun 15, 2026

    @henri62
    Author

    Sorry about not posting a file, I thought it was clear to reproduce.

    About the cause you found: Why would a type be converted? It is something the user sets/wants, when you set a specific "Data Type" for an SDO I want this specific type. It shall not change spontanously, despite the content. For TPDO's a default value is even not relevant (actually I think all SDO defaults are never used?).

    So I don't see the relevance why is is suddenly converted to anything else. Can you explain the issue what is underlying to this problem?

    When I do (C) programming with variables that may contain different types I define a struct called "Variant" containing the type (num) and a union with all possible types, so you do not lose the definition during processing. In C++ or C# it is even simpeler to create a class called "Variant" with all its methods and its operator overloads.

    By the way, filling in the default string with a '-' indeed avoids the spontanous change when saved.

    -edit-
    Using an OCTET_STRING in a TPDO seems weird, I want you to explain the use case:
    We need to implement a controller that listens to messages on the CAN bus where a slave device sends its version string every 5 seconds on a predefined COB-ID.
    In normal cases you would do an SDO read on the object where this string is defined, but its a master-less system (CleanOpen variant of CanOpen, See CiA422). So the device manufacturer decided to send a message every 5 seconds on a fixed COB-ID (0x1E2).
    So to be able to receive that with the CanOpenNode stack (or any other CanOpen device) without customisation, I created an SDO with the STRING_OCTET on a manufacturer specific index (0x2000) and an associated TPDO with the given COB-ID.
    The export the XDD an EDS and import it in the application that receives the CAN messages.

    In the previous version I simply used an array of UNSIGNED8 bytes in the SDO 0x2000 with 8 subindices and mapped the TPDO to these 8 UNSIGNED8 subindices, but it is cumbersome. It should be possible to do that in one go.

  6. henri62 commented on Jun 15, 2026

    @henri62
    Author

    I just looked into the function private DataType ConvertDataType(Items1ChoiceType choiceType, string defaultValue) and I think the Items1ChoiceType is the actual type of the edit field from .NET? Is that correct?
    But the returned data type should not be dependent on the native type of the "Default Value field" but be taken from the field "Object Type" the user entered.
    If there is an inconsistency in those, aka the "default value" field cannot be converted to the wanted type, I would expect an error when you save the SDO.

    Maybe that is also the reason why the TIME_OF_DAY, INTEGER48 and that kinds of types are missing/partly supported?

  7. henri62 commented on Jun 15, 2026

    @henri62
    Author

    I just found another issue for me, when I export the file with File ->Export CanOpenNode it gives an error:

    Error in 0x2000: Error converting default value - to type OCTET_STRING

    This was with '-' in the default value.

    I just read the actual definition of an OCTET_STRING "A sequential collection (array) of UNSIGNED8 values of varying length. This allows sequences of 8-bit values to be used, for example storing binary data."

    The question is what to do if you encounter a string in the default value? Convert it to a sequence of UNSIGNED8 values or give an error?

    What is more of an interest is that you may enter any value in different formats, as stated in CiA 306-1 (eds spec): These entries for any value are identical (for a value key):
    keyname=10
    keyname=0xa
    keyname=0x0a
    keyname=0xA
    keyname=0x000A
    keyname=012

    Now the fun part for OCTET_STRING, this is an allowed sequence (and shall be converted to a UNSIGNED8 sequence):
    DemoSeq=01a1053c45aabbccdd
    But this also crashes the OD.c/h export:
    Error in 0x2000: Error converting default value 01a1053c45aabbcc to type OCTET_STRING

    For a bit string this is a valid one:
    BitDemo=11001010000111
    But with the current implementation you cannot distinguish what it is, it could also be an array of bytes with the values: 11 00 10 10 00 01 11

  8. trojanobelix commented on Jun 15, 2026

    @trojanobelix
    Collaborator

    project (2).zip

    Sorry, I'm not familiar with the data model in detail.

    From what I've gathered, this won't work:

    if (devPar.Items1 != null && devPar.Items1ElementName != null)
    od.datatype = ConvertDataType(devPar.Items1ElementName[0], od.defaultvalue);

    At this point, the importer does not yet know the actual data type.
    Items1ElementName[0] is NOT the data type from …,
    but only the XML container type from the CiA-15745 schema.

    And this container type is:

    OCTET_STRING → BITSTRING

    DOMAIN → BITSTRING

    This means:

    So ConvertDataType() can never determine at this point whether it is DOMAIN or OCTET_STRING.

    But as I said: I’m not familiar with the data model in detail. Perhaps others will provide additional details.

    You can create a octal string objext e.g. 0x2000 with default value <<<01 02 03 04 05 0A 0B>>> (without <<< >>>)
    Just the values

    Then you get:

    OD.c
    OD_ATTR_RAM OD_RAM_t OD_RAM = {
    .x2000_octString = {0x01, 0x02, 0x03, 0x04, 0x05, 0x0A, 0x0B}
    };

    OD.h
    typedef struct {
    uint8_t x2000_octString[7];
    } OD_RAM_t;

    01a1053c45aabbccdd is not interpreted as OCTET_STRING, but should be imho. That needs some polish.

    Hope that helps

  9. henri62 commented on Jun 17, 2026

    @henri62
    Author

    Can you explain to me what is ment by "importer"? I would associate this with some file import but we're not talking about that, so probably in this context you mean something else?

  10. trojanobelix commented on Jun 17, 2026

    @trojanobelix
    Collaborator

    Importer just means the workflow when open a file (read, parse, ...)

  11. henri62 commented on Jun 17, 2026

    @henri62
    Author

    Ok clear, that means that the importer should look to the original type definition, not the content of the value itself.
    (Ofcourse if the value does not apply to the type syntax there is something serously wrong)

    The snippet in the xdd file now diplays this:

     <q1:parameter uniqueID="UID_OBJ_2000" access="readWrite">
        <label lang="en">Software number</label>
        <BITSTRING />
     <q1:defaultValue value="0" />
     </q1:parameter>
    

    This should have been something like OCTETSTRING. To solve this, I think it may have too much impact? Maybe take this into consideration for the new GUI2 editor and its underlying formats?

  12. Owen-Lynch474 commented on Aug 20, 2026

    @Owen-Lynch474

    A related problem is changing type to DOMAIN is not reflected in xdd:

    Image

    xdd:
    <q1:varDeclaration name="Program Data" uniqueID="UID_RECSUB_1F5001"> <BITSTRING /> </q1:varDeclaration>

  13. henri62 commented on Aug 21, 2026

    @henri62
    Author

    What I understood is that when the data is read from the xdd file it is converted to the actual CanOpen type based on content instead of using the actual type that is in the xdd.

    I think that approach is not the way it should be done: The conversion can be ambiguous. For example when the xdd contains a simple string it could be an BIT or an OCTET string or even a simple number.

    So if you read "01a1053c45aabbccdd" what type should that be? You cannot guess that on content.
    See also the post of "trojanobelix" and some examples I wrote above.

    So the reader that builds the variable/object tree shall use the real type what is in the xdd (and if that is not saved, somewher, the type shall be added) then crreate obects/variables from it. If a conversion is not possible, the xdd is apparently corrupt and the application shall give a descent error message which/what is wrong in the saved file.
    This makes the implementation even simpler to my opinion.

    I hope this method is used in the new protobuffer implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions