Skip to content

Commit 272327c

Browse files
committed
Merge branch 'feature-multipath'; Version 4.0.3
2 parents fb4b06e + 4cee052 commit 272327c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1503
-921
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ install:
1717
- pip install 'argparse; python_version < "2.7"'
1818
- pip install 'configparser; python_version < "3.0"'
1919

20-
# command to run tests
20+
# command to run tests. Must give a concrete location for time-related tests to pass
2121
script:
22-
- python -m pytest -v
22+
- TZ=Canada/Mountain python -m pytest -v

GNUmakefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,11 @@ help:
7171
@echo " vmware-debian-up Brings up Jessie VM w/ Docker capability"
7272
@echo " vmware-debian-ssh Log in to the VM"
7373

74-
test:
74+
test2:
7575
$(PY2TEST) || true
76+
test3:
7677
$(PY3TEST) || true
78+
test: test2 test3
7779

7880
install:
7981
$(PY2) setup.py install
@@ -164,6 +166,10 @@ test-%:
164166
$(PY2TEST) *$*_test.py
165167
$(PY3TEST) *$*_test.py
166168

169+
unit2-%:
170+
$(PY2TEST) -k $*
171+
unit3-%:
172+
$(PY3TEST) -k $*
167173
unit-%:
168174
$(PY2TEST) -k $*
169175
$(PY3TEST) -k $*

README.org

Lines changed: 145 additions & 89 deletions
Large diffs are not rendered by default.

README.pdf

-27.5 KB
Binary file not shown.

__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
1515
#
1616

17-
from __future__ import absolute_import
18-
from __future__ import print_function
17+
from __future__ import absolute_import, print_function, division
1918

2019
__author__ = "Perry Kundert"
2120
__email__ = "[email protected]"

automata.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
1515
#
1616

17-
from __future__ import absolute_import
18-
from __future__ import print_function
19-
from __future__ import division
17+
from __future__ import absolute_import, print_function, division
18+
try:
19+
from future_builtins import zip, map # Use Python 3 "lazy" zip, map
20+
except ImportError:
21+
pass
2022

2123
import array
2224
import logging
@@ -232,7 +234,7 @@ def push( self, item ):
232234
if self.memory:
233235
assert self.memory.pop() == item
234236
super( remembering, self ).push( item )
235-
237+
236238

237239
class decide( object ):
238240
"""A type of object that may be supplied as a state transition target, instead of a state. It must
@@ -777,9 +779,9 @@ def transition( self, source, machine=None, path=None, data=None, ending=None ):
777779
# StopIteration after yielding a transition, or if self is a terminal state
778780

779781
def delegate( self, source, machine=None, path=None, data=None, ending=None ):
780-
"""Base state class delegate generator does nothing."""
781-
raise StopIteration
782-
yield None
782+
"""Base state class delegate generator does nothing; equivalent to `yield from ()` in Python 3.3+"""
783+
return
784+
yield
783785

784786
def initialize( self, machine=None, path=None, data=None ):
785787
"""Done once at state entry."""
@@ -1399,7 +1401,7 @@ def __init__( self,
13991401

14001402

14011403
class string_base( object ):
1402-
"""When combined with a regex class, collects a string matching the regular expression, and puts it
1404+
r"""When combined with a regex class, collects a string matching the regular expression, and puts it
14031405
in the data artifact at path.context 'string' by default.
14041406
14051407
The default initial=".*\n", greedy=False configuration scans input only until the regular
@@ -1463,7 +1465,7 @@ def terminate( self, exception, machine=None, path=None, data=None ):
14631465
value = data[subs]
14641466
if isinstance( value, array.array ):
14651467
if value.typecode == 'c':
1466-
value = value.tostring()
1468+
value = value.tostring() if sys.version_info[0] < 3 else value.tobytes()
14671469
elif value.typecode == 'B':
14681470
value = value.tobytes()
14691471
elif value.typecode == 'u':
@@ -1487,7 +1489,7 @@ class integer_base( string_base ):
14871489
def __init__( self, name, initial=None, context="integer", **kwds ):
14881490
assert initial is None, "Cannot specify a sub-machine for %s.%s" % (
14891491
__package__, self.__class__.__name__ )
1490-
super( integer_base, self ).__init__( name=name, initial="\d+", context=context,
1492+
super( integer_base, self ).__init__( name=name, initial=r"\d+", context=context,
14911493
greedy=True, **kwds )
14921494

14931495
def terminate( self, exception, machine=None, path=None, data=None ):

automata_test.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
# unicode_literals, we cannot have any literals at all with unicode characters under 2.x, while
66
# maintaining 3.2 compatibilty. This is unfortunate.
77

8-
from __future__ import absolute_import
9-
from __future__ import print_function
10-
from __future__ import unicode_literals
11-
from __future__ import division
8+
from __future__ import absolute_import, print_function, division, unicode_literals
9+
try:
10+
from future_builtins import zip, map # Use Python 3 "lazy" zip, map
11+
except ImportError:
12+
pass
13+
1214

1315
import binascii
1416
import logging

bin/modbus_sim.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
1616
#
1717

18-
from __future__ import absolute_import
19-
from __future__ import print_function
20-
from __future__ import division
18+
from __future__ import absolute_import, print_function, division
19+
try:
20+
from future_builtins import zip, map # Use Python 3 "lazy" zip, map
21+
except ImportError:
22+
pass
2123

2224
__author__ = "Perry Kundert"
2325
__email__ = "[email protected]"

cpppo-router.cfg

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[UCMM]
2+
Route Path = 1/0
3+
Route = {
4+
"1/1-15": "localhost:44819"
5+
}

cpppo.cfg

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,56 @@ Interface Configuration = {
5252
"dns_secondary": "8.8.4.4",
5353
"domain_name": "example.com"
5454
}
55+
56+
#
57+
# UCMM -- Unconnected Message Manager
58+
#
59+
[UCMM]
60+
61+
# Route Path -- Device's default request route_path (if any) to respond to
62+
#
63+
# o Only uses this configured Route Path if none is supplied on the command-line
64+
# (eg. via -S|--simple|--route_path).
65+
# o null
66+
# - Any Route Path; will ignore the request's provided route_path
67+
# o 0/False
68+
# - no Route Path; only accept "Simple" (non-routing) CIP requests
69+
# o JSON List of Dict: [{"port": <int>, "link": <int>}]
70+
# - Respond to a specific route_path
71+
# - Default value is "port": 1 (Backplane), "link": 0 (First slot),
72+
# which is typically the slot occupied by the *Logix CPU.
73+
#
74+
# Route Path = <JSON>
75+
# ----------
76+
# Route Path = null # Any route_path allowed (the default)
77+
# Route Path = false # No route_path (Simple device)
78+
# Route Path = 0 # ''
79+
# Route Path = 1/0 # [{"port": 1, "link": 0}] allowed
80+
81+
# Route -- Route requests w/ specified route_path "port/link" to an EtherNet/IP CIP server
82+
#
83+
# o <port>/<link> --> <ip>[:<port>]
84+
# o If incoming request's 0'th route_path element matches the given route key,
85+
# then the request is forwarded to the specified EtherNet/IP CIP device, after the
86+
# matching route_path element is removed.
87+
# - If the resulting (trimmed) route_path is empty, a Simple (non-routing) request
88+
# is used (eg. appropriate for a non-routing MicroLogix, A-B Powerflex, etc).
89+
#
90+
# Route = {
91+
# "1/1": "localhost:11001",
92+
# "1/2": "localhost:11002",
93+
# "1/3-7": "localhost:11003",
94+
# "2/1.2.3.3": "localhost:11003",
95+
# "2/1.2.3.4": "192.168.0.4:44818",
96+
# "2/1.2.3.5": "192.168.0.4:44818"
97+
# }
98+
#
99+
# If no Route table is configured, the traditional default behaviour looks only at the UCMM's configured route_path,
100+
# or the default route_path (see cpppo/server/enip/main.py, route_path_default); see above.
101+
#
102+
# eg. route all Backplane (port 1) Slot (link) 1-15 to the same remote EtherNet/IP CIP device:
103+
# All other port/links are invalid, and result in an error status being returned -- unless
104+
# the configured Route Path is null -- then any port/link is accepted as a local request.
105+
# Route = {
106+
# "1/1-15": "localhost:44819"
107+
# }

0 commit comments

Comments
 (0)