@@ -204,26 +204,28 @@ def import_from_node(node_id: int, network: canopen.network.Network):
204204 return od
205205
206206
207- _SIGNED_BIT_LENGTHS = {
208- datatypes .INTEGER8 : 8 ,
209- datatypes . INTEGER16 : 16 ,
210- datatypes .INTEGER24 : 24 ,
211- datatypes . INTEGER32 : 32 ,
212- datatypes . INTEGER40 : 40 ,
213- datatypes . INTEGER48 : 48 ,
214- datatypes . INTEGER56 : 56 ,
215- datatypes . INTEGER64 : 64 ,
216- }
207+ def _calc_bit_length ( data_type : int ) -> int :
208+ if data_type in datatypes .SIGNED_TYPES :
209+ st = ODVariable . STRUCT_TYPES [ data_type ]
210+ if isinstance ( st , datatypes .IntegerN ):
211+ return st . width
212+ return st . size * 8
213+ else :
214+ raise ValueError (
215+ f"Invalid data_type ' { data_type } ', expecting a signed integer data_type."
216+ )
217217
218218
219219def _signed_int_from_hex (hex_str , bit_length ):
220220 number = int (hex_str , 0 )
221+ if number < 0 or number >= (1 << bit_length ):
222+ raise ValueError (
223+ f"Value { hex_str !r} is out of range for a { bit_length } -bit signed integer"
224+ )
221225 max_value = (1 << (bit_length - 1 )) - 1
222-
223226 if number > max_value :
224227 return number - (1 << bit_length )
225- else :
226- return number
228+ return number
227229
228230
229231def _convert_variable (node_id , var_type , value ):
@@ -242,6 +244,18 @@ def _convert_variable(node_id, var_type, value):
242244 return int (value , 0 )
243245
244246
247+ def _int_to_hex (data_type : int , value : int ) -> str :
248+ """Format an integer as EDS hex string.
249+
250+ Signed types with a negative value are written as two's-complement hex
251+ (e.g. INTEGER8 -1 → 0xFF) so the output is a valid EDS literal.
252+ """
253+ if data_type in datatypes .SIGNED_TYPES and value < 0 :
254+ bit_length = _calc_bit_length (data_type )
255+ return f"0x{ value + (1 << bit_length ):0{bit_length // 4 }X} "
256+ return f"0x{ value :02X} "
257+
258+
245259def _revert_variable (var_type , value ):
246260 if value is None :
247261 return None
@@ -252,7 +266,7 @@ def _revert_variable(var_type, value):
252266 elif var_type in datatypes .FLOAT_TYPES :
253267 return value
254268 else :
255- return f"0x { value :02X } "
269+ return _int_to_hex ( var_type , value )
256270
257271
258272def build_variable (
@@ -302,51 +316,60 @@ def build_variable(
302316 try :
303317 min_string = eds .get (section , "LowLimit" )
304318 if var .data_type in datatypes .SIGNED_TYPES :
305- var .min = _signed_int_from_hex (min_string , _SIGNED_BIT_LENGTHS [ var .data_type ] )
319+ var .min = _signed_int_from_hex (min_string , _calc_bit_length ( var .data_type ) )
306320 else :
307321 var .min = int (min_string , 0 )
308322 except ValueError :
309- pass
323+ logger .warning (
324+ "Invalid LowLimit %r for %s (0x%X), ignoring" ,
325+ eds .get (section , "LowLimit" ), var .name , var .index ,
326+ )
310327 if eds .has_option (section , "HighLimit" ):
311328 try :
312329 max_string = eds .get (section , "HighLimit" )
313330 if var .data_type in datatypes .SIGNED_TYPES :
314- var .max = _signed_int_from_hex (max_string , _SIGNED_BIT_LENGTHS [ var .data_type ] )
331+ var .max = _signed_int_from_hex (max_string , _calc_bit_length ( var .data_type ) )
315332 else :
316333 var .max = int (max_string , 0 )
317334 except ValueError :
318- pass
335+ logger .warning (
336+ "Invalid HighLimit %r for %s (0x%X), ignoring" ,
337+ eds .get (section , "HighLimit" ), var .name , var .index ,
338+ )
319339 if eds .has_option (section , "DefaultValue" ):
320340 try :
321341 var .default_raw = eds .get (section , "DefaultValue" )
322342 if '$NODEID' in var .default_raw :
323343 var .relative = True
324344 var .default = _convert_variable (node_id , var .data_type , var .default_raw )
325345 except ValueError :
326- pass
346+ logger .warning (
347+ "Invalid DefaultValue %r for %s (0x%X), ignoring" ,
348+ var .default_raw , var .name , var .index ,
349+ )
327350 if eds .has_option (section , "ParameterValue" ):
328351 try :
329352 var .value_raw = eds .get (section , "ParameterValue" )
330353 var .value = _convert_variable (node_id , var .data_type , var .value_raw )
331354 except ValueError :
332- pass
355+ logger .warning (
356+ "Invalid ParameterValue %r for %s (0x%X), ignoring" ,
357+ var .value_raw , var .name , var .index ,
358+ )
333359 # Factor, Description and Unit are not standard according to the CANopen specifications, but
334360 # they are implemented in the python canopen package, so we can at least try to use them
335361 if eds .has_option (section , "Factor" ):
336362 try :
337363 var .factor = float (eds .get (section , "Factor" ))
338364 except ValueError :
339- pass
365+ logger .warning (
366+ "Invalid Factor %r for %s (0x%X), ignoring" ,
367+ eds .get (section , "Factor" ), var .name , var .index ,
368+ )
340369 if eds .has_option (section , "Description" ):
341- try :
342- var .description = eds .get (section , "Description" )
343- except ValueError :
344- pass
370+ var .description = eds .get (section , "Description" )
345371 if eds .has_option (section , "Unit" ):
346- try :
347- var .unit = eds .get (section , "Unit" )
348- except ValueError :
349- pass
372+ var .unit = eds .get (section , "Unit" )
350373 return var
351374
352375
@@ -411,9 +434,9 @@ def export_variable(var, eds):
411434 eds .set (section , "PDOMapping" , hex (var .pdo_mappable ))
412435
413436 if getattr (var , 'min' , None ) is not None :
414- eds .set (section , "LowLimit" , var .min )
437+ eds .set (section , "LowLimit" , _int_to_hex ( var .data_type , var . min ) )
415438 if getattr (var , 'max' , None ) is not None :
416- eds .set (section , "HighLimit" , var .max )
439+ eds .set (section , "HighLimit" , _int_to_hex ( var .data_type , var . max ) )
417440
418441 if getattr (var , 'description' , '' ) != '' :
419442 eds .set (section , "Description" , var .description )
0 commit comments