ottowayi / pycomm3

A Python Ethernet/IP library for communicating with Allen-Bradley PLCs.
MIT License
406 stars 88 forks source link

[BUG] - Bool always False when reading entire UDT struct #182

Closed dfluegge closed 3 years ago

dfluegge commented 3 years ago

Pre-checks

Description When using either v1.2.2 or v1.2.3, a bool buried within a UDT is always reading False, no matter the actual state from the PLC. If reading the bool directly plc.read('myUDT.myBool'), the correct True/False is returned. If reading as plc.read('myUDT'), the value returned inside the struct is always False.

The older release, v1.1.1, does work correctly on both read cases, so something seems to have changed after this version. (it is noted v1.1.1 has problems with writing)

I used wireshark to look at the actual messages from the plc, comparing setting the bool True vs False. The returned message byte (were the bool exists within the offset) changed as expected (changed between \01 and \03), so it seems like something to do with the parsing.

Target PLC Model: 1756-L62/B LOGIX5562 Firmware Revision: 'major': 20, 'minor': 14 Other Devices in CIP Path: 1756-EN2T

Code Sample

Additional context

dfluegge commented 3 years ago

Just some more info, here is what get_tag_info returns about the UDT. I was trying to change/read Bool state of 'SO_DIV_2.bob' or 'SO_Div_2.Module[0].Alarm_Input01'. Neither parse correct value.

get_tag_info: {'tag_name': 'SO_Div_2', 'dim': 0, 'alias': False, 'instance_id': 543, 'symbol_address': 670076, 'symbol_object_address': 4598520, 'software_control': 67227565, 'external_access': 'Read/Write', 'dimensions': [0, 0, 0], 'template_instance_id': 2011, 'data_type': {'name': 'UDT_RedLionTC1', 'internal_tags': {'Module': {'offset': 0, 'tag_type': 'struct', 'data_type': {'name': 'UDT_CSCT8ISO1', 'internal_tags': {'TC_00_DINT': {'offset': 0, 'tag_type': 'atomic', 'data_type': 'DINT', 'data_type_name': 'DINT', 'array': 0, 'type_class': DINT}, 'TC_01A_DINT': {'offset': 4, 'tag_type': 'atomic', 'data_type': 'DINT', 'data_type_name': 'DINT', 'array': 0, 'type_class': DINT}, 'TC_02_DINT': {'offset': 8, 'tag_type': 'atomic', 'data_type': 'DINT', 'data_type_name': 'DINT', 'array': 0, 'type_class': DINT}, 'TC_03_DINT': {'offset': 12, 'tag_type': 'atomic', 'data_type': 'DINT', 'data_type_name': 'DINT', 'array': 0, 'type_class': DINT}, 'TC_04_DINT': {'offset': 16, 'tag_type': 'atomic', 'data_type': 'DINT', 'data_type_name': 'DINT', 'array': 0, 'type_class': DINT}, 'TC_05_DINT': {'offset': 20, 'tag_type': 'atomic', 'data_type': 'DINT', 'data_type_name': 'DINT', 'array': 0, 'type_class': DINT}, 'TC_06_DINT': {'offset': 24, 'tag_type': 'atomic', 'data_type': 'DINT', 'data_type_name': 'DINT', 'array': 0, 'type_class': DINT}, 'TC_07_DINT': {'offset': 28, 'tag_type': 'atomic', 'data_type': 'DINT', 'data_type_name': 'DINT', 'array': 0, 'type_class': DINT}, 'TC_08_DINT': {'offset': 32, 'tag_type': 'atomic', 'data_type': 'DINT', 'data_type_name': 'DINT', 'array': 0, 'type_class': DINT}, 'TC_01_REAL': {'offset': 36, 'tag_type': 'atomic', 'data_type': 'REAL', 'data_type_name': 'REAL', 'array': 0, 'type_class': REAL}, 'TC_02_REAL': {'offset': 40, 'tag_type': 'atomic', 'data_type': 'REAL', 'data_type_name': 'REAL', 'array': 0, 'type_class': REAL}, 'TC_03_REAL': {'offset': 44, 'tag_type': 'atomic', 'data_type': 'REAL', 'data_type_name': 'REAL', 'array': 0, 'type_class': REAL}, 'TC_04_REAL': {'offset': 48, 'tag_type': 'atomic', 'data_type': 'REAL', 'data_type_name': 'REAL', 'array': 0, 'type_class': REAL}, 'TC_05_REAL': {'offset': 52, 'tag_type': 'atomic', 'data_type': 'REAL', 'data_type_name': 'REAL', 'array': 0, 'type_class': REAL}, 'TC_06_REAL': {'offset': 56, 'tag_type': 'atomic', 'data_type': 'REAL', 'data_type_name': 'REAL', 'array': 0, 'type_class': REAL}, 'TC_07_REAL': {'offset': 60, 'tag_type': 'atomic', 'data_type': 'REAL', 'data_type_name': 'REAL', 'array': 0, 'type_class': REAL}, 'TC_08_REAL': {'offset': 64, 'tag_type': 'atomic', 'data_type': 'REAL', 'data_type_name': 'REAL', 'array': 0, 'type_class': REAL}, 'ZZZZZZZZZZUDT_CSCT8I17': {'offset': 68, 'tag_type': 'atomic', 'data_type': 'SINT', 'data_type_name': 'SINT', 'array': 0, 'type_class': SINT}, 'Alarm_Input01': {'offset': 68, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 0, 'type_class': BOOL}, 'Alarm_Input02': {'offset': 68, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 1, 'type_class': BOOL}, 'Alarm_Input03': {'offset': 68, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 2, 'type_class': BOOL}, 'Alarm_Input04': {'offset': 68, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 3, 'type_class': BOOL}, 'Alarm_Input05': {'offset': 68, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 4, 'type_class': BOOL}, 'Alarm_Input06': {'offset': 68, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 5, 'type_class': BOOL}, 'Alarm_Input07': {'offset': 68, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 6, 'type_class': BOOL}, 'Alarm_Input08': {'offset': 68, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 7, 'type_class': BOOL}, 'ZZZZZZZZZZUDT_CSCT8I26': {'offset': 69, 'tag_type': 'atomic', 'data_type': 'SINT', 'data_type_name': 'SINT', 'array': 0, 'type_class': SINT}, 'ModuleStatus': {'offset': 69, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 0, 'type_class': BOOL}, 'Health': {'offset': 69, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 1, 'type_class': BOOL}}, 'attributes': ['TC_00_DINT', 'TC_01A_DINT', 'TC_02_DINT', 'TC_03_DINT', 'TC_04_DINT', 'TC_05_DINT', 'TC_06_DINT', 'TC_07_DINT', 'TC_08_DINT', 'TC_01_REAL', 'TC_02_REAL', 'TC_03_REAL', 'TC_04_REAL', 'TC_05_REAL', 'TC_06_REAL', 'TC_07_REAL', 'TC_08_REAL', 'Alarm_Input01', 'Alarm_Input02', 'Alarm_Input03', 'Alarm_Input04', 'Alarm_Input05', 'Alarm_Input06', 'Alarm_Input07', 'Alarm_Input08', 'ModuleStatus', 'Health'], 'template': {'object_definition_size': 173, 'structure_size': 72, 'member_count': 29, 'structure_handle': 14768}, '_struct_members': ([(DINT(name='TC_00_DINT'), 0), (DINT(name='TC_01A_DINT'), 4), (DINT(name='TC_02_DINT'), 8), (DINT(name='TC_03_DINT'), 12), (DINT(name='TC_04_DINT'), 16), (DINT(name='TC_05_DINT'), 20), (DINT(name='TC_06_DINT'), 24), (DINT(name='TC_07_DINT'), 28), (DINT(name='TC_08_DINT'), 32), (REAL(name='TC_01_REAL'), 36), (REAL(name='TC_02_REAL'), 40), (REAL(name='TC_03_REAL'), 44), (REAL(name='TC_04_REAL'), 48), (REAL(name='TC_05_REAL'), 52), (REAL(name='TC_06_REAL'), 56), (REAL(name='TC_07_REAL'), 60), (REAL(name='TC_08_REAL'), 64), (SINT(name='ZZZZZZZZZZUDT_CSCT8I17'), 68), (SINT(name='ZZZZZZZZZZUDT_CSCT8I26'), 69)], {'Alarm_Input01': ('ZZZZZZZZZZUDT_CSCT8I17', 544), 'Alarm_Input02': ('ZZZZZZZZZZUDT_CSCT8I17', 545), 'Alarm_Input03': ('ZZZZZZZZZZUDT_CSCT8I17', 546), 'Alarm_Input04': ('ZZZZZZZZZZUDT_CSCT8I17', 547), 'Alarm_Input05': ('ZZZZZZZZZZUDT_CSCT8I17', 548), 'Alarm_Input06': ('ZZZZZZZZZZUDT_CSCT8I17', 549), 'Alarm_Input07': ('ZZZZZZZZZZUDT_CSCT8I17', 550), 'Alarm_Input08': ('ZZZZZZZZZZUDT_CSCT8I17', 551), 'ModuleStatus': ('ZZZZZZZZZZUDT_CSCT8I26', 552), 'Health': ('ZZZZZZZZZZUDT_CSCT8I26', 553)}), 'type_class': StructTag(DINT(name='TC_00_DINT'), DINT(name='TC_01A_DINT'), DINT(name='TC_02_DINT'), DINT(name='TC_03_DINT'), DINT(name='TC_04_DINT'), DINT(name='TC_05_DINT'), DINT(name='TC_06_DINT'), DINT(name='TC_07_DINT'), DINT(name='TC_08_DINT'), REAL(name='TC_01_REAL'), REAL(name='TC_02_REAL'), REAL(name='TC_03_REAL'), REAL(name='TC_04_REAL'), REAL(name='TC_05_REAL'), REAL(name='TC_06_REAL'), REAL(name='TC_07_REAL'), REAL(name='TC_08_REAL'), SINT(name='ZZZZZZZZZZUDT_CSCT8I17'), SINT(name='ZZZZZZZZZZUDT_CSCT8I26'), bool_members={'Alarm_Input01': ('ZZZZZZZZZZUDT_CSCT8I17', 544), 'Alarm_Input02': ('ZZZZZZZZZZUDT_CSCT8I17', 545), 'Alarm_Input03': ('ZZZZZZZZZZUDT_CSCT8I17', 546), 'Alarm_Input04': ('ZZZZZZZZZZUDT_CSCT8I17', 547), 'Alarm_Input05': ('ZZZZZZZZZZUDT_CSCT8I17', 548), 'Alarm_Input06': ('ZZZZZZZZZZUDT_CSCT8I17', 549), 'Alarm_Input07': ('ZZZZZZZZZZUDT_CSCT8I17', 550), 'Alarm_Input08': ('ZZZZZZZZZZUDT_CSCT8I17', 551), 'ModuleStatus': ('ZZZZZZZZZZUDT_CSCT8I26', 552), 'Health': ('ZZZZZZZZZZUDT_CSCT8I26', 553)}, host_members={'ZZZZZZZZZZUDT_CSCT8I17': SINT, 'ZZZZZZZZZZUDT_CSCT8I26': SINT}, struct_size=72)}, 'data_type_name': 'UDT_CSCT8ISO1', 'array': 10, 'type_class': StructTag(DINT(name='TC_00_DINT'), DINT(name='TC_01A_DINT'), DINT(name='TC_02_DINT'), DINT(name='TC_03_DINT'), DINT(name='TC_04_DINT'), DINT(name='TC_05_DINT'), DINT(name='TC_06_DINT'), DINT(name='TC_07_DINT'), DINT(name='TC_08_DINT'), REAL(name='TC_01_REAL'), REAL(name='TC_02_REAL'), REAL(name='TC_03_REAL'), REAL(name='TC_04_REAL'), REAL(name='TC_05_REAL'), REAL(name='TC_06_REAL'), REAL(name='TC_07_REAL'), REAL(name='TC_08_REAL'), SINT(name='ZZZZZZZZZZUDT_CSCT8I17'), SINT(name='ZZZZZZZZZZUDT_CSCT8I26'), bool_members={'Alarm_Input01': ('ZZZZZZZZZZUDT_CSCT8I17', 544), 'Alarm_Input02': ('ZZZZZZZZZZUDT_CSCT8I17', 545), 'Alarm_Input03': ('ZZZZZZZZZZUDT_CSCT8I17', 546), 'Alarm_Input04': ('ZZZZZZZZZZUDT_CSCT8I17', 547), 'Alarm_Input05': ('ZZZZZZZZZZUDT_CSCT8I17', 548), 'Alarm_Input06': ('ZZZZZZZZZZUDT_CSCT8I17', 549), 'Alarm_Input07': ('ZZZZZZZZZZUDT_CSCT8I17', 550), 'Alarm_Input08': ('ZZZZZZZZZZUDT_CSCT8I17', 551), 'ModuleStatus': ('ZZZZZZZZZZUDT_CSCT8I26', 552), 'Health': ('ZZZZZZZZZZUDT_CSCT8I26', 553)}, host_members={'ZZZZZZZZZZUDT_CSCT8I17': SINT, 'ZZZZZZZZZZUDT_CSCT8I26': SINT}, struct_size=72)[10]}, 'ZZZZZZZZZZUDT_RedLio1': {'offset': 720, 'tag_type': 'atomic', 'data_type': 'SINT', 'data_type_name': 'SINT', 'array': 0, 'type_class': SINT}, 'Health': {'offset': 720, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 0, 'type_class': BOOL}, 'bob': {'offset': 720, 'tag_type': 'atomic', 'data_type': 'BOOL', 'data_type_name': 'BOOL', 'bit': 1, 'type_class': BOOL}}, 'attributes': ['Module', 'Health', 'bob'], 'template': {'object_definition_size': 30, 'structure_size': 724, 'member_count': 4, 'structure_handle': 19111}, '_struct_members': ([(StructTag(DINT(name='TC_00_DINT'), DINT(name='TC_01A_DINT'), DINT(name='TC_02_DINT'), DINT(name='TC_03_DINT'), DINT(name='TC_04_DINT'), DINT(name='TC_05_DINT'), DINT(name='TC_06_DINT'), DINT(name='TC_07_DINT'), DINT(name='TC_08_DINT'), REAL(name='TC_01_REAL'), REAL(name='TC_02_REAL'), REAL(name='TC_03_REAL'), REAL(name='TC_04_REAL'), REAL(name='TC_05_REAL'), REAL(name='TC_06_REAL'), REAL(name='TC_07_REAL'), REAL(name='TC_08_REAL'), SINT(name='ZZZZZZZZZZUDT_CSCT8I17'), SINT(name='ZZZZZZZZZZUDT_CSCT8I26'), bool_members={'Alarm_Input01': ('ZZZZZZZZZZUDT_CSCT8I17', 544), 'Alarm_Input02': ('ZZZZZZZZZZUDT_CSCT8I17', 545), 'Alarm_Input03': ('ZZZZZZZZZZUDT_CSCT8I17', 546), 'Alarm_Input04': ('ZZZZZZZZZZUDT_CSCT8I17', 547), 'Alarm_Input05': ('ZZZZZZZZZZUDT_CSCT8I17', 548), 'Alarm_Input06': ('ZZZZZZZZZZUDT_CSCT8I17', 549), 'Alarm_Input07': ('ZZZZZZZZZZUDT_CSCT8I17', 550), 'Alarm_Input08': ('ZZZZZZZZZZUDT_CSCT8I17', 551), 'ModuleStatus': ('ZZZZZZZZZZUDT_CSCT8I26', 552), 'Health': ('ZZZZZZZZZZUDT_CSCT8I26', 553)}, host_members={'ZZZZZZZZZZUDT_CSCT8I17': SINT, 'ZZZZZZZZZZUDT_CSCT8I26': SINT}, struct_size=72)10, 0), (SINT(name='ZZZZZZZZZZUDT_RedLio1'), 720)], {'Health': ('ZZZZZZZZZZUDT_RedLio1', 5760), 'bob': ('ZZZZZZZZZZUDT_RedLio1', 5761)}), 'type_class': StructTag(StructTag(DINT(name='TC_00_DINT'), DINT(name='TC_01A_DINT'), DINT(name='TC_02_DINT'), DINT(name='TC_03_DINT'), DINT(name='TC_04_DINT'), DINT(name='TC_05_DINT'), DINT(name='TC_06_DINT'), DINT(name='TC_07_DINT'), DINT(name='TC_08_DINT'), REAL(name='TC_01_REAL'), REAL(name='TC_02_REAL'), REAL(name='TC_03_REAL'), REAL(name='TC_04_REAL'), REAL(name='TC_05_REAL'), REAL(name='TC_06_REAL'), REAL(name='TC_07_REAL'), REAL(name='TC_08_REAL'), SINT(name='ZZZZZZZZZZUDT_CSCT8I17'), SINT(name='ZZZZZZZZZZUDT_CSCT8I26'), bool_members={'Alarm_Input01': ('ZZZZZZZZZZUDT_CSCT8I17', 544), 'Alarm_Input02': ('ZZZZZZZZZZUDT_CSCT8I17', 545), 'Alarm_Input03': ('ZZZZZZZZZZUDT_CSCT8I17', 546), 'Alarm_Input04': ('ZZZZZZZZZZUDT_CSCT8I17', 547), 'Alarm_Input05': ('ZZZZZZZZZZUDT_CSCT8I17', 548), 'Alarm_Input06': ('ZZZZZZZZZZUDT_CSCT8I17', 549), 'Alarm_Input07': ('ZZZZZZZZZZUDT_CSCT8I17', 550), 'Alarm_Input08': ('ZZZZZZZZZZUDT_CSCT8I17', 551), 'ModuleStatus': ('ZZZZZZZZZZUDT_CSCT8I26', 552), 'Health': ('ZZZZZZZZZZUDT_CSCT8I26', 553)}, host_members={'ZZZZZZZZZZUDT_CSCT8I17': SINT, 'ZZZZZZZZZZUDT_CSCT8I26': SINT}, struct_size=72)10, SINT(name='ZZZZZZZZZZUDT_RedLio1'), bool_members={'Health': ('ZZZZZZZZZZUDT_RedLio1', 5760), 'bob': ('ZZZZZZZZZZUDT_RedLio1', 5761)}, host_members={'ZZZZZZZZZZUDT_RedLio1': SINT}, struct_size=724)}, 'data_type_name': 'UDT_RedLionTC1', 'tag_type': 'struct', 'type_class': StructTag(StructTag(DINT(name='TC_00_DINT'), DINT(name='TC_01A_DINT'), DINT(name='TC_02_DINT'), DINT(name='TC_03_DINT'), DINT(name='TC_04_DINT'), DINT(name='TC_05_DINT'), DINT(name='TC_06_DINT'), DINT(name='TC_07_DINT'), DINT(name='TC_08_DINT'), REAL(name='TC_01_REAL'), REAL(name='TC_02_REAL'), REAL(name='TC_03_REAL'), REAL(name='TC_04_REAL'), REAL(name='TC_05_REAL'), REAL(name='TC_06_REAL'), REAL(name='TC_07_REAL'), REAL(name='TC_08_REAL'), SINT(name='ZZZZZZZZZZUDT_CSCT8I17'), SINT(name='ZZZZZZZZZZUDT_CSCT8I26'), bool_members={'Alarm_Input01': ('ZZZZZZZZZZUDT_CSCT8I17', 544), 'Alarm_Input02': ('ZZZZZZZZZZUDT_CSCT8I17', 545), 'Alarm_Input03': ('ZZZZZZZZZZUDT_CSCT8I17', 546), 'Alarm_Input04': ('ZZZZZZZZZZUDT_CSCT8I17', 547), 'Alarm_Input05': ('ZZZZZZZZZZUDT_CSCT8I17', 548), 'Alarm_Input06': ('ZZZZZZZZZZUDT_CSCT8I17', 549), 'Alarm_Input07': ('ZZZZZZZZZZUDT_CSCT8I17', 550), 'Alarm_Input08': ('ZZZZZZZZZZUDT_CSCT8I17', 551), 'ModuleStatus': ('ZZZZZZZZZZUDT_CSCT8I26', 552), 'Health': ('ZZZZZZZZZZUDT_CSCT8I26', 553)}, host_members={'ZZZZZZZZZZUDT_CSCT8I17': SINT, 'ZZZZZZZZZZUDT_CSCT8I26': SINT}, struct_size=72)10, SINT(name='ZZZZZZZZZZUDT_RedLio1'), bool_members={'Health': ('ZZZZZZZZZZUDT_RedLio1', 5760), 'bob': ('ZZZZZZZZZZUDT_RedLio1', 5761)}, host_members={'ZZZZZZZZZZUDT_RedLio1': SINT}, struct_size=724)}

ottowayi commented 3 years ago

shit, I'm betting this is related to the fix in 1.2.2 for AOIs with >8 BOOLs not being mapped correctly. I thought I added enough test cases to make sure it works, but looks like I missed something. I'll look into it

dfluegge commented 3 years ago

The cool thing is the new version can read another AOI that I'm using which used to complain about parsing in past versions. So the toolkit is progressing in the right direction! Awesome toolkit by the way!

ottowayi commented 3 years ago

Thanks, it's just these damn BOOLs keep making things really complicated. So the 'fix' was because UDTs always map bools to a SINT and just adds more when needed, where as AOIs will use larger INTs or DINTs if needed. Something was missed in the offset calculations which may take me a while to find.

dfluegge commented 3 years ago

Let me know if you need any log info

ottowayi commented 3 years ago

I think I may have fixed it, if you want to try it out I pushed the fix to the develop branch. I'm still doing some testing and need to add more test cases to the PLC program, but if this works I can put out a new release right away.

dfluegge commented 3 years ago

I've done a bunch of spot testing and everything seems to be working now. I tried R/W to various datatypes throughout the UDT, and all worked correctly. Thank you.

ottowayi commented 3 years ago

great! I'll put out a new release this afternoon

ottowayi commented 3 years ago

fixed in 1.2.4