cpppo with OMRON PLC
Hi, I try to use cpppo with OMRON PLC (CJ1, CJ2 and NJ with ethernet card EIP21), but I can't read/write memory. With this command, I can see product on the network :
python -m cpppo.server.enip.client --udp --broadcast --list-identity -a 192.168.0.255
List Identity 0 from ('192.168.0.2', 44818): {
"count": 1,
"item[0].type_id": 12,
"item[0].length": 44,
"item[0].identity_object.version": 1,
"item[0].identity_object.sin_family": 2,
"item[0].identity_object.sin_port": 44818,
"item[0].identity_object.sin_addr": "192.168.0.2",
"item[0].identity_object.vendor_id": 47,
"item[0].identity_object.device_type": 12,
"item[0].identity_object.product_code": 13,
"item[0].identity_object.product_revision": 258,
"item[0].identity_object.status_word": 53,
"item[0].identity_object.serial_number": 8822956,
"item[0].identity_object.product_name": "CJ2B-EIP21",
"item[0].identity_object.state": 3
}
List Identity 1 from ('192.168.0.4', 44818): {
"count": 1,
"item[0].type_id": 12,
"item[0].length": 46,
"item[0].identity_object.version": 1,
"item[0].identity_object.sin_family": 2,
"item[0].identity_object.sin_port": 44818,
"item[0].identity_object.sin_addr": "192.168.0.4",
"item[0].identity_object.vendor_id": 47,
"item[0].identity_object.device_type": 12,
"item[0].identity_object.product_code": 1613,
"item[0].identity_object.product_revision": 257,
"item[0].identity_object.status_word": 48,
"item[0].identity_object.serial_number": 9243817,
"item[0].identity_object.product_name": "NS10-TV01-V2",
"item[0].identity_object.state": 3
}
But when I try to read/write memory area, cpppo return None
python -m cpppo.server.enip.get_attribute -a 192.168.0.2 "@0xC4/0x10/3"
Tue Jun 20 08:29:56 2017: 0: Single G_A_S @0x00C4/16/3 == None
In the EIP21 documentation, to read CPU unit mode, I have these informations :
Service code = 0x0E Class ID = 0xC4 Instance ID = 0x00 Request service data Attribute ID = 0x64
Other exemple to write a byte data
Service code = 0x1C Class ID = 0xC4 Instance ID = Specifies area (01 Hex to 14 Hex) Request service data Attribute ID = Address, No. of read bytes
What's the commande to read byte area memory with a service code?
Normally default route path is ok for my configuration (I have de CPU and next to the EIP21 ethernet card with unit number 0). I try to specifie de route path, but cpppo return an error :
python -m cpppo.server.enip.get_attribute -a 192.168.0.2 --route-path '[{"link": 0, "port": 1}]' "@0xC4/0x10/3"
Traceback (most recent call last):
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\r
unpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\r
unpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\s
ite-packages\cpppo-3.9.7-py3.6.egg\cpppo\server\enip\get_attribute.py", line 803
, in <module>
sys.exit( main() )
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\s
ite-packages\cpppo-3.9.7-py3.6.egg\cpppo\server\enip\get_attribute.py", line 758
, in main
route_path = json.loads( args.route_path ) if args.route_pa
th \
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\j
son\__init__.py", line 354, in loads
return _default_decoder.decode(s)
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\j
son\decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\vinssurfer\AppData\Local\Programs\Python\Python36-32\lib\j
son\decoder.py", line 357, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Can you help me to connect cpppo with OMRON plc?
Thanks.
To see what error codes the Omron is returning from the get_attribute request, add some "-v" options to the command.
As for the --route-path: it appears that (for some reason) the JSON specification for the route path you are supplying is not being parsed correctly, by the Python 'json' module. It could be due to invalid characters (non-ASCII quote symbols, for example). Windows is notorious for this, unfortunately, and getting quoting right on the command line is extremely difficult. Is it possible to try it from a Linux host, or on a Mac?
Thanks for your answer. I'm french so mayby quote is not same ASCII code. But I can't try with Linux or Mac.
That's the result with -vv
python -m cpppo.server.enip.get_attribute -a 192.168.0.7 -vv "@0xC4/0x10/3"
06-20 15:54:34.400 MainThread enip.cli DETAIL __init__ Connect: TCP/IP to ('192.168.0.7', 44818)
06-20 15:54:34.478 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.session_handle": 0,
"enip.options": 0,
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00')",
"enip.CIP.register.options": 0,
"enip.CIP.register.protocol_version": 1
}
06-20 15:54:34.494 MainThread enip.cli NORMAL __init__ Connect: Success in 0.093s/ 5.000s
06-20 15:54:34.494 MainThread enip.cli DETAIL parse_oper Tag: '@0xC4/0x10/3' yields Operation: {'path': [{'class': 196}, {'instance': 16}, {'attribute': 3}]}.update({'route_path': None, 'send_path': None})
06-20 15:54:34.494 MainThread enip.cli DETAIL cip_send Client CIP Send: {
"enip.session_handle": 132096,
"enip.options": 0,
"enip.status": 0,
"enip.sender_context.input": "bytearray(b'0\\x00\\x00\\x00\\x00\\x00\\x00\\x00')",
"enip.CIP.send_data.interface": 0,
"enip.CIP.send_data.timeout": 0,
"enip.CIP.send_data.CPF.item[0].type_id": 0,
"enip.CIP.send_data.CPF.item[1].type_id": 178,
"enip.CIP.send_data.CPF.item[1].unconnected_send.service": 82,
"enip.CIP.send_data.CPF.item[1].unconnected_send.status": 0,
"enip.CIP.send_data.CPF.item[1].unconnected_send.priority": 5,
"enip.CIP.send_data.CPF.item[1].unconnected_send.timeout_ticks": 157,
"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].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.request.path.segment[0].class": 196,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[1].instance": 16,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.path.segment[2].attribute": 3,
"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\\x03 \\xc4$\\x100\\x03')"
}
06-20 15:54:34.494 MainThread enip.cli DETAIL format_pat Formatted
@0x00C4/16/3 from: [{'class': 196}, {'instance': 16}, {'attribute': 3}]
06-20 15:54:34.494 MainThread enip.cli DETAIL issue Sent 0.003/ 5.000s
: Single G_A_S @0x00C4/16/3 {
"path.segment[0].class": 196,
"path.segment[1].instance": 16,
"path.segment[2].attribute": 3,
"get_attribute_single": true,
"service": 14,
"input": "bytearray(b'\\x0e\\x03 \\xc4$\\x100\\x03')"
}
06-20 15:54:34.525 MainThread enip.cli DETAIL issue Sending 1 (Context b'0')
06-20 15:54:34.525 MainThread enip.cli DETAIL pipeline Issuing 0/ 1; curr: 0 - last: -1 == 1 depth
06-20 15:54:34.541 MainThread enip.cli DETAIL collect Rcvd 0.006/ 5.000s
{
"peer": [
"192.168.0.7",
44818
],
"enip.command": 111,
"enip.length": 20,
"enip.session_handle": 132096,
"enip.status": 0,
"enip.sender_context.input": "array('B', [48, 0, 0, 0, 0, 0, 0, 0])",
"enip.options": 0,
"enip.input": "array('B', [0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 178, 0, 4, 0, 142, 0, 5, 0])",
"enip.CIP.send_data.interface": 0,
"enip.CIP.send_data.timeout": 0,
"enip.CIP.send_data.CPF.count": 2,
"enip.CIP.send_data.CPF.item[0].type_id": 0,
"enip.CIP.send_data.CPF.item[0].length": 0,
"enip.CIP.send_data.CPF.item[1].type_id": 178,
"enip.CIP.send_data.CPF.item[1].length": 4,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.input": "array('B', [142, 0, 5, 0])",
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.service": 142,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.status": 5,
"enip.CIP.send_data.CPF.item[1].unconnected_send.request.status_ext.size": 0
}
06-20 15:54:34.650 MainThread enip.cli DETAIL collect Receive 1 (Context b'0')
06-20 15:54:34.665 MainThread enip.cli DETAIL pipeline Completed 1/ 1; curr: 0 - last: 0 == 0 depth
Tue Jun 20 15:54:34 2017: 0: Single G_A_S @0x00C4/16/3 == None
06-20 15:54:34.681 MainThread enip.cli DETAIL pipeline Pipelined 1/ 1; curr: 0 - last: 0 == 0 depth
06-20 15:54:34.681 MainThread enip.get NORMAL main 1 requests in 0.192s at pipeline depth 0; 5.198 TPS
Does "service": 14, corresponding to Service code in Omron documentation? How can I change this value?
Thanks
Decimal 14 is hex 0x0E, so that's OK. I don't know if the OMRON does "routing" CIP requests (ie. with a route path encapsulation); perhaps try the "simple" non-routing CIP requests, by specifying the -S option to the ...get_attribute command. This eliminates the route-path and send-path encapsulation from the CIP request, and expects the receiving EtherNet/IP module to respond to the CIP request itself...
Yes I have an answer with -S option
With this command I can read which mode the PLC is (run, program, monitor)
python -m cpppo.server.enip.get_attribute -a 192.168.0.7 -S "@0xC4/0x0/0x64"
Tue Jun 20 16:45:53 2017: 0: Single G_A_S @0x00C4/0/100 == [1, 0]
but I can't not access to the memory area EIP21 omron.pdf I will continue on Thursday...
Hi, I have no problem to read/write plc operating mode (service 0x0E and Ox10) But to read/write memory or input/output, I need to change service code (service code 1C to 1F). You can see that in my previous post in the pdf file. How can I change the service code? Is it an other function than get_attrribute? Thanks
Hello, I renew my question : is-it possible to change the service code and how? Thanks
I have this code to read attribute and if I remember me well it was due to this error (routing=false)
import socket import time import cpppo from cpppo.server.enip import client
plc_ip_address = "192.168.1.10" timeout = 5.0
import logging cpppo.log_cfg['level'] = logging.ERROR
logging.basicConfig( **cpppo.log_cfg )
try:
with client.connector( host=plc_ip_address, timeout=timeout) as conn:
get_attr_single_operation = {
'path': [{'class': 4}, {'instance': 101}, {'attribute': 3}],
'method': 'get_attribute_single',
'send_path': '', 'route_path': False
}
failures,replies = conn.process(
operations=[get_attr_single_operation], timeout=timeout )
for rpy in replies:
print(rpy)
except Exception as exc: print ("EtherNet/IP I/O Failed: %s" % ( exc )) time.sleep( .1 )
I have exactly the same problem with Pepperl Fuchs IO link module. The service to access the data is 0x4b not 0x0E (get single attribute) as said in documentation page 53