pjkundert / cpppo

Communications Protocol Python Parser and Originator -- EtherNet/IP CIP
https://hardconsulting.com/products/6-cpppo-enip-api
Other
332 stars 109 forks source link

Rockwell Get Attribute Client #21

Closed jonathans56 closed 7 years ago

jonathans56 commented 8 years ago

I am using a Softlogix 5800 EtherNet/IP controller and ENIP card:

When trying to get/query tags I am getting a none (get_attribute) or non-zero (enip_client) status. I have been reviewing the readme for weeks and I still cannot understand what I am missing. I believe the SoftLogix controller only supports "Unconnected" requests (can someone verify?), so using the enip_client may not be an option. If this is the case I am not sure what the proper class/instance/attribute settings are for the get_attribute.

I would extremely appreciate any help here as I have been banging my head against the desk on this one.

Using Client:

python -m cpppo.server.enip.client -i -a 192.168.159.140 "Pump1" -vv 08-15 14:33:43.049 MainThread enip.cli DETAIL init Connect: TCP/IP to ('192.168.159.140', 44818) 08-15 14:33:43.118 MainThread enip.cli DETAIL cip_send Client CIP Send: { "enip.status": 0, "enip.sender_context.input": "bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00')", "enip.session_handle": 0, "enip.CIP.register.protocol_version": 1, "enip.CIP.register.options": 0, "enip.options": 0 } 08-15 14:33:43.125 MainThread enip.cli NORMAL init Connect: Success in 0.077s/ 5.000s 08-15 14:33:43.128 MainThread enip.cli DETAIL main Client Register Rcvd 0.079/ 5.000s 08-15 14:33:43.131 MainThread enip.cli DETAIL cip_send Client CIP Send: { "enip.status": 0, "enip.sender_context.input": "bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00')", "enip.session_handle": 2147614721, "enip.CIP.list_identity": {}, "enip.options": 0 } List Identity 0 from ('192.168.159.140', 44818): { "count": 1, "item[0].length": 59, "item[0].identity_object.sin_addr": "192.168.159.140", "item[0].identity_object.status_word": 48, "item[0].identity_object.vendor_id": 1, "item[0].identity_object.product_name": "SoftLogix5800 EtherNet/IP", "item[0].identity_object.sin_port": 9216, "item[0].identity_object.state": 3, "item[0].identity_object.version": 1, "item[0].identity_object.device_type": 12, "item[0].identity_object.sin_family": -18818, "item[0].identity_object.serial_number": 1881467854, "item[0].identity_object.product_code": 135, "item[0].identity_object.product_revision": 277, "item[0].type_id": 12 } 08-15 14:33:43.157 MainThread enip.cli DETAIL parse_oper Tag: 'Pump1' yields Operation: {'path': [{'symbolic': 'Pump1'}]}.update({'route_path': None, 'send_path': None}) 08-15 14:33:43.161 MainThread enip.cli DETAIL cip_send Client CIP Send: { "enip.status": 0, "enip.sender_context.input": "bytearray(b'0\x00\x00\x00\x00\x00\x00\x00')", "enip.session_handle": 2147614721, "enip.CIP.send_data.interface": 0, "enip.CIP.send_data.CPF.item[0].type_id": 0, "enip.CIP.send_data.CPF.item[1].unconnected_send.status": 0, "enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].link": 0, "enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].port": 1, "enip.CIP.send_data.CPF.item[1].unconnected_send.service": 82, "enip.CIP.send_data.CPF.item[1].unconnected_send.timeout_ticks": 157, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[0].symbolic": "Pump1", "enip.CIP.send_data.CPF.item[1].unconnected_send.request.read_tag.elements": 1, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 76, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "bytearray(b'L\x04\x91\x05Pump1\x00\x01\x00')", "enip.CIP.send_data.CPF.item[1].unconnected_send.priority": 5, "enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[0].class": 6, "enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[1].instance": 1, "enip.CIP.send_data.CPF.item[1].type_id": 178, "enip.CIP.send_data.timeout": 0, "enip.options": 0 } 08-15 14:33:43.168 MainThread enip.cli DETAIL format_pat Formatted Pump1 from: [{'symbolic': 'Pump1'}] 08-15 14:33:43.171 MainThread enip.cli DETAIL issue Sent 0.010/ 5.000s: Single Read Tag Pump1 { "path.segment[0].symbolic": "Pump1", "read_tag.elements": 1, "service": 76, "input": "bytearray(b'L\x04\x91\x05Pump1\x00\x01\x00')" } 08-15 14:33:43.171 MainThread enip.cli DETAIL issue Sending 1 (Context '0') 08-15 14:33:43.174 MainThread enip.cli DETAIL pipeline Issuing 0/ 1; curr: 0 - last: -1 == 1 depth 08-15 14:33:43.186 MainThread enip.cli DETAIL collect Rcvd 0.010/ 5.000s { "peer": [ "192.168.159.140", 44818 ], "enip.status": 0, "enip.sender_context.input": "array('c', '0\x00\x00\x00\x00\x00\x00\x00')", "enip.session_handle": 2147614721, "enip.length": 20, "enip.CIP.send_data.interface": 0, "enip.CIP.send_data.CPF.count": 2, "enip.CIP.send_data.CPF.item[0].length": 0, "enip.CIP.send_data.CPF.item[0].type_id": 0, "enip.CIP.send_data.CPF.item[1].length": 4, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.status": 8, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "array('c', '\xcc\x00\x08\x00')", "enip.CIP.send_data.CPF.item[1].unconnected_send.request.status_ext.size": 0, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.read_tag": true, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 204, "enip.CIP.send_data.CPF.item[1].type_id": 178, "enip.CIP.send_data.timeout": 0, "enip.command": 111, "enip.input": "array('c', '\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x04\x00\xcc\x00\x08\x00')", "enip.options": 0 } 08-15 14:33:43.197 MainThread enip.cli DETAIL collect Receive 1 (Context '0') 08-15 14:33:43.200 MainThread enip.cli DETAIL pipeline Completed 1/ 1; curr: 0 - last: 0 == 0 depth 08-15 14:33:43.200 MainThread enip.cli DETAIL validate Client Single Read Tag Pump1 Request: { "path.segment[0].symbolic": "Pump1", "read_tag.elements": 1, "service": 76, "input": "bytearray(b'L\x04\x91\x05Pump1\x00\x01\x00')" } 08-15 14:33:43.203 MainThread enip.cli DETAIL validate Yields Reply: { "status": 8, "input": "array('c', '\xcc\x00\x08\x00')", "status_ext.size": 0, "read_tag": true, "service": 204 } 08-15 14:33:43.207 MainThread enip.cli DETAIL format_pat Formatted Pump1 from: [{'symbolic': 'Pump1'}] 08-15 14:33:43.210 MainThread enip.cli WARNING validate Client Single Read Tag Pump1 returned non-zero status: Status 8 08-15 14:33:43.210 MainThread enip.cli NORMAL validate Pump1 == None: 'Status 8 ' Pump1 == None: 'Status 8 ' 08-15 14:33:43.211 MainThread enip.cli DETAIL pipeline Pipelined 1/ 1; curr: 0 - last: 0 == 0 depth 08-15 14:33:43.213 MainThread enip.cli NORMAL main Client Tag I/O Average 17.910 TPS ( 0.056s ea).

Using Get_Attributes:

$ python -m cpppo.server.enip.get_attribute 'Pump1' -a 192.168.159.140 -vv 08-15 14:21:40.471 MainThread enip.cli DETAIL init Connect: TCP/IP to ('192.168.159.140', 44818) 08-15 14:21:40.540 MainThread enip.cli DETAIL cip_send Client CIP Send: { "enip.status": 0, "enip.sender_context.input": "bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00')", "enip.session_handle": 0, "enip.CIP.register.protocol_version": 1, "enip.CIP.register.options": 0, "enip.options": 0 } 08-15 14:21:40.549 MainThread enip.cli NORMAL init Connect: Success in 0.079s/ 5.000s 08-15 14:21:40.552 MainThread enip.cli DETAIL parse_oper Tag: "'Pump1'" yields Operation: {'path': [{'symbolic': "'Pump1'"}]}.update({'route_path': None, 'send_path': None}) 08-15 14:21:40.553 MainThread enip.cli DETAIL cip_send Client CIP Send: { "enip.status": 0, "enip.sender_context.input": "bytearray(b'0\x00\x00\x00\x00\x00\x00\x00')", "enip.session_handle": 2147614721, "enip.CIP.send_data.interface": 0, "enip.CIP.send_data.CPF.item[0].type_id": 0, "enip.CIP.send_data.CPF.item[1].unconnected_send.status": 0, "enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].link": 0, "enip.CIP.send_data.CPF.item[1].unconnected_send.route_path.segment[0].port": 1, "enip.CIP.send_data.CPF.item[1].unconnected_send.service": 82, "enip.CIP.send_data.CPF.item[1].unconnected_send.timeout_ticks": 157, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[0].symbolic": "'Pump1'", "enip.CIP.send_data.CPF.item[1].unconnected_send.request.get_attribute_single": true, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 14, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "bytearray(b\"\x0e\x05\x91\x07\'Pump1\'\x00\")", "enip.CIP.send_data.CPF.item[1].unconnected_send.priority": 5, "enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[0].class": 6, "enip.CIP.send_data.CPF.item[1].unconnected_send.path.segment[1].instance": 1, "enip.CIP.send_data.CPF.item[1].type_id": 178, "enip.CIP.send_data.timeout": 0, "enip.options": 0 } 08-15 14:21:40.561 MainThread enip.cli DETAIL format_pat Formatted 'Pump1' from: [{'symbolic': "'Pump1'"}] 08-15 14:21:40.562 MainThread enip.cli DETAIL issue Sent 0.007/ 5.000s: Single G_A_S 'Pump1' { "path.segment[0].symbolic": "'Pump1'", "get_attribute_single": true, "service": 14, "input": "bytearray(b\"\x0e\x05\x91\x07\'Pump1\'\x00\")" } 08-15 14:21:40.565 MainThread enip.cli DETAIL issue Sending 1 (Context '0') 08-15 14:21:40.565 MainThread enip.cli DETAIL pipeline Issuing 0/ 1; curr: 0 - last: -1 == 1 depth 08-15 14:21:40.581 MainThread enip.cli DETAIL collect Rcvd 0.014/ 5.000s { "peer": [ "192.168.159.140", 44818 ], "enip.status": 0, "enip.sender_context.input": "array('c', '0\x00\x00\x00\x00\x00\x00\x00')", "enip.session_handle": 2147614721, "enip.length": 22, "enip.CIP.send_data.interface": 0, "enip.CIP.send_data.CPF.count": 2, "enip.CIP.send_data.CPF.item[0].length": 0, "enip.CIP.send_data.CPF.item[0].type_id": 0, "enip.CIP.send_data.CPF.item[1].length": 6, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.status": 4, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "array('c', '\x8e\x00\x04\x01\x00\x00')", "enip.CIP.send_data.CPF.item[1].unconnected_send.request.status_ext.data": [ 0 ], "enip.CIP.send_data.CPF.item[1].unconnected_send.request.status_ext.size": 1, "enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 142, "enip.CIP.send_data.CPF.item[1].type_id": 178, "enip.CIP.send_data.timeout": 0, "enip.command": 111, "enip.input": "array('c', '\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x06\x00\x8e\x00\x04\x01\x00\x00')", "enip.options": 0 } 08-15 14:21:40.588 MainThread enip.cli DETAIL collect Receive 1 (Context '0') 08-15 14:21:40.588 MainThread enip.cli DETAIL pipeline Completed 1/ 1; curr: 0 - last: 0 == 0 depth Mon Aug 15 14:21:40 2016: 0: Single G_A_S 'Pump1' == None 08-15 14:21:40.591 MainThread enip.cli DETAIL pipeline Pipelined 1/ 1; curr: 0 - last: 0 == 0 depth 08-15 14:21:40.592 MainThread enip.get NORMAL main 1 requests in 0.040s at pipeline depth 0; 24.927 TPS

python -m cpppo.server.enip.get_attribute '@4/1/1' -a 192.168.159.140 -v 08-15 14:23:39.404 MainThread enip.cli NORMAL init Connect: Success in 0.062s/ 5.000s Mon Aug 15 14:23:39 2016: 0: Single G_A_S '@4/1/1' == None 08-15 14:23:39.418 MainThread enip.get NORMAL main 1 requests in 0.013s at pipeline depth 0; 77.811 TPS

pjkundert commented 8 years ago

I suggest trying the "-S" (--simple) option, and see what happens.

Only PLCs that handle routing requests to other devices generally handle "routing" Unconnected requests. By specifying -S, Cpppo avoids using these types of requests. This is typically required for EtherNet/IP end devices, such as PowerFlex, MicroLogix, etc., which are typically only connected to sensors, and not other PLCs. Perhaps this is the case with SoftLogix?

jonathans56 commented 8 years ago

pjkundert,

Thank you for the reply.

I have tried the -S option with the 3 different ENIP commands with the same results:

$ python -m cpppo.server.enip.client -S -a 192.168.159.140 "Pump1" 08-15 16:42:52.155 MainThread enip.cli WARNING validate Client Single Read Tag Pump1 returned non-zero status: Status 4 Pump1 == None: 'Status 4 '

$ python -m cpppo.server.enip.get_attribute '@4/1/1' -a 192.168.159.140 -S Mon Aug 15 16:43:06 2016: 0: Single G_A_S '@4/1/1' == None

$ python -m cpppo.server.enip.get_attribute 'Pump1' -a 192.168.159.140 -S Mon Aug 15 16:43:14 2016: 0: Single G_A_S 'Pump1' == None

Previously I thought this maybe an issue with the virtual backplane, but I can verify the tags with a tag monitor and I can see the tags inside the controller. For cpppo to read tag data are the tags required to be produce or consumed? Read/Write attributes are a given, but I am just tugging at wires here, I have tried almost everything I have ready about, including using the proxy you previously posted:

$ python Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:19:22) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information.

from cpppo.server.enip.get_attribute import proxy_simple product_name, = proxy_simple( '192.168.159.140' ).read( [('Pump1','BOOL')] ) product_name

Any ideas, I have been stuck here for weeks.

pjkundert commented 8 years ago

Unfortunately, in my years of developing Cpppo, the documentation available for EtherNet/IP CIP itself, and for most devices has been essentially useless.

Most of the time, I resort to using Wireshark or Ethereal or 'tcpdump' to trace the raw communications between two working devices, or between some working software and the target device. Then, I try to manually parse the communications (or follow the Ethereal or Wireshark parse output, which often only partially decodes the communications, if at all). Usually, that gives me the information I need to implement some more of the protocol.

So; if you have any software that successfully talks to the SoftLogix using "Unconnected" communications (eg. RSLogix), you should sniff its communications while it accesses those tags, and see what it's doing...

Sorry I can't be more helpful! I've been shaking my head in disbelief for, literally, years while developing Cpppo...