eds: fix signed integer limit parsing and export for all SIGNED_TYPES#658
eds: fix signed integer limit parsing and export for all SIGNED_TYPES#658friederschueler wants to merge 5 commits into
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
Please always separate style changes from functional changes. Except of course fixing in the immediate vicinity of the functional changes. |
131f43e to
27e94d8
Compare
- Replace _calc_bit_length() (only handled INTEGER8/16/32/64) with a lookup dict _SIGNED_BIT_LENGTHS covering all 8 SIGNED_TYPES (INTEGER8/16/24/32/40/48/56/64) - Log a warning instead of silently ignoring invalid limit values (except ValueError: pass) - Add EDS test entries in sample.eds for INTEGER24/40/48/56 with hex-encoded negative limits - Extend test_record_with_limits and add test_invalid_limit_logs_warning Closes part of canopen-python#352.
27e94d8 to
f65a1fb
Compare
friederschueler
left a comment
There was a problem hiding this comment.
As the old importer couldn't use decimal format for signed limits, but we exported decimal there was definitively a bug. Now we also export in hex format by default, which is more common in eds I think. We could change that, or we could remember on import the exact format and then export it in that format, but this seems like an overkill.
|
Thanks for drilling deeper, the incomplete number parsing really was a nuisance. I don't know which is more common, hex or decimal for the limit values in EDS files. My random sample shows both in use, but never hexadecimal coding for negative limits. But definitely, any format with a leading minus sign is easier to grasp than writing two's complement hex numbers. Since that is very uncommon for hexadecimal numbers though, I'd favor defaulting to plain decimal notation on export. CiA 306 never mentions negative numbers, let alone writing any number in two's complement. But we can keep this special parsing feature of course. Need another slot of free time to finish reviewing, sorry for this incomplete feedback... |
| """Format an integer as EDS hex string. | ||
|
|
||
| Signed types with a negative value are written as two's-complement hex | ||
| (e.g. INTEGER8 -1 → 0xFF) so the output is a valid EDS literal. |
There was a problem hiding this comment.
According to CiA 306:
Integer numbers shall be written as decimal numbers, hexadecimal numbers or octal numbers.
I don't see any need to restrict ourselves to writing hex or two's complement at all. We may still accept it, though, as the data type rules are very clear on the possible interpretation. But the spec doesn't mention this at all.
It's also completely unclear how to handle floating point numbers in EDS files. I guess if we can parse them in Python, we can accept them. But I wouldn't assume any particular conversion to apply for a literal in hex notation: It's fine to write -0xFFFF.FF as a theoretical floating-point number noted in hex, just that Python only parses decimal floats.
>>> float(int("-0xFFFF", 16)) # this works fine, but not directly
-65535.0Just because CiA 301 defines a wire format for REAL types, doesn't mean we should try parsing hexadecimal byte sequences as IEEE floats. When exporting, the best approach I can see is to simply use Python's float to string conversion. This function gets in the way though, prohibiting us from writing anything but integer limits at all. Why not simply use _revert_variable() for the limits as well? The fall-back (integer) case in there can still do some limit checking, but no hex conversion.
Fixes incomplete and incorrect signed integer handling for
LowLimit/HighLimitin EDS parsing and export, as noted in #352.Changes
_calc_bit_length— extended to all SIGNED_TYPESThe existing function only handled INTEGER8/16/32/64. It now covers all 8
SIGNED_TYPES(INTEGER8/16/24/32/40/48/56/64) by deriving the bit width dynamically fromODVariable.STRUCT_TYPESinstead of a hardcoded if/elif chain._signed_int_from_hex— decimal and hex support, range validationThe parser now accepts both formats for
LowLimit/HighLimit:0xFFFFfor INTEGER16 →-1)-32768for INTEGER16 →-32768)An explicit
ValueErroris raised if the value does not fit in the type's bit width. Previously, a value like0xFFFFfor an 8-bit field would silently produce a wrong result._int_to_hex— new helper for EDS integer serializationFormats any integer as a valid EDS hex literal. Negative signed values are written as two's-complement unsigned hex (e.g. INTEGER32
-1→0xFFFFFFFF), which is the canonical EDS format. Used by_revert_variableand the export ofLowLimit/HighLimit._revert_variable— fix for negative integersPreviously used
f"0x{value:02X}"unconditionally, which raisesValueErrorfor negative values and broke export of any negativeDefaultValue. Now delegates to_int_to_hex.Export of
LowLimit/HighLimitPreviously written as raw Python integers (e.g.
-2147483648). Now uses_int_to_hexto produce canonical unsigned two's-complement hex.Silent parse errors →
logger.warningAll
except ValueError: passblocks inbuild_variablenow log the field name, value, object name and index:LowLimit,HighLimit,DefaultValue,ParameterValue,FactorDead
try/except ValueErroraroundDescriptionandUnitremoved —ConfigParser.get()never raisesValueError.Tests
sample.edsentries covering all four combinations of signed/unsigned × hex/decimal limitstest_record_with_limitsas a table-driven test withsubTesttest_signed_int_from_hex_accepts_decimalandtest_signed_int_from_hex_rejects_out_of_rangeCloses part of #352.