@@ -112,23 +112,6 @@ class CIPDriver:
112112 _auto_slot_cip_path = False
113113
114114 def __init__ (self , path : str , * args , ** kwargs ):
115- """
116- :param path: CIP path to intended target
117-
118- The path may contain 3 forms:
119-
120- - IP Address Only (``10.20.30.100``) - Use for a ControlLogix PLC is in slot 0 or if connecting to a CompactLogix or Micro800 PLC.
121- - IP Address/Slot (``10.20.30.100/1``) - (ControlLogix) if PLC is not in slot 0
122- - CIP Routing Path (``1.2.3.4/backplane/2/enet/6.7.8.9/backplane/0``) - Use for more complex routing.
123-
124- .. note::
125-
126- Both the IP Address and IP Address/Slot options are shortcuts, they will be replaced with the
127- CIP path automatically. The ``enet`` / ``backplane`` (or ``bp``) segments are symbols for the CIP routing
128- port numbers and will be replaced with the correct value.
129-
130- """
131-
132115 self ._sequence : cycle = cycle (65535 , start = 1 )
133116 self ._sock : Optional [Socket ] = None
134117 self ._session : int = 0
@@ -137,13 +120,13 @@ def __init__(self, path: str, *args, **kwargs):
137120 self ._target_is_connected : bool = False
138121 self ._info : Dict [str , Any ] = {}
139122 self ._cip_path = path
140- ip , _path = parse_connection_path (path , self ._auto_slot_cip_path )
123+ ip , port , _path = parse_connection_path (path , self ._auto_slot_cip_path )
141124
142125 self ._cfg = {
143126 "context" : b"_pycomm_" ,
144127 "protocol version" : b"\x01 \x00 " ,
145128 "rpi" : 5000 ,
146- "port" : 44818 ,
129+ "port" : port or 44818 ,
147130 "timeout" : 10 ,
148131 "ip address" : ip ,
149132 "cip_path" : _path ,
@@ -605,15 +588,27 @@ def _receive(self):
605588 return reply
606589
607590
608- def parse_connection_path (path : str , auto_slot : bool = False ) -> Tuple [str , List [PortSegment ]]:
591+ def parse_connection_path (path : str , auto_slot : bool = False ) -> Tuple [str , Optional [ int ], List [PortSegment ]]:
609592 """
610593 Parses and validates the CIP path into the destination IP and
611594 sequence of port/link segments.
612595 Returns the IP and a list of PortSegments
613596 """
614597 try :
615- path = path .replace ("\\ " , "/" )
598+ path = path .replace ("\\ " , "/" ). replace ( "," , "/" )
616599 ip , * route = path .split ("/" )
600+ if ':' in ip :
601+ ip , port = ip .split (':' )
602+ try :
603+ port = int (port )
604+ except Exception as err :
605+ raise RequestError (f'Invalid port: { port } ' )
606+ else :
607+ if 0 > port >= 65535 :
608+ raise RequestError (f'Invalid port: { port } ' )
609+
610+ else :
611+ port = None
617612
618613 try :
619614 ipaddress .ip_address (ip )
@@ -627,7 +622,7 @@ def parse_connection_path(path: str, auto_slot: bool = False) -> Tuple[str, List
627622 except Exception as err :
628623 raise RequestError (f"Failed to parse connection path: { path } " ) from err
629624 else :
630- return ip , _path
625+ return ip , port , _path
631626
632627
633628def parse_cip_route (path : Union [str , List [str ]], auto_slot : bool = False ) -> List [PortSegment ]:
0 commit comments