Skip to content

Commit 60256ff

Browse files
committed
Merge branch 'fix-tag-case' into master; Version 4.3.0
2 parents d4409d7 + 57b58b2 commit 60256ff

File tree

4 files changed

+37
-26
lines changed

4 files changed

+37
-26
lines changed

server/enip/device.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -167,18 +167,18 @@ def redirect_tag( tag, address ):
167167
Make sure we stay with only str type tags (mostly for Python2, in case somehow we get a Unicode
168168
tag). Multi-segment symbolic tags are expected to be looked up as: symbol["<symbol1>.<symbol2>"]
169169
170+
All Tag lookups are case-insensitive, so are stored lower-case.
170171
"""
171-
tag = str( tag )
172172
assert isinstance( address, dict )
173173
assert all( k in symbol_keys for k in address )
174174
assert all( k in address for k in symbol_keys )
175-
symbol[tag] = address
175+
symbol[str( tag ).lower()] = address
176176
return tuple( address[k] for k in symbol_keys )
177177

178178

179179
def resolve_tag( tag ):
180180
"""Return the (class_id, instance_id, attribute_id) tuple corresponding to tag, or None if not specified"""
181-
address = symbol.get( str( tag ), None )
181+
address = symbol.get( str( tag ).lower(), None )
182182
if address:
183183
return tuple( address[k] for k in symbol_keys )
184184
return None
@@ -205,7 +205,7 @@ def resolve( path, attribute=False ):
205205
if ( result['class'] is not None and result['instance'] is not None
206206
and ( not attribute or result['attribute'] is not None )):
207207
break # All desired terms specified; done! (ie. ignore 'element')
208-
working = dict( term )
208+
working = dict( term )
209209
while working:
210210
# Each term is something like {'class':5}, {'instance':1}, or (from symbol table):
211211
# {'class':5,'instance':1}. Pull each key (eg. 'class') from working into result,
@@ -216,17 +216,17 @@ def resolve( path, attribute=False ):
216216
assert result[key] is None, \
217217
"Failed to override %r==%r with %r from path segment %r in path %r" % (
218218
key, result[key], working[key], term, path['segment'] )
219-
result[key] = working.pop( key ) # single 'class'/'instance'/'attribute' seg.
219+
result[key] = working.pop( key ) # single 'class'/'instance'/'attribute' seg.
220220
if working:
221221
assert 'symbolic' in working, \
222222
( "Unrecognized symbolic name %r found in path %r" % ( tag, path['segment'] )
223223
if tag
224224
else "Invalid term %r found in path %r" % ( working, path['segment'] ))
225-
tag += ( '.' if tag else '' ) + str( working['symbolic'] )
226-
working = None
227-
if tag in symbol:
228-
working = dict( symbol[tag] )
229-
tag = ''
225+
tag += ( '.' if tag else '' ) + str( working['symbolic'] )
226+
working = None
227+
if tag.lower() in symbol:
228+
working = dict( symbol[tag.lower()] )
229+
tag = ''
230230

231231
# Any tag not recognized will remain after all resolution complete
232232
assert not tag, \
@@ -237,7 +237,7 @@ def resolve( path, attribute=False ):
237237
"Failed to resolve required Class (%r), Instance (%r) %s Attribute(%r) from path: %r" % (
238238
result['class'], result['instance'], "and the" if attribute else "but not",
239239
result['attribute'], path['segment'] )
240-
result = result['class'], result['instance'], result['attribute'] if attribute else None
240+
result = result['class'], result['instance'], result['attribute'] if attribute else None
241241
log.detail( "Class %5d/0x%04x, Instance %3d, Attribute %5r <== %r",
242242
result[0], result[0], result[1], result[2], path['segment'] )
243243

server/enip_test.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3146,13 +3146,17 @@ def test_enip_CIP( repeat=1 ):
31463146

31473147

31483148
def test_enip_device_symbolic():
3149-
enip.device.symbol['SCADA'] = {'class':0x401, 'instance':1, 'attribute':2}
3150-
path={'segment':[{'symbolic':'SCADA'}, {'element':4}]}
3149+
enip.device.redirect_tag( 'SCADA', {'class':0x401, 'instance':1, 'attribute':2} )
3150+
path = {
3151+
'segment':[{'symbolic':'SCADA'}, {'element':4}]
3152+
}
31513153
assert enip.device.resolve( path, attribute=True ) == (0x401,1,2)
31523154
assert enip.device.resolve( path ) == (0x401,1,None)
31533155

3154-
enip.device.symbol['Tag.Subtag'] = {'class':0x401, 'instance':1, 'attribute':3}
3155-
path={'segment':[{'symbolic':'Tag'}, {'symbolic':'Subtag'}, {'element':4}]}
3156+
enip.device.redirect_tag( 'Tag.Subtag', {'class':0x401, 'instance':1, 'attribute':3} )
3157+
path = {
3158+
'segment':[{'symbolic':'Tag'}, {'symbolic':'Subtag'}, {'element':4}]
3159+
}
31563160
assert enip.device.resolve( path, attribute=True ) == (0x401,1,3)
31573161

31583162
try:
@@ -3235,7 +3239,7 @@ class Test_Device( enip.device.Object ):
32353239
assert enip.device.lookup( *enip.device.resolve( {'segment':[{'class':class_num}, {'instance':1}]} )) is O
32363240
assert enip.device.lookup( *enip.device.resolve( {'segment':[{'class':class_num}, {'instance':2}]} )) is O2
32373241

3238-
enip.device.symbol['BOO'] = {'class': class_num, 'instance': 1}
3242+
enip.device.redirect_tag( 'BOO', {'class': class_num, 'instance': 1, 'attribute': 2 } )
32393243

32403244
path = {'segment':[{'symbolic':'BOO', 'length':3}, {'attribute':2}, {'element':4}]}
32413245
assert enip.device.lookup( *enip.device.resolve( path )) is O
@@ -3264,7 +3268,7 @@ def test_enip_logix():
32643268
assert len( Obj_a1 ) == 100
32653269

32663270
# Set up a symbolic tag referencing the Logix Object's Attribute
3267-
enip.device.symbol['SCADA'] = {'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':1 }
3271+
enip.device.redirect_tag( 'SCADA', {'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':1 } )
32683272

32693273
# Lets get it to parse a request:
32703274
# 'service': 0x52,

server/logix_test.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,18 @@ def test_logix_multiple():
143143
Obj_a4 = Obj.attribute['4'] = enip.device.Attribute( 'number', enip.parser.REAL, default=0.0)
144144

145145
# Set up a symbolic tag referencing the Logix Object's Attribute
146-
enip.device.symbol['parts'] = {'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':1 }
147-
enip.device.symbol['ControlWord'] \
148-
= {'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':2 }
149-
enip.device.symbol['SCADA_40001'] \
150-
= {'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':3 }
151-
enip.device.symbol['number'] \
152-
= {'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':4 }
146+
enip.device.redirect_tag( 'parts', {
147+
'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':1
148+
})
149+
enip.device.redirect_tag( 'ControlWord', {
150+
'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':2
151+
})
152+
enip.device.redirect_tag('SCADA_40001', {
153+
'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':3
154+
})
155+
enip.device.redirect_tag( 'number', {
156+
'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':4
157+
})
153158

154159

155160
assert len( Obj_a1 ) == size
@@ -627,7 +632,9 @@ def logix_performance( repeat=1000 ):
627632
assert len( Obj_a1 ) == size
628633

629634
# Set up a symbolic tag referencing the Logix Object's Attribute
630-
enip.device.symbol['SCADA'] = {'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':1 }
635+
enip.device.redirect_tag( 'SCADA', {
636+
'class': Obj.class_id, 'instance': Obj.instance_id, 'attribute':1
637+
})
631638

632639
# Lets get it to parse a request, resulting in a 200 element response:
633640
# 'service': 0x52,

version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version_info__ = ( 4, 2, 5 )
1+
__version_info__ = ( 4, 3, 0 )
22
__version__ = '.'.join( map( str, __version_info__ ))

0 commit comments

Comments
 (0)