@@ -74,13 +74,13 @@ def get_static_bit_length(self) -> Optional[int]:
74
74
return ((length + 7 ) // 8 ) * 8
75
75
76
76
def coded_const_prefix (self , request_prefix : bytes = b'' ) -> bytes :
77
- prefix = b''
78
77
encode_state = EncodeState (
79
- bytearray (prefix ), parameter_values = {}, triggering_request = request_prefix )
78
+ coded_message = bytearray (), parameter_values = {}, triggering_request = request_prefix )
79
+
80
80
for param in self .parameters :
81
- if isinstance (param , ( CodedConstParameter , NrcConstParameter , MatchingRequestParameter ,
82
- PhysicalConstantParameter )):
83
- encode_state . coded_message = bytearray ( param .encode_into_pdu (encode_state ) )
81
+ if ( isinstance (param , MatchingRequestParameter ) and param . request_byte_position < len ( request_prefix )) or \
82
+ isinstance ( param , ( CodedConstParameter , NrcConstParameter , PhysicalConstantParameter )):
83
+ param .encode_into_pdu (physical_value = None , encode_state = encode_state )
84
84
else :
85
85
break
86
86
return encode_state .coded_message
@@ -122,52 +122,63 @@ def convert_physical_to_internal(self,
122
122
triggering_coded_request : Optional [bytes ],
123
123
is_end_of_pdu : bool = True ) -> bytes :
124
124
125
+ encode_state = EncodeState (
126
+ bytearray (),
127
+ parameter_values = cast (Dict [str , ParameterValue ], param_value ),
128
+ triggering_request = triggering_coded_request ,
129
+ is_end_of_pdu = False )
130
+
125
131
if not isinstance (param_value , dict ):
126
- raise EncodeError (
132
+ odxraise (
127
133
f"Expected a dictionary for the values of structure { self .short_name } , "
128
- f"got { type (param_value )} " )
134
+ f"got { type (param_value ).__name__ } " , EncodeError )
135
+ elif encode_state .cursor_bit_position != 0 :
136
+ odxraise (
137
+ f"Structures must be byte aligned, but "
138
+ f"{ self .short_name } requested to be at bit position "
139
+ f"{ encode_state .cursor_bit_position } " , EncodeError )
140
+ encode_state .bit_position = 0
129
141
130
142
# in strict mode, ensure that no values for unknown parameters are specified.
131
143
if strict_mode :
132
- param_names = [param .short_name for param in self .parameters ]
133
- for param_key in param_value :
134
- if param_key not in param_names :
135
- odxraise (f"Value for unknown parameter '{ param_key } ' specified" )
136
-
137
- encode_state = EncodeState (
138
- bytearray (),
139
- dict (param_value ),
140
- triggering_request = triggering_coded_request ,
141
- is_end_of_pdu = False )
144
+ param_names = {param .short_name for param in self .parameters }
145
+ for param_value_name in param_value :
146
+ if param_value_name not in param_names :
147
+ odxraise (f"Value for unknown parameter '{ param_value_name } ' specified "
148
+ f"for structure { self .short_name } " )
142
149
143
150
for param in self .parameters :
144
- if param == self .parameters [- 1 ]:
145
- # The last parameter is at the end of the PDU if the
146
- # structure itself is at the end of the PDU. TODO:
147
- # This assumes that the last parameter specified in
148
- # the ODX is located last in the PDU...
151
+ if id ( param ) == id ( self .parameters [- 1 ]) :
152
+ # The last parameter of the structure is at the end of
153
+ # the PDU if the structure itself is at the end of the
154
+ # PDU. TODO: This assumes that the last parameter
155
+ # specified in the ODX is located last in the PDU...
149
156
encode_state .is_end_of_pdu = is_end_of_pdu
150
157
151
- if isinstance (
152
- param ,
153
- (LengthKeyParameter , TableKeyParameter )) and param .short_name in param_value :
154
- # This is a hack to always encode a dummy value for
155
- # length- and table keys. since these can be specified
158
+ if isinstance (param , (LengthKeyParameter , TableKeyParameter )):
159
+ # At this point, we encode a placeholder value for length-
160
+ # and table keys, since these can be specified
156
161
# implicitly (i.e., by means of parameters that use
157
- # these keys), to avoid getting an "overlapping
162
+ # these keys). To avoid getting an "overlapping
158
163
# parameter" warning, we must encode a value of zero
159
164
# into the PDU here and add the real value of the
160
- # parameter in a post processing step.
161
- tmp = encode_state . parameter_values . pop ( param .short_name )
162
- encode_state . coded_message = bytearray (param .encode_into_pdu ( encode_state ) )
163
- encode_state . parameter_values [ param . short_name ] = tmp
165
+ # parameter in a post- processing step.
166
+ param .encode_placeholder_into_pdu (
167
+ physical_value = param_value . get (param .short_name ), encode_state = encode_state )
168
+
164
169
continue
165
170
166
- encode_state .coded_message = bytearray (param .encode_into_pdu (encode_state ))
171
+ if param .is_required and param .short_name not in param_value :
172
+ odxraise (f"No value for required parameter { param .short_name } specified" ,
173
+ EncodeError )
167
174
168
- if self .byte_size is not None and len (encode_state .coded_message ) < self .byte_size :
169
- # Padding bytes needed
170
- encode_state .coded_message = encode_state .coded_message .ljust (self .byte_size , b"\0 " )
175
+ param .encode_into_pdu (
176
+ physical_value = param_value .get (param .short_name ), encode_state = encode_state )
177
+
178
+ if self .byte_size is not None :
179
+ if len (encode_state .coded_message ) < self .byte_size :
180
+ # Padding bytes needed
181
+ encode_state .coded_message = encode_state .coded_message .ljust (self .byte_size , b"\0 " )
171
182
172
183
# encode the length- and table keys. This cannot be done above
173
184
# because we allow these to be defined implicitly (i.e. they
@@ -177,22 +188,25 @@ def convert_physical_to_internal(self,
177
188
# the current parameter is neither a length- nor a table key
178
189
continue
179
190
180
- # Encode the key parameter into the message
181
- encode_state . coded_message = bytearray ( param .encode_into_pdu (encode_state ) )
191
+ # Encode the value of the key parameter into the message
192
+ param .encode_value_into_pdu (encode_state = encode_state )
182
193
183
194
# Assert that length is as expected
184
- self ._validate_coded_message (encode_state .coded_message )
195
+ self ._validate_coded_message_size (encode_state .cursor_byte_position -
196
+ encode_state .origin_byte_position )
185
197
186
- return bytearray ( encode_state .coded_message )
198
+ return encode_state .coded_message
187
199
188
- def _validate_coded_message (self , coded_message : bytes ) -> None :
200
+ def _validate_coded_message_size (self , coded_byte_len : int ) -> None :
189
201
190
202
if self .byte_size is not None :
191
203
# We definitely broke something if we didn't respect the explicit byte_size
192
- odxassert (
193
- len (coded_message ) == self .byte_size ,
194
- "Verification of coded message {coded_message.hex()} failed: Incorrect size." )
195
- # No need to check further
204
+ if self .byte_size != coded_byte_len :
205
+ warnings .warn (
206
+ "Verification of coded message failed: Incorrect size." ,
207
+ OdxWarning ,
208
+ stacklevel = 1 )
209
+
196
210
return
197
211
198
212
bit_length = self .get_static_bit_length ()
@@ -201,12 +215,12 @@ def _validate_coded_message(self, coded_message: bytes) -> None:
201
215
# Nothing to check
202
216
return
203
217
204
- if len ( coded_message ) * 8 != bit_length :
218
+ if coded_byte_len * 8 != bit_length :
205
219
# We may have broke something
206
220
# but it could be that bit_length was mis calculated and not the actual bytes are wrong
207
221
# Could happen with overlapping parameters and parameters with gaps
208
222
warnings .warn (
209
- f "Verification of coded message ' { coded_message . hex () } ' possibly failed: Size may be incorrect." ,
223
+ "Verification of coded message possibly failed: Size may be incorrect." ,
210
224
OdxWarning ,
211
225
stacklevel = 1 )
212
226
0 commit comments