Skip to content

Commit da82067

Browse files
committed
Merge pull request #16 from gijzelaerr/cli_getset
implement client/server get/set so we can set TCP port
2 parents b3242e8 + 64409da commit da82067

File tree

8 files changed

+179
-75
lines changed

8 files changed

+179
-75
lines changed

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ before_install:
1212
install:
1313
- python setup.py install
1414
script:
15-
- sudo /home/travis/virtualenv/python2.7/bin/nosetests test/test_partner.py
16-
- sudo /home/travis/virtualenv/python2.7/bin/nosetests test/test_server.py
17-
- nohup sudo /home/travis/virtualenv/python2.7/bin/snap7-server.py &
15+
- /home/travis/virtualenv/python2.7/bin/nosetests test/test_partner.py
16+
- /home/travis/virtualenv/python2.7/bin/nosetests test/test_server.py
17+
- nohup /home/travis/virtualenv/python2.7/bin/snap7-server.py &
1818
- nosetests test/test_client.py
1919
notifications:
2020
webhooks:

run_tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
export PYTHONPATH=.
44
sudo nosetests test/test_partner.py
55
sudo nosetests test/test_server.py
6-
sudo PYTHONPATH=. snap7/bin/snap7-server.py &
6+
PYTHONPATH=. snap7/bin/snap7-server.py &
77
nosetests test/test_client.py
88

snap7/bin/snap7-server.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@
77
import logging
88
import snap7
99

10+
tcpport = 1102
1011

1112
def mainloop():
1213
server = snap7.server.Server()
1314
size = 100
1415
data = (snap7.types.wordlen_to_ctypes[snap7.types.S7WLByte] * size)()
1516
server.register_area(snap7.types.srvAreaDB, 1, data)
1617

17-
server.start()
18+
server.start(tcpport=tcpport)
1819
while True:
19-
#logger.info("server: %s cpu: %s users: %s" % server.get_status())
2020
while True:
2121
event = server.pick_event()
2222
if event:
@@ -26,31 +26,11 @@ def mainloop():
2626
time.sleep(1)
2727

2828

29-
def check_root():
30-
"""
31-
check if uid of this process is root
32-
"""
33-
import os
34-
import platform
35-
36-
if platform.system() == 'Windows':
37-
# We don't need root on Windows to use port 102
38-
return True
39-
40-
if os.getuid() == 0:
41-
return True
42-
43-
44-
root_msg = "it sucks, but you need to run this as root. The snap7 library is" \
45-
" hardcoded run on port 102, which requires root privileges."
46-
4729
if __name__ == '__main__':
4830
import sys
4931
if len(sys.argv) > 1:
5032
snap7.common.load_library(sys.argv[1])
5133
logging.basicConfig()
5234
logger = logging.getLogger()
5335
logger.setLevel(logging.INFO)
54-
if not check_root():
55-
logging.error(root_msg)
5636
mainloop()

snap7/client.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
import logging
77

88
import snap7
9-
from snap7.types import S7Object, buffer_type, buffer_size
10-
from snap7.types import wordlen_to_ctypes, BlocksList, areas
9+
from snap7.types import S7Object, buffer_type, buffer_size, BlocksList, param_types
1110
from snap7.common import check_error, load_library, ipv4
1211
from snap7.exceptions import Snap7Exception
1312

@@ -55,17 +54,21 @@ def disconnect(self):
5554
return self.library.Cli_Disconnect(self.pointer)
5655

5756
@error_wrap
58-
def connect(self, address, rack, slot):
57+
def connect(self, address, rack, slot, tcpport=102):
5958
"""
6059
Connect to a S7 server.
6160
6261
:param address: IP address of server
6362
:param rack: rack on server
6463
:param slot: slot on server.
6564
"""
66-
logger.info("connecting to %s rack %s slot %s" % (address, rack, slot))
65+
logger.info("connecting to %s:%s rack %s slot %s" % (address, tcpport,
66+
rack, slot))
67+
68+
self.set_param(snap7.types.RemotePort, tcpport)
69+
6770
return self.library.Cli_ConnectTo(self.pointer, c_char_p(address),
68-
c_int(rack), c_int(slot))
71+
c_int(rack), c_int(slot))
6972

7073
def db_read(self, db_number, start, size):
7174
"""This is a lean function of Cli_ReadArea() to read PLC DB.
@@ -423,3 +426,23 @@ def compress(self, time):
423426
:param time: Maximum time expected to complete the operation (ms).
424427
"""
425428
return self.library.Cli_Compress(self.pointer, time)
429+
430+
@error_wrap
431+
def set_param(self, number, value):
432+
"""Sets an internal Server object parameter.
433+
"""
434+
logger.debug("setting param number %s to %s" % (number, value))
435+
type_ = param_types[number]
436+
return self.library.Cli_SetParam(self.pointer, number,
437+
byref(type_(value)))
438+
439+
def get_param(self, number):
440+
"""Reads an internal Server object parameter.
441+
"""
442+
logger.debug("retreiving param number %s" % number)
443+
type_ = param_types[number]
444+
value = type_()
445+
code = self.library.Cli_GetParam(self.pointer, c_int(number),
446+
byref(value))
447+
check_error(code)
448+
return value.value

snap7/server.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
import ctypes
55
import logging
66
import re
7-
from snap7.types import S7Object, longword, SrvEvent, server_statuses, \
8-
cpu_statuses
7+
import snap7.types
98
from snap7.common import check_error, load_library, ipv4
109

1110
logger = logging.getLogger(__name__)
@@ -57,7 +56,7 @@ def create(self):
5756
"""
5857
logger.info("creating server")
5958
self.library.Srv_Create.restype = ctypes.c_void_p
60-
return S7Object(self.library.Srv_Create())
59+
return snap7.types.S7Object(self.library.Srv_Create())
6160

6261
@error_wrap
6362
def register_area(self, area_code, index, userdata):
@@ -78,7 +77,8 @@ def set_events_callback(self, call_back):
7877
"""
7978
logger.info("setting event callback")
8079
CALLBACK = ctypes.CFUNCTYPE(None, ctypes.c_void_p,
81-
ctypes.POINTER(SrvEvent), ctypes.c_int)
80+
ctypes.POINTER(snap7.types.SrvEvent),
81+
ctypes.c_int)
8282

8383
def wrapper(usrptr, pevent, size):
8484
"""
@@ -106,7 +106,8 @@ def set_read_events_callback(self, call_back):
106106
"""
107107
logger.info("setting read event callback")
108108
CALLBACK = ctypes.CFUNCTYPE(None, ctypes.c_void_p,
109-
ctypes.POINTER(SrvEvent), ctypes.c_int)
109+
ctypes.POINTER(snap7.types.SrvEvent),
110+
ctypes.c_int)
110111

111112
def wrapper(usrptr, pevent, size):
112113
"""
@@ -136,11 +137,14 @@ def log_callback(event):
136137
self.set_events_callback(log_callback)
137138

138139
@error_wrap
139-
def start(self):
140+
def start(self, tcpport=102):
140141
"""
141142
start the server.
142143
"""
143-
logger.info("starting server on 0.0.0.0:102")
144+
if tcpport != 102:
145+
logging.info("setting server TCP port to %s" % tcpport)
146+
self.set_param(snap7.types.LocalPort, tcpport)
147+
logger.info("starting server on 0.0.0.0:%s" % tcpport)
144148
return self.library.Srv_Start(self.pointer)
145149

146150
@error_wrap
@@ -176,8 +180,8 @@ def get_status(self):
176180
logger.debug("status server %s cpu %s clients %s" %
177181
(server_status.value, cpu_status.value,
178182
clients_count.value))
179-
return server_statuses[server_status.value], \
180-
cpu_statuses[cpu_status.value], \
183+
return snap7.types.server_statuses[server_status.value], \
184+
snap7.types.cpu_statuses[cpu_status.value], \
181185
clients_count.value
182186

183187
@error_wrap
@@ -202,10 +206,13 @@ def lock_area(self, code, index):
202206
return self.library.Srv_UnlockArea(self.pointer, code, index)
203207

204208
@error_wrap
205-
def start_to(self, ip):
209+
def start_to(self, ip, tcpport=102):
206210
"""
207211
start server on a specific interface.
208212
"""
213+
if tcpport != 102:
214+
logging.info("setting server TCP port to %s" % tcpport)
215+
self.set_param(snap7.types.LocalPort, tcpport)
209216
assert re.match(ipv4, ip), '%s is invalid ipv4' % ip
210217
logger.info("starting server to %s:102" % ip)
211218
return self.library.Srv_Start(self.pointer, ip)
@@ -229,15 +236,15 @@ def set_mask(self, kind, mask):
229236
def set_cpu_status(self, status):
230237
"""Sets the Virtual CPU status.
231238
"""
232-
assert status in cpu_statuses, 'unknown cpu state %s' % status
239+
assert status in snap7.types.cpu_statuses, 'unknown cpu state %s' % status
233240
logger.debug("setting cpu status to %s" % status)
234241
return self.library.Srv_SetCpuStatus(self.pointer, status)
235242

236243
def pick_event(self):
237244
"""Extracts an event (if available) from the Events queue.
238245
"""
239246
logger.debug("checking event queue")
240-
event = SrvEvent()
247+
event = snap7.types.SrvEvent()
241248
ready = ctypes.c_int32()
242249
code = self.library.Srv_PickEvent(self.pointer, ctypes.byref(event),
243250
ctypes.byref(ready))
@@ -261,7 +268,7 @@ def get_mask(self, kind):
261268
"""Reads the specified filter mask.
262269
"""
263270
logger.debug("retrieving mask kind %s" % kind)
264-
mask = longword()
271+
mask = snap7.types.longword()
265272
code = self.library.Srv_GetMask(self.pointer, kind, ctypes.byref(mask))
266273
check_error(code)
267274
return mask

snap7/types.py

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
import ctypes
55
from snap7.common import ADict
66

7-
8-
9-
107
S7Object = ctypes.c_void_p
118
buffer_size = 65536
129
buffer_type = ctypes.c_ubyte * buffer_size
@@ -15,21 +12,39 @@
1512
longword = ctypes.c_uint32
1613

1714
# // PARAMS LIST
18-
LocalPort = 1
19-
RemotePort = 2
20-
PingTimeout = 3
21-
SendTimeout = 4
22-
RecvTimeout = 5
23-
WorkInterval = 6
24-
SrcRef = 7
25-
DstRef = 8
26-
SrcTSap = 9
27-
PDURequest = 10
28-
MaxClients = 11
29-
BSendTimeout = 12
30-
BRecvTimeout = 13
31-
RecoveryTime = 14
32-
KeepAliveTime = 15
15+
LocalPort = 1
16+
RemotePort = 2
17+
PingTimeout = 3
18+
SendTimeout = 4
19+
RecvTimeout = 5
20+
WorkInterval = 6
21+
SrcRef = 7
22+
DstRef = 8
23+
SrcTSap = 9
24+
PDURequest = 10
25+
MaxClients = 11
26+
BSendTimeout = 12
27+
BRecvTimeout = 13
28+
RecoveryTime = 14
29+
KeepAliveTime = 15
30+
31+
param_types = ADict({
32+
LocalPort: ctypes.c_uint16,
33+
RemotePort: ctypes.c_uint16,
34+
PingTimeout: ctypes.c_int32,
35+
SendTimeout: ctypes.c_int32,
36+
RecvTimeout: ctypes.c_int32,
37+
WorkInterval: ctypes.c_int32,
38+
SrcRef: ctypes.c_uint16,
39+
DstRef: ctypes.c_uint16,
40+
SrcTSap: ctypes.c_uint16,
41+
PDURequest: ctypes.c_int32,
42+
MaxClients: ctypes.c_int32,
43+
BSendTimeout: ctypes.c_int32,
44+
BRecvTimeout: ctypes.c_int32,
45+
RecoveryTime: ctypes.c_uint32,
46+
KeepAliveTime: ctypes.c_uint32,
47+
})
3348

3449
# mask types
3550
mkEvent = 0
@@ -147,5 +162,5 @@ class BlocksList(ctypes.Structure):
147162
def __str__(self):
148163
return "<block list count OB: %s FB: %s FC: %s SFB: %x SFC: %s DB: %s" \
149164
" SDB: %s>" % (self.OBCount, self.FBCount, self.FCCount,
150-
self.SFBCount, self.SFCCount, self.DBCount,
151-
self.SDBCount)
165+
self.SFBCount, self.SFCCount, self.DBCount,
166+
self.SDBCount)

0 commit comments

Comments
 (0)