py-uds-demo 25.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of py-uds-demo might be problematic. Click here for more details.

@@ -0,0 +1,398 @@
1
+ from typing import TYPE_CHECKING
2
+ if TYPE_CHECKING:
3
+ from py_uds_demo.core.server import UdsServer
4
+ from py_uds_demo.core.utils.helpers import split_integer_to_bytes
5
+
6
+
7
+ class ReadDataByIdentifier:
8
+ """
9
+ Handles Read Data By Identifier (0x22) service requests.
10
+
11
+ What:
12
+ This service is used to read data from the server (ECU), identified
13
+ by a 2-byte Data Identifier (DID). It's one of the most common UDS
14
+ services.
15
+
16
+ Why:
17
+ It provides a standardized way to read a wide variety of data, such
18
+ as sensor values, configuration settings, part numbers, software
19
+ versions, and more.
20
+
21
+ How:
22
+ The client sends a request with the SID 0x22 followed by one or more
23
+ 2-byte DIDs. The server responds with the SID 0x62, the requested
24
+ DID(s), and the corresponding data.
25
+
26
+ Real-world example:
27
+ A workshop tool needs to verify the software version of an ECU. It
28
+ sends a Read Data By Identifier request with the DID for the software
29
+ version (e.g., 0xF188). The ECU responds with the version, which the
30
+ tool then displays to the technician.
31
+
32
+ Attributes:
33
+ uds_server: The UDS server instance.
34
+ """
35
+ def __init__(self, uds_server: 'UdsServer') -> None:
36
+ self.uds_server: 'UdsServer' = uds_server
37
+
38
+ def process_request(self, data_stream: list) -> list:
39
+ """
40
+ Processes a Read Data By Identifier request.
41
+
42
+ Args:
43
+ data_stream: The request data stream.
44
+
45
+ Returns:
46
+ A list of bytes representing the response.
47
+ """
48
+ if len(data_stream) != 3:
49
+ return self.uds_server.negative_response.report_negative_response(
50
+ self.uds_server.SID.RDBI, self.uds_server.NRC.INCORRECT_MESSAGE_LENGTH_OR_INVALID_FORMAT
51
+ )
52
+ did = (data_stream[1] << 8) | data_stream[2]
53
+ match did:
54
+ case self.uds_server.did.ACTIVE_DIAGNOSTIC_SESSION:
55
+ return self.uds_server.positive_response.report_positive_response(
56
+ self.uds_server.SID.RDBI, data_stream[1:3] + [self.uds_server.diagnostic_session_control.active_session]
57
+ )
58
+ case self.uds_server.did.VEHICLE_IDENTIFICATION_NUMBER:
59
+ return self.uds_server.positive_response.report_positive_response(
60
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.vehicle_identification_number
61
+ )
62
+ case self.uds_server.did.MANUFACTURER_SPARE_PART_NUMBER:
63
+ return self.uds_server.positive_response.report_positive_response(
64
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.manufacturer_spare_part_number
65
+ )
66
+ case self.uds_server.did.MANUFACTURER_ECU_SOFTWARE_NUMBER:
67
+ return self.uds_server.positive_response.report_positive_response(
68
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.manufacturer_ecu_software_number
69
+ )
70
+ case self.uds_server.did.MANUFACTURER_ECU_SOFTWARE_VERSION:
71
+ return self.uds_server.positive_response.report_positive_response(
72
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.manufacturer_ecu_software_version
73
+ )
74
+ case self.uds_server.did.ECU_MANUFACTURING_DATE:
75
+ return self.uds_server.positive_response.report_positive_response(
76
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.ecu_manufacturing_date
77
+ )
78
+ case self.uds_server.did.ECU_SERIAL_NUMBER:
79
+ return self.uds_server.positive_response.report_positive_response(
80
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.ecu_serial_number
81
+ )
82
+ case self.uds_server.did.SUPPORTED_FUNCTIONAL_UNITS:
83
+ return self.uds_server.positive_response.report_positive_response(
84
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.supported_functional_units
85
+ )
86
+ case self.uds_server.did.SYSTEM_SUPPLIER_ECU_SOFTWARE_NUMBER:
87
+ return self.uds_server.positive_response.report_positive_response(
88
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.system_supplier_ecu_software_number
89
+ )
90
+ case self.uds_server.did.SYSTEM_SUPPLIER_ECU_SOFTWARE_VERSION:
91
+ return self.uds_server.positive_response.report_positive_response(
92
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.system_supplier_ecu_software_version
93
+ )
94
+ case self.uds_server.did.PROGRAMMING_DATE:
95
+ return self.uds_server.positive_response.report_positive_response(
96
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.programming_date
97
+ )
98
+ case self.uds_server.did.REPAIR_SHOP_CODE:
99
+ return self.uds_server.positive_response.report_positive_response(
100
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.repair_shop_code
101
+ )
102
+ case self.uds_server.did.EXHAUST_REGULATION_TYPE_APPROVAL_NUMBER:
103
+ return self.uds_server.positive_response.report_positive_response(
104
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.exhaust_regulation_type_approval_number
105
+ )
106
+ case self.uds_server.did.INSTALLATION_DATE:
107
+ return self.uds_server.positive_response.report_positive_response(
108
+ self.uds_server.SID.RDBI, data_stream[1:3] + self.uds_server.memory.ecu_installation_date
109
+ )
110
+ case _:
111
+ return self.uds_server.negative_response.report_negative_response(
112
+ self.uds_server.SID.RDBI, self.uds_server.NRC.REQUEST_OUT_OF_RANGE
113
+ )
114
+
115
+
116
+ class ReadMemoryByAddress:
117
+ """
118
+ Handles Read Memory By Address (0x23) service requests.
119
+
120
+ What:
121
+ This service is used to read data from a specific memory address in
122
+ the server (ECU).
123
+
124
+ Why:
125
+ It provides a low-level way to access the ECU's memory, which is
126
+ useful for debugging, reverse engineering, or accessing data that
127
+ is not available through a Data Identifier (DID).
128
+
129
+ How:
130
+ The client sends a request with the SID 0x23, followed by the memory
131
+ address and the number of bytes to read. The server responds with
132
+ the SID 0x63 and the requested data.
133
+
134
+ Real-world example:
135
+ A software developer is debugging a new feature and wants to inspect
136
+ the value of a variable in real-time. They use the Read Memory By
137
+ Address service to read the memory location where that variable is
138
+ stored, helping them to understand its behavior.
139
+
140
+ Attributes:
141
+ uds_server: The UDS server instance.
142
+ """
143
+ def __init__(self, uds_server: 'UdsServer') -> None:
144
+ self.uds_server: 'UdsServer' = uds_server
145
+
146
+ def process_request(self, data_stream: list) -> list:
147
+ """
148
+ Processes a Read Memory By Address request.
149
+
150
+ Args:
151
+ data_stream: The request data stream.
152
+
153
+ Returns:
154
+ A list of bytes representing the response.
155
+ """
156
+ if len(data_stream) != 5:
157
+ return self.uds_server.negative_response.report_negative_response(
158
+ self.uds_server.SID.RMBA, self.uds_server.NRC.INCORRECT_MESSAGE_LENGTH_OR_INVALID_FORMAT
159
+ )
160
+
161
+ address = (data_stream[1] << 24) | (data_stream[2] << 16) | (data_stream[3] << 8) | data_stream[4]
162
+
163
+ if address not in self.uds_server.memory.memory_map:
164
+ return self.uds_server.negative_response.report_negative_response(
165
+ self.uds_server.SID.RMBA, self.uds_server.NRC.REQUEST_OUT_OF_RANGE
166
+ )
167
+
168
+ return self.uds_server.positive_response.report_positive_response(
169
+ self.uds_server.SID.RMBA, self.uds_server.memory.memory_map[address]
170
+ )
171
+
172
+
173
+ class ReadScalingDataByIdentifier:
174
+ """
175
+ Handles Read Scaling Data By Identifier (0x24) service requests.
176
+
177
+ What:
178
+ This service is used to retrieve the scaling information for a data
179
+ value that is returned by the ReadDataByIdentifier service.
180
+
181
+ Why:
182
+ Some data values are transmitted as scaled integers to save space or
183
+ for other reasons. This service provides the necessary information
184
+ (e.g., a formula or a lookup table) to convert the raw integer value
185
+ into a physical value (e.g., a floating-point number with a unit).
186
+
187
+ How:
188
+ The client sends a request with the SID 0x24 and a DID. The server
189
+ responds with the scaling information for that DID.
190
+
191
+ Note:
192
+ This service is not fully implemented in this simulator.
193
+ """
194
+ def __init__(self, uds_server: 'UdsServer') -> None:
195
+ self.uds_server: 'UdsServer' = uds_server
196
+
197
+ def process_request(self, data_stream: list) -> list:
198
+ """
199
+ Processes a Read Scaling Data By Identifier request.
200
+
201
+ Args:
202
+ data_stream: The request data stream.
203
+
204
+ Returns:
205
+ A negative response, as this service is not supported.
206
+ """
207
+ return self.uds_server.negative_response.report_negative_response(
208
+ self.uds_server.SID.RSDBI, self.uds_server.NRC.SERVICE_NOT_SUPPORTED
209
+ )
210
+
211
+
212
+ class ReadDataByPeriodicIdentifier:
213
+ """
214
+ Handles Read Data By Periodic Identifier (0x2A) service requests.
215
+
216
+ What:
217
+ This service is used to request that the server (ECU) periodically
218
+ transmits the data values for one or more Data Identifiers (DIDs).
219
+
220
+ Why:
221
+ It's an efficient way to monitor data over time without the need for
222
+ the client to continuously send requests. This is useful for data
223
+ logging or for displaying live data on a diagnostic tool.
224
+
225
+ How:
226
+ The client sends a request with the SID 0x2A, specifying the DIDs
227
+ to be read and the transmission rate. The server then starts sending
228
+ the data periodically until instructed to stop.
229
+
230
+ Note:
231
+ This service is not fully implemented in this simulator.
232
+ """
233
+ def __init__(self, uds_server: 'UdsServer') -> None:
234
+ self.uds_server: 'UdsServer' = uds_server
235
+
236
+ def process_request(self, data_stream: list) -> list:
237
+ """
238
+ Processes a Read Data By Periodic Identifier request.
239
+
240
+ Args:
241
+ data_stream: The request data stream.
242
+
243
+ Returns:
244
+ A negative response, as this service is not supported.
245
+ """
246
+ return self.uds_server.negative_response.report_negative_response(
247
+ self.uds_server.SID.RDBPI, self.uds_server.NRC.SERVICE_NOT_SUPPORTED
248
+ )
249
+
250
+
251
+ class DynamicallyDefineDataIdentifier:
252
+ """
253
+ Handles Dynamically Define Data Identifier (0x2C) service requests.
254
+
255
+ What:
256
+ This service allows a client to dynamically define a new Data
257
+ Identifier (DID) at runtime. This new DID can be composed of data
258
+ from other existing DIDs or from specific memory addresses.
259
+
260
+ Why:
261
+ It's useful when you need to read a combination of data that is not
262
+ available in a single, predefined DID. Instead of sending multiple
263
+ requests, you can create one dynamic DID to get all the data in a
264
+ single response, which can be more efficient.
265
+
266
+ How:
267
+ The client sends a request with the SID 0x2C and the definition of
268
+ the new DID, which includes the source DIDs or memory addresses.
269
+
270
+ Note:
271
+ This service is not fully implemented in this simulator.
272
+ """
273
+ def __init__(self, uds_server: 'UdsServer') -> None:
274
+ self.uds_server: 'UdsServer' = uds_server
275
+
276
+ def process_request(self, data_stream: list) -> list:
277
+ """
278
+ Processes a Dynamically Define Data Identifier request.
279
+
280
+ Args:
281
+ data_stream: The request data stream.
282
+
283
+ Returns:
284
+ A negative response, as this service is not supported.
285
+ """
286
+ return self.uds_server.negative_response.report_negative_response(
287
+ self.uds_server.SID.DDDI, self.uds_server.NRC.SERVICE_NOT_SUPPORTED
288
+ )
289
+
290
+
291
+ class WriteDataByIdentifier:
292
+ """
293
+ Handles Write Data By Identifier (0x2E) service requests.
294
+
295
+ What:
296
+ This service is used to write data to the server (ECU) at a location
297
+ specified by a Data Identifier (DID).
298
+
299
+ Why:
300
+ It's used to change the ECU's behavior or update its configuration.
301
+ This can include things like setting a new speed limit, updating the
302
+ VIN, or changing calibration values.
303
+
304
+ How:
305
+ The client sends a request with the SID 0x2E, the DID to be written,
306
+ and the data to write. The server responds with the SID 0x6E and the
307
+ DID that was written to confirm the operation.
308
+
309
+ Real-world example:
310
+ A car manufacturer wants to update the service date in the instrument
311
+ cluster. A technician uses a diagnostic tool to send a Write Data By
312
+ Identifier request with the DID for the service date and the new date.
313
+ The instrument cluster then updates its display accordingly.
314
+
315
+ Attributes:
316
+ uds_server: The UDS server instance.
317
+ """
318
+ def __init__(self, uds_server: 'UdsServer') -> None:
319
+ self.uds_server: 'UdsServer' = uds_server
320
+
321
+ def process_request(self, data_stream: list) -> list:
322
+ """
323
+ Processes a Write Data By Identifier request.
324
+
325
+ Args:
326
+ data_stream: The request data stream.
327
+
328
+ Returns:
329
+ A list of bytes representing the response.
330
+ """
331
+ if len(data_stream) < 4:
332
+ return self.uds_server.negative_response.report_negative_response(
333
+ self.uds_server.SID.WDBI, self.uds_server.NRC.INCORRECT_MESSAGE_LENGTH_OR_INVALID_FORMAT
334
+ )
335
+
336
+ did = (data_stream[1] << 8) | data_stream[2]
337
+
338
+ if did not in self.uds_server.memory.writable_dids:
339
+ return self.uds_server.negative_response.report_negative_response(
340
+ self.uds_server.SID.WDBI, self.uds_server.NRC.REQUEST_OUT_OF_RANGE
341
+ )
342
+
343
+ data_to_write = data_stream[3:]
344
+ self.uds_server.memory.did_data[did] = data_to_write
345
+
346
+ return self.uds_server.positive_response.report_positive_response(self.uds_server.SID.WDBI, data_stream[1:3])
347
+
348
+
349
+ class WriteMemoryByAddress:
350
+ """
351
+ Handles Write Memory By Address (0x3D) service requests.
352
+
353
+ What:
354
+ This service is used to write data to a specific memory address in
355
+ the server (ECU).
356
+
357
+ Why:
358
+ It provides a low-level way to modify the ECU's memory, which is
359
+ useful for debugging, applying patches, or writing data to memory
360
+ locations that are not accessible through a Data Identifier (DID).
361
+
362
+ How:
363
+ The client sends a request with the SID 0x3D, the memory address,
364
+ and the data to be written. The server responds with the SID 0x7D
365
+ to confirm the operation.
366
+
367
+ Real-world example:
368
+ A developer needs to apply a small patch to the ECU's software
369
+ without performing a full reflash. They can use the Write Memory By
370
+ Address service to write the patched code directly into the
371
+ specified memory locations.
372
+
373
+ Attributes:
374
+ uds_server: The UDS server instance.
375
+ """
376
+ def __init__(self, uds_server: 'UdsServer') -> None:
377
+ self.uds_server: 'UdsServer' = uds_server
378
+
379
+ def process_request(self, data_stream: list) -> list:
380
+ """
381
+ Processes a Write Memory By Address request.
382
+
383
+ Args:
384
+ data_stream: The request data stream.
385
+
386
+ Returns:
387
+ A list of bytes representing the response.
388
+ """
389
+ if len(data_stream) < 6:
390
+ return self.uds_server.negative_response.report_negative_response(
391
+ self.uds_server.SID.WMBA, self.uds_server.NRC.INCORRECT_MESSAGE_LENGTH_OR_INVALID_FORMAT
392
+ )
393
+
394
+ address = (data_stream[1] << 24) | (data_stream[2] << 16) | (data_stream[3] << 8) | data_stream[4]
395
+ data_to_write = data_stream[5:]
396
+ self.uds_server.memory.memory_map[address] = data_to_write
397
+
398
+ return self.uds_server.positive_response.report_positive_response(self.uds_server.SID.WMBA, [])