stlehmann / pyads

Python wrapper for TwinCAT ADS
MIT License
254 stars 94 forks source link

Issue reading arrays of strings #405

Open AliceJoby opened 1 month ago

AliceJoby commented 1 month ago

If there's an array of strings in the PLC, pyads will miss reading the extra byte needed for strings and won't be able to read past the first item in the array. Ex. PLC has Array [0..10] of STRING(20) pyads will parse the datatype from the PLC and determine the datatype to be pyads.symbol.c_char_Array_20_Array_10, which is correct. However, when determining the number of bytes needed to be read and reading the array, only 20 bytes will be read of the first array. Strings have an extra byte that need to be read. As a result, the last byte of the first item will become the first byte of the second item in the array, messing up the decoding.

If I put a breakpoint at https://github.com/stlehmann/pyads/blob/master/pyads/structs.py#L332 and modify the PLC datatype to be Array [0..10] of STRING(21), then the array will be read correctly.

chrisbeardy commented 1 month ago

Thanks for this, there defo seems to be a bug here, effects both symbol reading and read_by_name, whether you pass type in or not, although if you do pass type in then you seem to only get back the first index of the array but decoded correctly, if you don't pass the type in you get back an array of c_char_Array_20 objects.

chrisbeardy commented 1 month ago

looks linked / duplicate of #356 @AliceJoby there is a workaround in #356 if you need it while i fix the issue

chrisbeardy commented 2 weeks ago

@RobertoRoos fancy taking a look at this? looks like #410 may have a simlar fix?

RobertoRoos commented 1 day ago

Yeah, I'm having a look now.

I can reproduce this with the plc code:

VAR_GLOBAL
    // Sizes according to `SIZEOF()`:
    list_of_strings         : ARRAY[0..9] OF STRING;            // 810
END_VAR

and Python code:

    with Connection(ams_net_id="127.0.0.1.1.1", ams_net_port=851) as plc:
        list_of_strings = plc.read_by_name("GVL_Example.list_of_strings")

    for item in list_of_strings:
        txt = item.value.decode()
        print(txt)