liftoff-sr / CIPster

Ethernet/IP (Common Industrial Protocol) stack in C++. This started as a C to C++ conversion of C based OpENer.
Other
141 stars 50 forks source link

EtherNet/IP Adapter with FANUC using CIPster failing in Forward Open request #42

Open adryash opened 2 months ago

adryash commented 2 months ago

I am trying to write a C++ EtherNet/IP Adapter that will communicate with a FANUC robot configured as a Scanner. Unfortunatelly, after exchanging 3 messages I get recv() error: Connection reset by peer and I don't know why. It seems that the robot for some reason refuses the Forward Open response, even if on the C++ side everything works fine.

My code is in general very similar to the code from sample_application, configured to work with the robot.

uint8_t m_assemblyInputData[64];
uint8_t m_assemblyOutputData[64];

CreateAssemblyInstance(101, ByteBuf(m_assemblyInputData, sizeof(m_assemblyInputData)));
CreateAssemblyInstance(151, ByteBuf(m_assemblyOutputData, sizeof(m_assemblyOutputData)));
CreateAssemblyInstance(100, ByteBuf(0, 0));
ConfigureExclusiveOwnerConnectionPoint(151,101,-1);

From my BeforeAssemblyDataSend method I tried returning true, false, writing something in my buffer or not doing anything - each time without luck.

My Scanner configuration on the robot side is:

Vendor Id: 60000
Device Type: 12
Product code: 65001
Input size (words): 32
Output size (words): 32
RPI (ms): 1000
Assembly instance (input): 101
Assembly instance (output): 151
Configuration instance: 100

General:
I/O Data Type: 16-BIT WORDS
Timeout Multiplier: 4
Reconnect: FALSE
Major Revision: 1
Minor Revision: 2
Alarm Severity: WARN
Quick Connect: FALSE

Originator To Target:
RPI: 1000

Target To Originator:
Transport Type: UNICAST
RPI: 1000

Connection Type:
Type: Exclusive-Owner
O=>T Format: Run/Idle Header
T=>0 Format: Modeless

Configuration String Status
Size(bytes): 0

When I set the connection Enable to TRUE, I get an error:

PRIO-350 EtherNet/IP Scanner Error (1)
PRIO-358 EtherNet/Ip FwdOpen Fail (0x0)

And the Status is for the whole time OFFLINE.

In my C++ Adapter I get logs:

ServiceRemove: removing service 'SetAttributeSingle' from class 'Message Router'.
ServiceRemove: removing service 'SetAttributeSingle' from class 'Identity'.
ServiceRemove: removing service 'SetAttributeSingle' from class 'Connection Manager'.
ServiceRemove: removing service 'SetAttributeSingle' from class 'Connection'.
ServiceRemove: removing service 'GetAttributeSingle' from class 'Connection'.
CreateInstance: created assembly aInstanceId 101
CreateInstance: created assembly aInstanceId 151
CreateInstance: created assembly aInstanceId 100
s_sockets.tcp_listener == 23
master_set_add[23]: TCP socket
master_set_add[26]: UDP socket
master_set_add[25]: UDP socket
master_set_add[24]: UDP socket
NetworkHandlerInitialize:
 tcp_listener                 :23
 udp_unicast_listener         :26
 udp_local_broadcast_listener :25
 udp_global_broadcast_listener:24
 added to master_set
 ...
CheckAndHandleTcpListenerSocket[35]: new TCP connection
RegisterTcpConnection[35]: session peer:[ROBOT IP]
NoteTcpActivity[35]
master_set_add[35]: TCP socket
ReceiveTcpMsg[35]:
rTCP: 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      00 00 00 00 00 00 00 00
ReceiveTcpMsg[35]: received 24 TCP bytes, command:'ListServices'
NoteTcpActivity[35]
HandleReceivedExplicitTcpData[35]:'ListServices'
HandleDataOnTcpSocket[35]: replied with 50 bytes
ReceiveTcpMsg[35]:
rTCP: 65 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00
      00 00 00 00 00 00 00 00 01 00 00 00
ReceiveTcpMsg[35]: received 28 TCP bytes, command:'RegisterSession'
NoteTcpActivity[35]
HandleReceivedExplicitTcpData[35]:'RegisterSession'
RegisterSession[35]: session_id:2
SetSessionHandle(2)
HandleDataOnTcpSocket[35]: replied with 28 bytes
ReceiveTcpMsg[35]:
rTCP: 6f 00 60 00 02 00 00 00 00 00 00 00 00 00 00 00
      00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00
      00 00 00 00 b2 00 3c 00 54 02 20 06 24 01 05 99
      00 00 00 00 5c 53 8c 13 b5 7d 64 01 .. .. .. ..
      00 00 00 00 40 42 0f 00 46 48 40 42 0f 00 42 48
      01 09 34 04 60 ea 0c 00 e9 fd 01 02 20 04 24 64
      2c 97 2c 65 01 80 10 00 00 02 08 ae ac 10 ef 7e
      00 00 00 00 00 00 00 00
ReceiveTcpMsg[35]: received 120 TCP bytes, command:'SendRRData'
NoteTcpActivity[35]
HandleReceivedExplicitTcpData[35]:'SendRRData'
NotifyMR: routing...
NotifyMR: targeting 'Connection Manager' instance:1 service:'ForwardOpen'
forward_open: ConnSerNo:7db5 VendorId:164 OriginatorSerNum:[ROBOT S/N] CID:0x00000000 PID:0x138c535c
ResolveInstances: ignoring config_path because of missing data segment
ResolveInstances: forward_open conn_path: (consuming assembly 151)(producing assembly 101)
forward_open: trigger_class:1
forward_open: o_t RPI_usecs:1000000
forward_open: o_t size:70
forward_open: o_t priority:2
forward_open: o_t type:PointToPoint
forward_open: t_o RPI_usecs:1000000
forward_open: t_o size:66
forward_open: t_o priority:2
forward_open: t_o type:PointToPoint
CorrectSizes: requested conn_size(70) is OK for consuming:'assembly 151'
CorrectSizes: requested conn_size(66) is OK for producing:'assembly 101'
SetInstanceType<7>(IoExclusiveOwner)
GeneralConfiguration<7>: new PointToPoint CID:0x45670013
SetExpectedPacketRateUSecs( 1000000 ) adjusted=1000000
SetInstanceType<7>(IoExclusiveOwner)
createSocket[36]: bound on 0.0.0.0:2222
master_set_add[36]: UDP socket
CipConn::SetState<7>(Established)
forward_open: OpenConnection() succeeded
forward_open: sending success response
NotifyMR: service ForwardOpen of class 'Connection Manager' returned 1
HandleDataOnTcpSocket[35]: replied with 70 bytes
UdpSocket[36] bound:0.0.0.0:2222  mcast:no
ReceiveTcpMsg[35]:
ReceiveTcpMsg[35]: recv() error: Connection reset by peer
NetworkHandlerProcessOnce[35]: calling CloseBySocket()
CloseBySocket[35]
CloseSocket[35]
master_set_rem[35]
SendConnectedData[36]@13210000 PID:0x138c535c len:84  dst:[ROBOT IP]:2222
SendConnectedData[36]@14210000 PID:0x138c535c len:84  dst:[ROBOT IP]:2222
SendConnectedData[36]@15210000 PID:0x138c535c len:84  dst:[ROBOT IP]:2222
SendConnectedData[36]@16210000 PID:0x138c535c len:84  dst:[ROBOT IP]:2222
SendConnectedData[36]@17210000 PID:0x138c535c len:84  dst:[ROBOT IP]:2222
SendConnectedData[36]@18210000 PID:0x138c535c len:84  dst:[ROBOT IP]:2222
SendConnectedData[36]@19210000 PID:0x138c535c len:84  dst:[ROBOT IP]:2222
SendConnectedData[36]@20210000 PID:0x138c535c len:84  dst:[ROBOT IP]:2222
SendConnectedData[36]@21210000 PID:0x138c535c len:84  dst:[ROBOT IP]:2222
SendConnectedData[36]@22210000 PID:0x138c535c len:84  dst:[ROBOT IP]:2222
ManageConnections<7>: >>> c-class:1 timeOut@23210000
Close<7>
CipConn::SetState<7>(NonExistent)
CheckForTimedOutConnectionsAndCloseTCPConnections: killing session:2
CloseBySessionHandle: inactive aSessionHandle:2

What am I doing wrong? Is there any other thing to configure that I am not aware of? Or maybe the protocol versions are incompatible?

liftoff-sr commented 2 months ago

This is a support request, and not yet known to be an issue (aka bug report). It would have been better posted to the discussion section. However I respond:

The Fanuc implementation of Ethernet/IP is somewhat limited. I know we have installs where we have had success talking with it, but its been months and my memory is not clear regarding the difficulties. To paraphrase the problem, try and relate this to the situation: the spec can say "all of the above is ok", yet Fanuc will only support a very specific subset of all of the above. I was not impressed with their implementation, and even less impressed with the support that was unavailable to my customer from them.

To make a guess, I think the format or sequence of SockAddr fields in one of our replies was bothering them, even though you could clearly see we were within spec.

I would start by bringing in wireshark. The packet decoding within that tool is very good for EIP. Perhaps it will show some kind of disagreement. You should be able to see both directions of traffic. On linux we just fire up tcpdump, create a capture file, and then transfer it to a desktop for examination by wireshark later.

Attached is a script we use to fire up tcpdump.

If that shows nothing, then I'd ask on an EIP forum about the brain dead or old form of the SockAddr sequence that this robot can handle. You could dumb down the code to work around the problem most likely.

liftoff-sr commented 2 months ago

EtherNet/IP makes use of well known TCP port number 44818 for explicit messaging

and UDP port number 2222 for implicit messaging

tcpdump tutorial:

https://danielmiessler.com/study/tcpdump/

INTERFACE=any

INTERFACE=ethernet0

INTERFACE=br0

FILE=/tmp/eip.cap

rm "$FILE" 2> /dev/null

tcpdump -nn -i $INTERFACE -w "$FILE" 'udp port 2222 or tcp port 44818'

adryash commented 2 months ago

Thanks for your reply! I tried Wireshark and to be honest, I do not see anything special there. There is a proper request-response sequence of List Services, Register Session and Forward Open. After the last one the robot just sends TCP RST to my adapter and that's it. Could you give me some more explanation about what can be wrong with the SockAddr? Maybe I can try to change some lines in the CIPster code to check other possibilities?

adryash commented 2 months ago

Update: I made it work. We have to send the O->T Saii in the forward open reply even if we are using standard 0x08AE port. Now FANUC robot connects properly to my adapter using CIPster library. I made a proper pull request for next generations.

LouKordos commented 5 days ago

Hello @adryash , I think we are trying to achieve the same thing, only you are much more knowledgable regarding CIP. I am basically trying to implement this: https://github.com/UofI-CDACS/fanuc_ethernet_ip_drivers, only in C++, so reading and writing (position) registers. Looking at the code, it sends an explicit generic message, but I am not sure how I can implement this using CIPster. Looking at the sampleapplication.cc, would I just create an explicit message assembly and populate the uint8_t array with with class code, service, instance and attribute? I can't find where the actual send happens in the example though...