Skip to content

Commit 8e2dd94

Browse files
committed
Merge pull request gijzelaerr#28 from lance5107B/master
Add support for Cli_ReadMultiVars
2 parents eeaea98 + 272a6a8 commit 8e2dd94

4 files changed

Lines changed: 164 additions & 0 deletions

File tree

example/read_multi.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""
2+
Example ussage of the read_multi_vars function
3+
4+
This was tested against a S7-319 CPU
5+
"""
6+
7+
import ctypes
8+
import struct
9+
10+
import snap7
11+
from snap7.common import check_error
12+
from snap7.snap7types import S7DataItem, S7AreaDB, S7WLByte
13+
14+
15+
client = snap7.client.Client()
16+
client.connect('10.100.5.2', 0, 2)
17+
18+
data_items = (S7DataItem * 3)()
19+
20+
data_items[0].Area = ctypes.c_int32(S7AreaDB)
21+
data_items[0].WordLen = ctypes.c_int32(S7WLByte)
22+
data_items[0].Result = ctypes.c_int32(0)
23+
data_items[0].DBNumber = ctypes.c_int32(200)
24+
data_items[0].Start = ctypes.c_int32(16)
25+
data_items[0].Amount = ctypes.c_int32(4) # reading a REAL, 4 bytes
26+
27+
data_items[1].Area = ctypes.c_int32(S7AreaDB)
28+
data_items[1].WordLen = ctypes.c_int32(S7WLByte)
29+
data_items[1].Result = ctypes.c_int32(0)
30+
data_items[1].DBNumber = ctypes.c_int32(200)
31+
data_items[1].Start = ctypes.c_int32(12)
32+
data_items[1].Amount = ctypes.c_int32(4) # reading a REAL, 4 bytes
33+
34+
data_items[2].Area = ctypes.c_int32(S7AreaDB)
35+
data_items[2].WordLen = ctypes.c_int32(S7WLByte)
36+
data_items[2].Result = ctypes.c_int32(0)
37+
data_items[2].DBNumber = ctypes.c_int32(200)
38+
data_items[2].Start = ctypes.c_int32(2)
39+
data_items[2].Amount = ctypes.c_int32(2) # reading an INT, 2 bytes
40+
41+
# create buffers to receive the data
42+
# use the Amount attribute on each item to size the buffer
43+
for di in data_items:
44+
# create the buffer
45+
buffer = ctypes.create_string_buffer(di.Amount)
46+
47+
# cast the pointer to the buffer to the required type
48+
pBuffer = ctypes.cast(ctypes.pointer(buffer),
49+
ctypes.POINTER(ctypes.c_uint8))
50+
di.pData = pBuffer
51+
52+
result, data_items = client.read_multi_vars(data_items)
53+
54+
for di in data_items:
55+
check_error(di.Result)
56+
57+
# struct formats
58+
fmts = ['>f', '>f', '>h']
59+
60+
# unpack and print the result of each read
61+
for i in range(0, len(data_items)):
62+
fmt = fmts[i]
63+
di = data_items[i]
64+
foo = ''.join([chr(di.pData[i]) for i in range(0, di.Amount)])
65+
fnum = struct.unpack(fmt, foo)[0]
66+
print(fnum)
67+
68+
client.disconnect()
69+
client.destroy()

snap7/client.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,17 @@ def write_area(self, area, dbnumber, start, data):
228228
return self.library.Cli_WriteArea(self.pointer, area, dbnumber, start,
229229
size, wordlen, byref(cdata))
230230

231+
def read_multi_vars(self, items):
232+
"""This function read multiple variables from the PLC.
233+
234+
:param items: list of S7DataItem objects
235+
:returns: a tuple with the return code and a list of data items
236+
"""
237+
result = self.library.Cli_ReadMultiVars(self.pointer, byref(items),
238+
c_int32(len(items)))
239+
check_error(result, context="client")
240+
return result, items
241+
231242
def list_blocks(self):
232243
"""Returns the AG blocks amount divided by type.
233244

snap7/snap7types.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,15 @@ def __str__(self):
164164
" SDB: %s>" % (self.OBCount, self.FBCount, self.FCCount,
165165
self.SFBCount, self.SFCCount, self.DBCount,
166166
self.SDBCount)
167+
168+
class S7DataItem(ctypes.Structure):
169+
_pack_ = 1
170+
_fields_ = [
171+
('Area', ctypes.c_int32),
172+
('WordLen', ctypes.c_int32),
173+
('Result', ctypes.c_int32),
174+
('DBNumber', ctypes.c_int32),
175+
('Start', ctypes.c_int32),
176+
('Amount', ctypes.c_int32),
177+
('pData', ctypes.POINTER(ctypes.c_uint8))
178+
]

test/test_client.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import ctypes
2+
import struct
13
import unittest
24
import logging
35
import time
46
from subprocess import Popen
57
from os import path, kill
68
import snap7
79
from snap7.snap7exceptions import Snap7Exception
10+
from snap7.snap7types import S7AreaDB, S7WLByte, S7DataItem
811

912

1013
logging.basicConfig(level=logging.WARNING)
@@ -54,6 +57,75 @@ def test_db_write(self):
5457
def test_db_get(self):
5558
self.client.db_get(db_number=db_number)
5659

60+
def test_read_multi_vars(self):
61+
db = 1
62+
63+
# build and write test values
64+
test_value_1 = 129.5
65+
test_bytes_1 = bytearray(struct.pack('>f', test_value_1))
66+
self.client.db_write(db, 0, test_bytes_1)
67+
68+
test_value_2 = -129.5
69+
test_bytes_2 = bytearray(struct.pack('>f', test_value_2))
70+
self.client.db_write(db, 4, test_bytes_2)
71+
72+
test_value_3 = -123
73+
test_bytes_3 = bytearray(struct.pack('>h', test_value_3))
74+
self.client.db_write(db, 8, test_bytes_3)
75+
76+
test_values = [test_value_1, test_value_2, test_value_3]
77+
78+
# build up our requests
79+
data_items = (S7DataItem * 3)()
80+
81+
data_items[0].Area = ctypes.c_int32(S7AreaDB)
82+
data_items[0].WordLen = ctypes.c_int32(S7WLByte)
83+
data_items[0].Result = ctypes.c_int32(0)
84+
data_items[0].DBNumber = ctypes.c_int32(db)
85+
data_items[0].Start = ctypes.c_int32(0)
86+
data_items[0].Amount = ctypes.c_int32(4) # reading a REAL, 4 bytes
87+
88+
data_items[1].Area = ctypes.c_int32(S7AreaDB)
89+
data_items[1].WordLen = ctypes.c_int32(S7WLByte)
90+
data_items[1].Result = ctypes.c_int32(0)
91+
data_items[1].DBNumber = ctypes.c_int32(db)
92+
data_items[1].Start = ctypes.c_int32(4)
93+
data_items[1].Amount = ctypes.c_int32(4) # reading a REAL, 4 bytes
94+
95+
data_items[2].Area = ctypes.c_int32(S7AreaDB)
96+
data_items[2].WordLen = ctypes.c_int32(S7WLByte)
97+
data_items[2].Result = ctypes.c_int32(0)
98+
data_items[2].DBNumber = ctypes.c_int32(db)
99+
data_items[2].Start = ctypes.c_int32(8)
100+
data_items[2].Amount = ctypes.c_int32(2) # reading an INT, 2 bytes
101+
102+
# create buffers to receive the data
103+
# use the Amount attribute on each item to size the buffer
104+
for di in data_items:
105+
# create the buffer
106+
dataBuffer = ctypes.create_string_buffer(di.Amount)
107+
# get a pointer to the buffer
108+
pBuffer = ctypes.cast(ctypes.pointer(dataBuffer),
109+
ctypes.POINTER(ctypes.c_uint8))
110+
di.pData = pBuffer
111+
112+
result, data_items = self.client.read_multi_vars(data_items)
113+
114+
result_values = []
115+
# struct formats to match data_items[] above
116+
fmts = ['>f', '>f', '>h']
117+
# unpack and test the result of each read
118+
for i in xrange(0, len(data_items)):
119+
fmt = fmts[i]
120+
di = data_items[i]
121+
bytes_str = ''.join([chr(di.pData[j]) for j in range(0, di.Amount)])
122+
result_values.append(struct.unpack(fmt, bytes_str)[0])
123+
124+
self.assertEqual(result_values[0], test_values[0])
125+
self.assertEqual(result_values[1], test_values[1])
126+
self.assertEqual(result_values[2], test_values[2])
127+
128+
57129
def test_upload(self):
58130
"""
59131
this raises an exception due to missing authorization? maybe not

0 commit comments

Comments
 (0)