Skip to content

Commit 5dd8e6f

Browse files
Merge pull request #648 from bizfsc/fix/encode-phys-int64-precision
Fix encode_phys precision loss for int64 with factor=1
2 parents b73daa6 + 1eba930 commit 5dd8e6f

2 files changed

Lines changed: 38 additions & 2 deletions

File tree

canopen/objectdictionary/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,8 +492,8 @@ def decode_phys(self, value: int) -> Union[int, bool, float, str, bytes]:
492492

493493
def encode_phys(self, value: Union[int, bool, float, str, bytes]) -> int:
494494
if self.data_type in INTEGER_TYPES:
495-
value /= self.factor
496-
value = int(round(value))
495+
if self.factor != 1:
496+
value = round(value / self.factor)
497497
return value
498498

499499
def decode_desc(self, value: int) -> str:

test/test_od.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,42 @@ def test_phys(self):
182182
self.assertAlmostEqual(var.decode_phys(128), 12.8)
183183
self.assertEqual(var.encode_phys(-0.1), -1)
184184

185+
def test_phys_factor_1_int64_roundtrip(self):
186+
"""int64 values must survive encode_phys when factor is 1."""
187+
var = od.ODVariable("Test UNSIGNED64", 0x1000)
188+
var.data_type = od.UNSIGNED64
189+
value = 0x55554444AAAABBBB
190+
self.assertEqual(var.encode_phys(value), value)
191+
192+
def test_phys_factor_1_preserves_int(self):
193+
"""encode_phys with factor=1 must not convert int to float."""
194+
var = od.ODVariable("Test INTEGER32", 0x1000)
195+
var.data_type = od.INTEGER32
196+
self.assertIsInstance(var.encode_phys(42), int)
197+
198+
def test_phys_factor_1000_rounds(self):
199+
"""Integer factor > 1 uses float rounding behaviour, not truncating division."""
200+
var = od.ODVariable("Test INTEGER32", 0x1000)
201+
var.data_type = od.INTEGER32
202+
var.factor = 1000
203+
# 5555 / 1000 = 5.555 → round → 6
204+
self.assertEqual(var.encode_phys(5555), 6)
205+
206+
def test_phys_float_factor(self):
207+
"""Float factor uses float division + round."""
208+
var = od.ODVariable("Test INTEGER16", 0x1000)
209+
var.data_type = od.INTEGER16
210+
var.factor = 0.5
211+
# 10 / 0.5 = 20
212+
self.assertEqual(var.encode_phys(10), 20)
213+
214+
def test_phys_float_factor_decodes_to_float(self):
215+
"""decode_phys with float factor ensures a float result."""
216+
var = od.ODVariable("Test INTEGER32", 0x1000)
217+
var.data_type = od.INTEGER32
218+
var.factor = 1.0
219+
self.assertIsInstance(var.decode_phys(42), float)
220+
185221
def test_desc(self):
186222
var = od.ODVariable("Test UNSIGNED8", 0x1000)
187223
var.data_type = od.UNSIGNED8

0 commit comments

Comments
 (0)