Skip to content

Commit 2fe2ed3

Browse files
committed
utils: add support for 64 bits to long functions
1 parent 9577e15 commit 2fe2ed3

File tree

3 files changed

+70
-27
lines changed

3 files changed

+70
-27
lines changed

CHANGES

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ Revision history for pyModbusTCP
22

33
0.x.x Next release
44

5-
- encode_ieee and decode_ieee, now support double-precision format with opt double.
5+
- word_list_to_long() and long_list_to_word(), now support 64 bits long long with opt long_long.
6+
- encode_ieee() and decode_ieee(), now support double-precision format with opt double.
67
- add shortcut alias for functions with long names in utils.
78
- rewrite of some functions in utils.
89
- improve test_utils readability.

pyModbusTCP/utils.py

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,26 +92,39 @@ def toggle_bit(value, offset):
9292
########################
9393
# Word convert functions
9494
########################
95-
def word_list_to_long(val_list, big_endian=True):
96-
"""Word list (16 bits int) to long list (32 bits int)
95+
def word_list_to_long(val_list, big_endian=True, long_long=False):
96+
"""Word list (16 bits) to long (32 bits) or long long (64 bits) list
9797
9898
By default word_list_to_long() use big endian order. For use little endian, set
99-
big_endian param to False.
99+
big_endian param to False. Output format could be long long with long_long
100+
option set to True.
100101
101102
:param val_list: list of 16 bits int value
102103
:type val_list: list
103104
:param big_endian: True for big endian/False for little (optional)
104105
:type big_endian: bool
106+
:param long_long: True for long long 64 bits, default is long 32 bits (optional)
107+
:type long_long: bool
105108
:returns: list of 32 bits int value
106109
:rtype: list
107110
"""
108111
long_list = []
109-
# populate long_list (len is half of 16 bits val_list) with 32 bits value
110-
for i in range(int(len(val_list) / 2)):
112+
block_size = 4 if long_long else 2
113+
# populate long_list (len is half or quarter of 16 bits val_list) with 32 or 64 bits value
114+
for index in range(int(len(val_list) / block_size)):
115+
start = block_size * index
116+
l = 0
111117
if big_endian:
112-
long_list.append((val_list[i * 2] << 16) + val_list[(i * 2) + 1])
118+
if long_long:
119+
l += (val_list[start] << 48) + (val_list[start+1] << 32)
120+
l += (val_list[start+2] << 16) + (val_list[start+3])
121+
else:
122+
l += (val_list[start] << 16) + val_list[start+1]
113123
else:
114-
long_list.append((val_list[(i * 2) + 1] << 16) + val_list[i * 2])
124+
if long_long:
125+
l += (val_list[start+3] << 48) + (val_list[start+2] << 32)
126+
l += (val_list[start+1] << 16) + val_list[start]
127+
long_list.append(l)
115128
# return long list
116129
return long_list
117130

@@ -120,28 +133,34 @@ def word_list_to_long(val_list, big_endian=True):
120133
words2longs = word_list_to_long
121134

122135

123-
def long_list_to_word(val_list, big_endian=True):
124-
"""Long list (32 bits int) to word list (16 bits int)
136+
def long_list_to_word(val_list, big_endian=True, long_long=False):
137+
"""Long (32 bits) or long long (64 bits) list to word (16 bits) list
125138
126139
By default long_list_to_word() use big endian order. For use little endian, set
127-
big_endian param to False.
140+
big_endian param to False. Input format could be long long with long_long
141+
param to True.
128142
129143
:param val_list: list of 32 bits int value
130144
:type val_list: list
131145
:param big_endian: True for big endian/False for little (optional)
132146
:type big_endian: bool
147+
:param long_long: True for long long 64 bits, default is long 32 bits (optional)
148+
:type long_long: bool
133149
:returns: list of 16 bits int value
134150
:rtype: list
135151
"""
136152
word_list = []
137-
# populate 16 bits word_list with 32 bits value of val_list
153+
# populate 16 bits word_list with 32 or 64 bits value of val_list
138154
for val in val_list:
155+
block_l = []
156+
block_l.append(val & 0xffff)
157+
block_l.append((val >> 16) & 0xffff)
158+
if long_long:
159+
block_l.append((val >> 32) & 0xffff)
160+
block_l.append((val >> 48) & 0xffff)
139161
if big_endian:
140-
word_list.append(val >> 16)
141-
word_list.append(val & 0xffff)
142-
else:
143-
word_list.append(val & 0xffff)
144-
word_list.append(val >> 16)
162+
block_l.reverse()
163+
word_list.extend(block_l)
145164
# return long list
146165
return word_list
147166

tests/test_utils.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,26 +55,49 @@ def test_word_list_to_long(self):
5555
# if len of list is odd ignore last value
5656
self.assertEqual(word_list_to_long([0x1, 0x2, 0x3]), [0x10002])
5757
# test convert with big and little endian
58-
dead_l = [0xdead, 0xbeef]
58+
l1 = [0xdead, 0xbeef]
59+
l2 = [0xfeed, 0xface, 0xcafe, 0xbeef]
5960
big = dict(big_endian=True)
6061
nobig = dict(big_endian=False)
61-
self.assertEqual(words2longs(dead_l, **big), [0xdeadbeef])
62-
self.assertEqual(words2longs(dead_l*2, **big), [0xdeadbeef]*2)
63-
self.assertEqual(words2longs(dead_l, **nobig), [0xbeefdead])
64-
self.assertEqual(words2longs(dead_l*2, **nobig), [0xbeefdead]*2)
62+
big64 = dict(big_endian=True, long_long=True)
63+
nobig64 = dict(big_endian=False, long_long=True)
64+
self.assertEqual(words2longs(l1, **big), [0xdeadbeef])
65+
self.assertEqual(words2longs(l2, **big), [0xfeedface, 0xcafebeef])
66+
self.assertEqual(words2longs(l1, **nobig), [0xbeefdead])
67+
self.assertEqual(words2longs(l2, **nobig), [0xfacefeed, 0xbeefcafe])
68+
self.assertEqual(words2longs(l1*2, **big64), [0xdeadbeefdeadbeef])
69+
self.assertEqual(words2longs(l2*2, **big64), [0xfeedfacecafebeef]*2)
70+
self.assertEqual(words2longs(l1*2, **nobig64), [0xbeefdeadbeefdead])
71+
self.assertEqual(words2longs(l2*2, **nobig64), [0xbeefcafefacefeed]*2)
6572

6673
def test_long_list_to_word(self):
6774
# test long_list_to_word() and short alias longs2words()
6875
# empty list, return empty list
6976
self.assertEqual(long_list_to_word([]), [])
7077
# test convert with big and little endian
71-
dead_l = [0xdeadbeef]
78+
l1 = [0xdeadbeef]
79+
l1_big = [0xdead, 0xbeef]
80+
l1_nobig = [0xbeef, 0xdead]
81+
l1_big64 = [0x0000, 0x0000, 0xdead, 0xbeef]
82+
l1_nobig64 = [0xbeef, 0xdead, 0x0000, 0x0000]
83+
l2 = [0xfeedface, 0xcafebeef]
84+
l2_big = [0xfeed, 0xface, 0xcafe, 0xbeef]
85+
l2_nobig = [0xface, 0xfeed, 0xbeef, 0xcafe]
86+
l3 = [0xfeedfacecafebeef]
87+
l3_big64 = [0xfeed, 0xface, 0xcafe, 0xbeef]
88+
l3_nobig64 = [0xbeef, 0xcafe, 0xface, 0xfeed]
7289
big = dict(big_endian=True)
7390
nobig = dict(big_endian=False)
74-
self.assertEqual(longs2words(dead_l, **big), [0xdead, 0xbeef])
75-
self.assertEqual(longs2words(dead_l*2, **big), [0xdead, 0xbeef]*2)
76-
self.assertEqual(longs2words(dead_l, **nobig), [0xbeef, 0xdead])
77-
self.assertEqual(longs2words(dead_l*2, **nobig), [0xbeef, 0xdead]*2)
91+
big64 = dict(big_endian=True, long_long=True)
92+
nobig64 = dict(big_endian=False, long_long=True)
93+
self.assertEqual(longs2words(l1, **big), l1_big)
94+
self.assertEqual(longs2words(l2, **big), l2_big)
95+
self.assertEqual(longs2words(l1, **nobig), l1_nobig)
96+
self.assertEqual(longs2words(l2, **nobig), l2_nobig)
97+
self.assertEqual(longs2words(l1*2, **big64), l1_big64*2)
98+
self.assertEqual(longs2words(l3*2, **big64), l3_big64*2)
99+
self.assertEqual(longs2words(l1*4, **nobig64), l1_nobig64*4)
100+
self.assertEqual(longs2words(l3*4, **nobig64), l3_nobig64*4)
78101

79102
def test_get_2comp(self):
80103
# test get_2comp() and short alias twos_c()

0 commit comments

Comments
 (0)