Skip to content

Commit 9d54fe5

Browse files
committed
Revert "Bit handling LSB -> MSB across bytes. (#2634)"
This reverts commit 968564c.
1 parent 2c948c6 commit 9d54fe5

File tree

5 files changed

+54
-46
lines changed

5 files changed

+54
-46
lines changed

API_changes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ API changes 3.10.0
88
- payload removed (replaced by "convert_to/from_registers")
99
- slave=, slaves= replaced by device_id=, device_ids=
1010
- slave request names changed to device
11+
<<<<<<< HEAD
1112
- bit handling order is LSB (last byte) -> MSB (first byte)
1213
readCoils and other bit functions now return bit in logical order (NOT byte order)
1314

@@ -22,6 +23,8 @@ API changes 3.10.0
2223
Hex bytes: 0x01 0x03
2324
Older versions would deliver True False * 7 True True False * 6
2425
V3.10 deliver True True False * 6 True False * 7
26+
=======
27+
>>>>>>> parent of 968564c0 (Bit handling LSB -> MSB across bytes. (#2634))
2528

2629
API changes 3.9.0
2730
-----------------

doc/source/upgrade_40.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ Pymodbus 4.0 upgrade procedure
44
Pymodbus 4.0 contains a number of incompatibilities with Pymodbus 3.x, however
55
most of these are simple edits.
66

7+
<<<<<<< HEAD
78

9+
=======
10+
>>>>>>> parent of 968564c0 (Bit handling LSB -> MSB across bytes. (#2634))
811
Python 3.9
912
----------
1013
Python 3.9 is reaching end of life and from october 2025 no longer receives security updates.

pymodbus/pdu/pdu.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,15 @@ def pack_bitstring(bits: list[bool], align_byte=True) -> bytes:
166166
bits_extra = 8 if align_byte else 16
167167
if (extra := len(bits) % bits_extra):
168168
t_bits += [False] * (bits_extra - extra)
169-
for bit in reversed(t_bits):
170-
packed <<= 1
171-
if bit:
172-
packed += 1
173-
i += 1
174-
if i == 8:
175-
ret += struct.pack(">B", packed)
176-
i = packed = 0
169+
for byte_inx in range(0, len(t_bits), 8):
170+
for bit in reversed(t_bits[byte_inx:byte_inx+8]):
171+
packed <<= 1
172+
if bit:
173+
packed += 1
174+
i += 1
175+
if i == 8:
176+
ret += struct.pack(">B", packed)
177+
i = packed = 0
177178
return ret
178179

179180

@@ -185,13 +186,11 @@ def unpack_bitstring(data: bytes) -> list[bool]:
185186
bytes 0x05 0x81
186187
result = unpack_bitstring(bytes)
187188
188-
[True, False, False, False] +
189-
[False, False, False, True] +
190-
[True, False, True, False] +
191-
[False, False, False, False]
189+
[True, False, True, False] + [False, False, False, False]
190+
[True, False, False, False] + [False, False, False, True]
192191
"""
193192
res = []
194-
for byte_index in range(len(data) -1, -1, -1):
193+
for _, t_byte in enumerate(data):
195194
for bit in (1, 2, 4, 8, 16, 32, 64, 128):
196-
res.append(bool(data[byte_index] & bit))
195+
res.append(bool(t_byte & bit))
197196
return res

test/client/test_client.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,49 +176,49 @@ def fake_execute(_self, _no_response_expected, request):
176176
(
177177
ModbusClientMixin.DATATYPE.BITS,
178178
[True] + [False] * 15,
179-
[1], # 0x00 0x01
179+
[256], # 0x01 0x00
180180
None,
181181
),
182182
(
183183
ModbusClientMixin.DATATYPE.BITS,
184184
[False] * 8 + [True] + [False] * 7,
185-
[256], # 0x01 0x00
185+
[1], # 0x00 0x01
186186
None,
187187
),
188188
(
189189
ModbusClientMixin.DATATYPE.BITS,
190190
[False] * 15 + [True],
191-
[32768], # 0x80 0x00
191+
[128], # 0x00 0x80
192192
None,
193193
),
194194
(
195195
ModbusClientMixin.DATATYPE.BITS,
196196
[True] + [False] * 14 + [True],
197-
[32769], # 0x80 0x01
197+
[384], # 0x01 0x80
198198
None,
199199
),
200200
(
201201
ModbusClientMixin.DATATYPE.BITS,
202202
[False] * 8 + [True, False, True] + [False] * 5,
203-
[1280], # 0x05 0x00
203+
[5], # 0x00 0x05
204204
None,
205205
),
206206
(
207207
ModbusClientMixin.DATATYPE.BITS,
208208
[True] + [False] * 7 + [True, False, True] + [False] * 5,
209-
[1281], # 0x05 0x01
209+
[261], # 0x01 0x05
210210
None,
211211
),
212212
(
213213
ModbusClientMixin.DATATYPE.BITS,
214214
[True] + [False] * 6 + [True, True, False, True] + [False] * 5,
215-
[1409], # 0x05 0x81
215+
[33029], # 0x81 0x05
216216
None,
217217
),
218218
(
219219
ModbusClientMixin.DATATYPE.BITS,
220220
[False] * 8 + [True] + [False] * 7 + [True] + [False] * 6 + [True, True, False, True] + [False] * 5,
221-
[1409, 256], # 92340480 = 0x05 0x81 0x01 0x00
221+
[1, 33029], # 92340480 = 0x00 0x01 0x81 0x05
222222
None,
223223
),
224224
],

test/pdu/test_pdu.py

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -255,21 +255,21 @@ async def test_pdu_default_datastore(self, mock_context):
255255
@pytest.mark.parametrize(
256256
("bytestream", "bitlist"),
257257
[
258-
(b"\x00\x01", [True] + [False] * 15),
259-
(b"\x01\x00", [False] * 8 + [True] + [False] * 7),
260-
(b"\x80\x00", [False] * 15 + [True]),
261-
(b"\x80\x01", [True] + [False] * 14 + [True]),
262-
(b"\x05\x00", [False] * 8 + [True, False, True] + [False] * 5),
263-
(b"\x05\x01", [True] + [False] * 7 + [True, False, True] + [False] * 5),
264-
(b"\x05\x81", [True] + [False] * 6 + [True, True, False, True] + [False] * 5),
265-
(b"\x05\x81\x01\x00", [False] * 8 + [True] + [False] * 7 + [True] + [False] * 6 + [True, True, False, True] + [False] * 5),
258+
(b"\x01\x00", [True] + [False] * 15),
259+
(b"\x00\x80", [False] * 15 + [True]),
260+
(b"\x00\x01", [False] * 8 + [True] + [False] * 7),
261+
(b"\x01\x80", [True] + [False] * 14 + [True]),
262+
(b"\x00\x05", [False] * 8 + [True, False, True] + [False] * 5),
263+
(b"\x01\x05", [True] + [False] * 7 + [True, False, True] + [False] * 5),
264+
(b"\x81\x05", [True] + [False] * 6 + [True, True, False, True] + [False] * 5),
265+
(b"\x00\x01\x81\x05", [False] * 8 + [True] + [False] * 7 + [True] + [False] * 6 + [True, True, False, True] + [False] * 5),
266266
267-
(b"\x00\x01", [True]),
268-
(b"\x01\x00", [False] * 8 + [True]),
269-
(b"\x05\x00", [False] * 8 + [True, False, True]),
270-
(b"\x05\x01", [True] + [False] * 7 + [True, False, True]),
271-
(b"\x05\x81", [True] + [False] * 6 + [True, True, False, True]),
272-
(b"\x05\x81\x01\x00", [False] * 8 + [True] + [False] * 7 + [True] + [False] * 6 + [True, True, False, True]),
267+
(b"\x01\x00", [True]),
268+
(b"\x00\x01", [False] * 8 + [True]),
269+
(b"\x00\x05", [False] * 8 + [True, False, True]),
270+
(b"\x01\x05", [True] + [False] * 7 + [True, False, True]),
271+
(b"\x81\x05", [True] + [False] * 6 + [True, True, False, True]),
272+
(b"\x00\x01\x81\x05", [False] * 8 + [True] + [False] * 7 + [True] + [False] * 6 + [True, True, False, True]),
273273
],
274274
)
275275
def test_bit_packing(self, bytestream, bitlist):
@@ -280,9 +280,9 @@ def test_bit_packing(self, bytestream, bitlist):
280280
("bytestream", "bitlist"),
281281
[
282282
(b"\x01", [True]),
283-
(b"\x01\x00", [False] * 8 + [True]),
283+
(b"\x00\x01", [False] * 8 + [True]),
284284
(b"\x05", [True, False, True]),
285-
(b"\x05\x01", [True] + [False] * 7 + [True, False, True]),
285+
(b"\x01\x05", [True] + [False] * 7 + [True, False, True]),
286286
],
287287
)
288288
def test_bit_packing8(self, bytestream, bitlist):
@@ -293,14 +293,17 @@ def test_bit_packing8(self, bytestream, bitlist):
293293
("bytestream", "bitlist"),
294294
[
295295
(b"\x01", [True] + [False] * 7),
296-
(b"\x00\x01", [True] + [False] * 15),
297-
(b"\x01\x00", [False] * 8 + [True] + [False] * 7),
298-
(b"\x80\x00", [False] * 15 + [True]),
299-
(b"\x80\x01", [True] + [False] * 14 + [True]),
300-
(b"\x05\x00", [False] * 8 + [True, False, True] + [False] * 5),
301-
(b"\x05\x01", [True] + [False] * 7 + [True, False, True] + [False] * 5),
302-
(b"\x05\x81", [True] + [False] * 6 + [True, True, False, True] + [False] * 5),
303-
(b"\x05\x81\x01\x00", [False] * 8 + [True] + [False] * 7 + [True] + [False] * 6 + [True, True, False, True] + [False] * 5),
296+
(b"\x01\x00", [True] + [False] * 15),
297+
(b"\x00\x01", [False] * 8 + [True] + [False] * 7),
298+
(b"\x00\x80", [False] * 15 + [True]),
299+
(b"\x01\x80", [True] + [False] * 14 + [True]),
300+
(b"\x00\x05", [False] * 8 + [True, False, True] + [False] * 5),
301+
(b"\x01\x05", [True] + [False] * 7 + [True, False, True] + [False] * 5),
302+
(b"\x81\x05", [True] + [False] * 6 + [True, True, False, True] + [False] * 5),
303+
(b"\x05\x81\x01\x00", [True, False, True] + [False] * 5 +
304+
[True] + [False] * 6 + [True] +
305+
[True] + [False] * 7 +
306+
[False] * 8),
304307
],
305308
)
306309
def test_bit_unpacking(self, bytestream, bitlist):

0 commit comments

Comments
 (0)