Browse Source

fix BCD fields encoding

For some case the encode function was raising AssertionError despite
the BCD value beeing correct (in this case it was 1.11).

There is two main modification in the version I propose:

First the added rounding before converting the "percent" to an integer.
This may seems odd but it is actually to "correct" the error introduce
by the multiplication.

Second the comparison is done "after" conversion by recreating the
floating point value from the integer and percent variables. This is to
make sure that the value in the descriptor is the same as intended.

I've made sure that all correct values (that can be stored in bcd fields)
doesn't raise an error when passed to the encode function.

I've used the following program to test the new implementation:
```
for obj in [float(f"{i:02}.{p:02}") for i in range(100) for p in range(100)]:
    integer = int(obj) % 100
    percent = int(round(obj * 100)) % 100
    if float(f"{integer:02}.{percent:02}") != obj:
        print (f"BCD conversion error: {integer:02}.{percent:02} != {obj}")
```
main
dokthar 4 years ago
parent
commit
1d1408cb49
1 changed files with 6 additions and 6 deletions
  1. +6
    -6
      usb_protocol/types/descriptor.py

+ 6
- 6
usb_protocol/types/descriptor.py View File

@@ -87,13 +87,13 @@ class BCDFieldAdapter(construct.Adapter):

def _encode(self, obj, context, path):

# Ensure the data is parseable.
if (obj * 100) % 1:
raise AssertionError("BCD fields must be in the format XX.YY")

# Break the object down into its component parts...
integer = int(obj)
percent = int((obj * 100) % 100)
integer = int(obj) % 100
percent = int(round(obj * 100)) % 100

# ... make sure nothing is lost during conversion...
if float(f"{integer:02}.{percent:02}") != obj:
raise AssertionError("BCD fields must be in the format XX.YY")

# ... and squish them into an integer.
return int(f"{integer:02}{percent:02}", 16)


Loading…
Cancel
Save