oscura 0.0.1__py3-none-any.whl → 0.1.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.
- oscura/__init__.py +813 -8
- oscura/__main__.py +392 -0
- oscura/analyzers/__init__.py +37 -0
- oscura/analyzers/digital/__init__.py +177 -0
- oscura/analyzers/digital/bus.py +691 -0
- oscura/analyzers/digital/clock.py +805 -0
- oscura/analyzers/digital/correlation.py +720 -0
- oscura/analyzers/digital/edges.py +632 -0
- oscura/analyzers/digital/extraction.py +413 -0
- oscura/analyzers/digital/quality.py +878 -0
- oscura/analyzers/digital/signal_quality.py +877 -0
- oscura/analyzers/digital/thresholds.py +708 -0
- oscura/analyzers/digital/timing.py +1104 -0
- oscura/analyzers/eye/__init__.py +46 -0
- oscura/analyzers/eye/diagram.py +434 -0
- oscura/analyzers/eye/metrics.py +555 -0
- oscura/analyzers/jitter/__init__.py +83 -0
- oscura/analyzers/jitter/ber.py +333 -0
- oscura/analyzers/jitter/decomposition.py +759 -0
- oscura/analyzers/jitter/measurements.py +413 -0
- oscura/analyzers/jitter/spectrum.py +220 -0
- oscura/analyzers/measurements.py +40 -0
- oscura/analyzers/packet/__init__.py +171 -0
- oscura/analyzers/packet/daq.py +1077 -0
- oscura/analyzers/packet/metrics.py +437 -0
- oscura/analyzers/packet/parser.py +327 -0
- oscura/analyzers/packet/payload.py +2156 -0
- oscura/analyzers/packet/payload_analysis.py +1312 -0
- oscura/analyzers/packet/payload_extraction.py +236 -0
- oscura/analyzers/packet/payload_patterns.py +670 -0
- oscura/analyzers/packet/stream.py +359 -0
- oscura/analyzers/patterns/__init__.py +266 -0
- oscura/analyzers/patterns/clustering.py +1036 -0
- oscura/analyzers/patterns/discovery.py +539 -0
- oscura/analyzers/patterns/learning.py +797 -0
- oscura/analyzers/patterns/matching.py +1091 -0
- oscura/analyzers/patterns/periodic.py +650 -0
- oscura/analyzers/patterns/sequences.py +767 -0
- oscura/analyzers/power/__init__.py +116 -0
- oscura/analyzers/power/ac_power.py +391 -0
- oscura/analyzers/power/basic.py +383 -0
- oscura/analyzers/power/conduction.py +314 -0
- oscura/analyzers/power/efficiency.py +297 -0
- oscura/analyzers/power/ripple.py +356 -0
- oscura/analyzers/power/soa.py +372 -0
- oscura/analyzers/power/switching.py +479 -0
- oscura/analyzers/protocol/__init__.py +150 -0
- oscura/analyzers/protocols/__init__.py +150 -0
- oscura/analyzers/protocols/base.py +500 -0
- oscura/analyzers/protocols/can.py +620 -0
- oscura/analyzers/protocols/can_fd.py +448 -0
- oscura/analyzers/protocols/flexray.py +405 -0
- oscura/analyzers/protocols/hdlc.py +399 -0
- oscura/analyzers/protocols/i2c.py +368 -0
- oscura/analyzers/protocols/i2s.py +296 -0
- oscura/analyzers/protocols/jtag.py +393 -0
- oscura/analyzers/protocols/lin.py +445 -0
- oscura/analyzers/protocols/manchester.py +333 -0
- oscura/analyzers/protocols/onewire.py +501 -0
- oscura/analyzers/protocols/spi.py +334 -0
- oscura/analyzers/protocols/swd.py +325 -0
- oscura/analyzers/protocols/uart.py +393 -0
- oscura/analyzers/protocols/usb.py +495 -0
- oscura/analyzers/signal_integrity/__init__.py +63 -0
- oscura/analyzers/signal_integrity/embedding.py +294 -0
- oscura/analyzers/signal_integrity/equalization.py +370 -0
- oscura/analyzers/signal_integrity/sparams.py +484 -0
- oscura/analyzers/spectral/__init__.py +53 -0
- oscura/analyzers/spectral/chunked.py +273 -0
- oscura/analyzers/spectral/chunked_fft.py +571 -0
- oscura/analyzers/spectral/chunked_wavelet.py +391 -0
- oscura/analyzers/spectral/fft.py +92 -0
- oscura/analyzers/statistical/__init__.py +250 -0
- oscura/analyzers/statistical/checksum.py +923 -0
- oscura/analyzers/statistical/chunked_corr.py +228 -0
- oscura/analyzers/statistical/classification.py +778 -0
- oscura/analyzers/statistical/entropy.py +1113 -0
- oscura/analyzers/statistical/ngrams.py +614 -0
- oscura/analyzers/statistics/__init__.py +119 -0
- oscura/analyzers/statistics/advanced.py +885 -0
- oscura/analyzers/statistics/basic.py +263 -0
- oscura/analyzers/statistics/correlation.py +630 -0
- oscura/analyzers/statistics/distribution.py +298 -0
- oscura/analyzers/statistics/outliers.py +463 -0
- oscura/analyzers/statistics/streaming.py +93 -0
- oscura/analyzers/statistics/trend.py +520 -0
- oscura/analyzers/validation.py +598 -0
- oscura/analyzers/waveform/__init__.py +36 -0
- oscura/analyzers/waveform/measurements.py +943 -0
- oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
- oscura/analyzers/waveform/spectral.py +1689 -0
- oscura/analyzers/waveform/wavelets.py +298 -0
- oscura/api/__init__.py +62 -0
- oscura/api/dsl.py +538 -0
- oscura/api/fluent.py +571 -0
- oscura/api/operators.py +498 -0
- oscura/api/optimization.py +392 -0
- oscura/api/profiling.py +396 -0
- oscura/automotive/__init__.py +73 -0
- oscura/automotive/can/__init__.py +52 -0
- oscura/automotive/can/analysis.py +356 -0
- oscura/automotive/can/checksum.py +250 -0
- oscura/automotive/can/correlation.py +212 -0
- oscura/automotive/can/discovery.py +355 -0
- oscura/automotive/can/message_wrapper.py +375 -0
- oscura/automotive/can/models.py +385 -0
- oscura/automotive/can/patterns.py +381 -0
- oscura/automotive/can/session.py +452 -0
- oscura/automotive/can/state_machine.py +300 -0
- oscura/automotive/can/stimulus_response.py +461 -0
- oscura/automotive/dbc/__init__.py +15 -0
- oscura/automotive/dbc/generator.py +156 -0
- oscura/automotive/dbc/parser.py +146 -0
- oscura/automotive/dtc/__init__.py +30 -0
- oscura/automotive/dtc/database.py +3036 -0
- oscura/automotive/j1939/__init__.py +14 -0
- oscura/automotive/j1939/decoder.py +745 -0
- oscura/automotive/loaders/__init__.py +35 -0
- oscura/automotive/loaders/asc.py +98 -0
- oscura/automotive/loaders/blf.py +77 -0
- oscura/automotive/loaders/csv_can.py +136 -0
- oscura/automotive/loaders/dispatcher.py +136 -0
- oscura/automotive/loaders/mdf.py +331 -0
- oscura/automotive/loaders/pcap.py +132 -0
- oscura/automotive/obd/__init__.py +14 -0
- oscura/automotive/obd/decoder.py +707 -0
- oscura/automotive/uds/__init__.py +48 -0
- oscura/automotive/uds/decoder.py +265 -0
- oscura/automotive/uds/models.py +64 -0
- oscura/automotive/visualization.py +369 -0
- oscura/batch/__init__.py +55 -0
- oscura/batch/advanced.py +627 -0
- oscura/batch/aggregate.py +300 -0
- oscura/batch/analyze.py +139 -0
- oscura/batch/logging.py +487 -0
- oscura/batch/metrics.py +556 -0
- oscura/builders/__init__.py +41 -0
- oscura/builders/signal_builder.py +1131 -0
- oscura/cli/__init__.py +14 -0
- oscura/cli/batch.py +339 -0
- oscura/cli/characterize.py +273 -0
- oscura/cli/compare.py +775 -0
- oscura/cli/decode.py +551 -0
- oscura/cli/main.py +247 -0
- oscura/cli/shell.py +350 -0
- oscura/comparison/__init__.py +66 -0
- oscura/comparison/compare.py +397 -0
- oscura/comparison/golden.py +487 -0
- oscura/comparison/limits.py +391 -0
- oscura/comparison/mask.py +434 -0
- oscura/comparison/trace_diff.py +30 -0
- oscura/comparison/visualization.py +481 -0
- oscura/compliance/__init__.py +70 -0
- oscura/compliance/advanced.py +756 -0
- oscura/compliance/masks.py +363 -0
- oscura/compliance/reporting.py +483 -0
- oscura/compliance/testing.py +298 -0
- oscura/component/__init__.py +38 -0
- oscura/component/impedance.py +365 -0
- oscura/component/reactive.py +598 -0
- oscura/component/transmission_line.py +312 -0
- oscura/config/__init__.py +191 -0
- oscura/config/defaults.py +254 -0
- oscura/config/loader.py +348 -0
- oscura/config/memory.py +271 -0
- oscura/config/migration.py +458 -0
- oscura/config/pipeline.py +1077 -0
- oscura/config/preferences.py +530 -0
- oscura/config/protocol.py +875 -0
- oscura/config/schema.py +713 -0
- oscura/config/settings.py +420 -0
- oscura/config/thresholds.py +599 -0
- oscura/convenience.py +457 -0
- oscura/core/__init__.py +299 -0
- oscura/core/audit.py +457 -0
- oscura/core/backend_selector.py +405 -0
- oscura/core/cache.py +590 -0
- oscura/core/cancellation.py +439 -0
- oscura/core/confidence.py +225 -0
- oscura/core/config.py +506 -0
- oscura/core/correlation.py +216 -0
- oscura/core/cross_domain.py +422 -0
- oscura/core/debug.py +301 -0
- oscura/core/edge_cases.py +541 -0
- oscura/core/exceptions.py +535 -0
- oscura/core/gpu_backend.py +523 -0
- oscura/core/lazy.py +832 -0
- oscura/core/log_query.py +540 -0
- oscura/core/logging.py +931 -0
- oscura/core/logging_advanced.py +952 -0
- oscura/core/memoize.py +171 -0
- oscura/core/memory_check.py +274 -0
- oscura/core/memory_guard.py +290 -0
- oscura/core/memory_limits.py +336 -0
- oscura/core/memory_monitor.py +453 -0
- oscura/core/memory_progress.py +465 -0
- oscura/core/memory_warnings.py +315 -0
- oscura/core/numba_backend.py +362 -0
- oscura/core/performance.py +352 -0
- oscura/core/progress.py +524 -0
- oscura/core/provenance.py +358 -0
- oscura/core/results.py +331 -0
- oscura/core/types.py +504 -0
- oscura/core/uncertainty.py +383 -0
- oscura/discovery/__init__.py +52 -0
- oscura/discovery/anomaly_detector.py +672 -0
- oscura/discovery/auto_decoder.py +415 -0
- oscura/discovery/comparison.py +497 -0
- oscura/discovery/quality_validator.py +528 -0
- oscura/discovery/signal_detector.py +769 -0
- oscura/dsl/__init__.py +73 -0
- oscura/dsl/commands.py +246 -0
- oscura/dsl/interpreter.py +455 -0
- oscura/dsl/parser.py +689 -0
- oscura/dsl/repl.py +172 -0
- oscura/exceptions.py +59 -0
- oscura/exploratory/__init__.py +111 -0
- oscura/exploratory/error_recovery.py +642 -0
- oscura/exploratory/fuzzy.py +513 -0
- oscura/exploratory/fuzzy_advanced.py +786 -0
- oscura/exploratory/legacy.py +831 -0
- oscura/exploratory/parse.py +358 -0
- oscura/exploratory/recovery.py +275 -0
- oscura/exploratory/sync.py +382 -0
- oscura/exploratory/unknown.py +707 -0
- oscura/export/__init__.py +25 -0
- oscura/export/wireshark/README.md +265 -0
- oscura/export/wireshark/__init__.py +47 -0
- oscura/export/wireshark/generator.py +312 -0
- oscura/export/wireshark/lua_builder.py +159 -0
- oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
- oscura/export/wireshark/type_mapping.py +165 -0
- oscura/export/wireshark/validator.py +105 -0
- oscura/exporters/__init__.py +94 -0
- oscura/exporters/csv.py +303 -0
- oscura/exporters/exporters.py +44 -0
- oscura/exporters/hdf5.py +219 -0
- oscura/exporters/html_export.py +701 -0
- oscura/exporters/json_export.py +291 -0
- oscura/exporters/markdown_export.py +367 -0
- oscura/exporters/matlab_export.py +354 -0
- oscura/exporters/npz_export.py +219 -0
- oscura/exporters/spice_export.py +210 -0
- oscura/extensibility/__init__.py +131 -0
- oscura/extensibility/docs.py +752 -0
- oscura/extensibility/extensions.py +1125 -0
- oscura/extensibility/logging.py +259 -0
- oscura/extensibility/measurements.py +485 -0
- oscura/extensibility/plugins.py +414 -0
- oscura/extensibility/registry.py +346 -0
- oscura/extensibility/templates.py +913 -0
- oscura/extensibility/validation.py +651 -0
- oscura/filtering/__init__.py +89 -0
- oscura/filtering/base.py +563 -0
- oscura/filtering/convenience.py +564 -0
- oscura/filtering/design.py +725 -0
- oscura/filtering/filters.py +32 -0
- oscura/filtering/introspection.py +605 -0
- oscura/guidance/__init__.py +24 -0
- oscura/guidance/recommender.py +429 -0
- oscura/guidance/wizard.py +518 -0
- oscura/inference/__init__.py +251 -0
- oscura/inference/active_learning/README.md +153 -0
- oscura/inference/active_learning/__init__.py +38 -0
- oscura/inference/active_learning/lstar.py +257 -0
- oscura/inference/active_learning/observation_table.py +230 -0
- oscura/inference/active_learning/oracle.py +78 -0
- oscura/inference/active_learning/teachers/__init__.py +15 -0
- oscura/inference/active_learning/teachers/simulator.py +192 -0
- oscura/inference/adaptive_tuning.py +453 -0
- oscura/inference/alignment.py +653 -0
- oscura/inference/bayesian.py +943 -0
- oscura/inference/binary.py +1016 -0
- oscura/inference/crc_reverse.py +711 -0
- oscura/inference/logic.py +288 -0
- oscura/inference/message_format.py +1305 -0
- oscura/inference/protocol.py +417 -0
- oscura/inference/protocol_dsl.py +1084 -0
- oscura/inference/protocol_library.py +1230 -0
- oscura/inference/sequences.py +809 -0
- oscura/inference/signal_intelligence.py +1509 -0
- oscura/inference/spectral.py +215 -0
- oscura/inference/state_machine.py +634 -0
- oscura/inference/stream.py +918 -0
- oscura/integrations/__init__.py +59 -0
- oscura/integrations/llm.py +1827 -0
- oscura/jupyter/__init__.py +32 -0
- oscura/jupyter/display.py +268 -0
- oscura/jupyter/magic.py +334 -0
- oscura/loaders/__init__.py +526 -0
- oscura/loaders/binary.py +69 -0
- oscura/loaders/configurable.py +1255 -0
- oscura/loaders/csv.py +26 -0
- oscura/loaders/csv_loader.py +473 -0
- oscura/loaders/hdf5.py +9 -0
- oscura/loaders/hdf5_loader.py +510 -0
- oscura/loaders/lazy.py +370 -0
- oscura/loaders/mmap_loader.py +583 -0
- oscura/loaders/numpy_loader.py +436 -0
- oscura/loaders/pcap.py +432 -0
- oscura/loaders/preprocessing.py +368 -0
- oscura/loaders/rigol.py +287 -0
- oscura/loaders/sigrok.py +321 -0
- oscura/loaders/tdms.py +367 -0
- oscura/loaders/tektronix.py +711 -0
- oscura/loaders/validation.py +584 -0
- oscura/loaders/vcd.py +464 -0
- oscura/loaders/wav.py +233 -0
- oscura/math/__init__.py +45 -0
- oscura/math/arithmetic.py +824 -0
- oscura/math/interpolation.py +413 -0
- oscura/onboarding/__init__.py +39 -0
- oscura/onboarding/help.py +498 -0
- oscura/onboarding/tutorials.py +405 -0
- oscura/onboarding/wizard.py +466 -0
- oscura/optimization/__init__.py +19 -0
- oscura/optimization/parallel.py +440 -0
- oscura/optimization/search.py +532 -0
- oscura/pipeline/__init__.py +43 -0
- oscura/pipeline/base.py +338 -0
- oscura/pipeline/composition.py +242 -0
- oscura/pipeline/parallel.py +448 -0
- oscura/pipeline/pipeline.py +375 -0
- oscura/pipeline/reverse_engineering.py +1119 -0
- oscura/plugins/__init__.py +122 -0
- oscura/plugins/base.py +272 -0
- oscura/plugins/cli.py +497 -0
- oscura/plugins/discovery.py +411 -0
- oscura/plugins/isolation.py +418 -0
- oscura/plugins/lifecycle.py +959 -0
- oscura/plugins/manager.py +493 -0
- oscura/plugins/registry.py +421 -0
- oscura/plugins/versioning.py +372 -0
- oscura/py.typed +0 -0
- oscura/quality/__init__.py +65 -0
- oscura/quality/ensemble.py +740 -0
- oscura/quality/explainer.py +338 -0
- oscura/quality/scoring.py +616 -0
- oscura/quality/warnings.py +456 -0
- oscura/reporting/__init__.py +248 -0
- oscura/reporting/advanced.py +1234 -0
- oscura/reporting/analyze.py +448 -0
- oscura/reporting/argument_preparer.py +596 -0
- oscura/reporting/auto_report.py +507 -0
- oscura/reporting/batch.py +615 -0
- oscura/reporting/chart_selection.py +223 -0
- oscura/reporting/comparison.py +330 -0
- oscura/reporting/config.py +615 -0
- oscura/reporting/content/__init__.py +39 -0
- oscura/reporting/content/executive.py +127 -0
- oscura/reporting/content/filtering.py +191 -0
- oscura/reporting/content/minimal.py +257 -0
- oscura/reporting/content/verbosity.py +162 -0
- oscura/reporting/core.py +508 -0
- oscura/reporting/core_formats/__init__.py +17 -0
- oscura/reporting/core_formats/multi_format.py +210 -0
- oscura/reporting/engine.py +836 -0
- oscura/reporting/export.py +366 -0
- oscura/reporting/formatting/__init__.py +129 -0
- oscura/reporting/formatting/emphasis.py +81 -0
- oscura/reporting/formatting/numbers.py +403 -0
- oscura/reporting/formatting/standards.py +55 -0
- oscura/reporting/formatting.py +466 -0
- oscura/reporting/html.py +578 -0
- oscura/reporting/index.py +590 -0
- oscura/reporting/multichannel.py +296 -0
- oscura/reporting/output.py +379 -0
- oscura/reporting/pdf.py +373 -0
- oscura/reporting/plots.py +731 -0
- oscura/reporting/pptx_export.py +360 -0
- oscura/reporting/renderers/__init__.py +11 -0
- oscura/reporting/renderers/pdf.py +94 -0
- oscura/reporting/sections.py +471 -0
- oscura/reporting/standards.py +680 -0
- oscura/reporting/summary_generator.py +368 -0
- oscura/reporting/tables.py +397 -0
- oscura/reporting/template_system.py +724 -0
- oscura/reporting/templates/__init__.py +15 -0
- oscura/reporting/templates/definition.py +205 -0
- oscura/reporting/templates/index.html +649 -0
- oscura/reporting/templates/index.md +173 -0
- oscura/schemas/__init__.py +158 -0
- oscura/schemas/bus_configuration.json +322 -0
- oscura/schemas/device_mapping.json +182 -0
- oscura/schemas/packet_format.json +418 -0
- oscura/schemas/protocol_definition.json +363 -0
- oscura/search/__init__.py +16 -0
- oscura/search/anomaly.py +292 -0
- oscura/search/context.py +149 -0
- oscura/search/pattern.py +160 -0
- oscura/session/__init__.py +34 -0
- oscura/session/annotations.py +289 -0
- oscura/session/history.py +313 -0
- oscura/session/session.py +445 -0
- oscura/streaming/__init__.py +43 -0
- oscura/streaming/chunked.py +611 -0
- oscura/streaming/progressive.py +393 -0
- oscura/streaming/realtime.py +622 -0
- oscura/testing/__init__.py +54 -0
- oscura/testing/synthetic.py +808 -0
- oscura/triggering/__init__.py +68 -0
- oscura/triggering/base.py +229 -0
- oscura/triggering/edge.py +353 -0
- oscura/triggering/pattern.py +344 -0
- oscura/triggering/pulse.py +581 -0
- oscura/triggering/window.py +453 -0
- oscura/ui/__init__.py +48 -0
- oscura/ui/formatters.py +526 -0
- oscura/ui/progressive_display.py +340 -0
- oscura/utils/__init__.py +99 -0
- oscura/utils/autodetect.py +338 -0
- oscura/utils/buffer.py +389 -0
- oscura/utils/lazy.py +407 -0
- oscura/utils/lazy_imports.py +147 -0
- oscura/utils/memory.py +836 -0
- oscura/utils/memory_advanced.py +1326 -0
- oscura/utils/memory_extensions.py +465 -0
- oscura/utils/progressive.py +352 -0
- oscura/utils/windowing.py +362 -0
- oscura/visualization/__init__.py +321 -0
- oscura/visualization/accessibility.py +526 -0
- oscura/visualization/annotations.py +374 -0
- oscura/visualization/axis_scaling.py +305 -0
- oscura/visualization/colors.py +453 -0
- oscura/visualization/digital.py +337 -0
- oscura/visualization/eye.py +420 -0
- oscura/visualization/histogram.py +281 -0
- oscura/visualization/interactive.py +858 -0
- oscura/visualization/jitter.py +702 -0
- oscura/visualization/keyboard.py +394 -0
- oscura/visualization/layout.py +365 -0
- oscura/visualization/optimization.py +1028 -0
- oscura/visualization/palettes.py +446 -0
- oscura/visualization/plot.py +92 -0
- oscura/visualization/power.py +290 -0
- oscura/visualization/power_extended.py +626 -0
- oscura/visualization/presets.py +467 -0
- oscura/visualization/protocols.py +932 -0
- oscura/visualization/render.py +207 -0
- oscura/visualization/rendering.py +444 -0
- oscura/visualization/reverse_engineering.py +791 -0
- oscura/visualization/signal_integrity.py +808 -0
- oscura/visualization/specialized.py +553 -0
- oscura/visualization/spectral.py +811 -0
- oscura/visualization/styles.py +381 -0
- oscura/visualization/thumbnails.py +311 -0
- oscura/visualization/time_axis.py +351 -0
- oscura/visualization/waveform.py +367 -0
- oscura/workflow/__init__.py +13 -0
- oscura/workflow/dag.py +377 -0
- oscura/workflows/__init__.py +58 -0
- oscura/workflows/compliance.py +280 -0
- oscura/workflows/digital.py +272 -0
- oscura/workflows/multi_trace.py +502 -0
- oscura/workflows/power.py +178 -0
- oscura/workflows/protocol.py +492 -0
- oscura/workflows/reverse_engineering.py +639 -0
- oscura/workflows/signal_integrity.py +227 -0
- oscura-0.1.0.dist-info/METADATA +300 -0
- oscura-0.1.0.dist-info/RECORD +463 -0
- oscura-0.1.0.dist-info/entry_points.txt +2 -0
- {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/licenses/LICENSE +1 -1
- oscura-0.0.1.dist-info/METADATA +0 -63
- oscura-0.0.1.dist-info/RECORD +0 -5
- {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""UDS (Unified Diagnostic Services) protocol support per ISO 14229.
|
|
2
|
+
|
|
3
|
+
This module provides decoding and analysis of UDS diagnostic messages used
|
|
4
|
+
in modern automotive ECUs for diagnostics, programming, and security access.
|
|
5
|
+
|
|
6
|
+
Supported Services (ISO 14229-1):
|
|
7
|
+
- 0x10: Diagnostic Session Control
|
|
8
|
+
- 0x11: ECU Reset
|
|
9
|
+
- 0x14: Clear Diagnostic Information
|
|
10
|
+
- 0x19: Read DTC Information
|
|
11
|
+
- 0x22: Read Data By Identifier
|
|
12
|
+
- 0x23: Read Memory By Address
|
|
13
|
+
- 0x27: Security Access
|
|
14
|
+
- 0x28: Communication Control
|
|
15
|
+
- 0x2E: Write Data By Identifier
|
|
16
|
+
- 0x2F: Input Output Control By Identifier
|
|
17
|
+
- 0x31: Routine Control
|
|
18
|
+
- 0x34: Request Download
|
|
19
|
+
- 0x35: Request Upload
|
|
20
|
+
- 0x36: Transfer Data
|
|
21
|
+
- 0x37: Request Transfer Exit
|
|
22
|
+
- 0x3E: Tester Present
|
|
23
|
+
- 0x85: Control DTC Setting
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
>>> from oscura.automotive.uds import UDSDecoder
|
|
27
|
+
>>> from oscura.automotive.can.models import CANMessage
|
|
28
|
+
>>> # Create a UDS request message (Diagnostic Session Control)
|
|
29
|
+
>>> msg = CANMessage(
|
|
30
|
+
... arbitration_id=0x7DF,
|
|
31
|
+
... timestamp=1.0,
|
|
32
|
+
... data=bytes([0x02, 0x10, 0x01]) # Length=2, SID=0x10, sub=0x01
|
|
33
|
+
... )
|
|
34
|
+
>>> service = UDSDecoder.decode_service(msg)
|
|
35
|
+
>>> print(service)
|
|
36
|
+
UDSService(0x10 DiagnosticSessionControl [Request], sub=0x01)
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"UDSDecoder",
|
|
43
|
+
"UDSNegativeResponse",
|
|
44
|
+
"UDSService",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
from oscura.automotive.uds.decoder import UDSDecoder
|
|
48
|
+
from oscura.automotive.uds.models import UDSNegativeResponse, UDSService
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"""UDS (Unified Diagnostic Services) protocol decoder per ISO 14229.
|
|
2
|
+
|
|
3
|
+
This module implements decoding for UDS diagnostic messages used in automotive ECUs.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from oscura.automotive.can.models import CANMessage
|
|
12
|
+
|
|
13
|
+
from oscura.automotive.uds.models import UDSNegativeResponse, UDSService
|
|
14
|
+
|
|
15
|
+
__all__ = ["UDSDecoder"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Service ID mappings per ISO 14229-1
|
|
19
|
+
_SERVICE_NAMES = {
|
|
20
|
+
0x10: "DiagnosticSessionControl",
|
|
21
|
+
0x11: "ECUReset",
|
|
22
|
+
0x14: "ClearDiagnosticInformation",
|
|
23
|
+
0x19: "ReadDTCInformation",
|
|
24
|
+
0x22: "ReadDataByIdentifier",
|
|
25
|
+
0x23: "ReadMemoryByAddress",
|
|
26
|
+
0x27: "SecurityAccess",
|
|
27
|
+
0x28: "CommunicationControl",
|
|
28
|
+
0x2E: "WriteDataByIdentifier",
|
|
29
|
+
0x2F: "InputOutputControlByIdentifier",
|
|
30
|
+
0x31: "RoutineControl",
|
|
31
|
+
0x34: "RequestDownload",
|
|
32
|
+
0x35: "RequestUpload",
|
|
33
|
+
0x36: "TransferData",
|
|
34
|
+
0x37: "RequestTransferExit",
|
|
35
|
+
0x3E: "TesterPresent",
|
|
36
|
+
0x85: "ControlDTCSetting",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Negative Response Codes per ISO 14229-1
|
|
40
|
+
_NRC_NAMES = {
|
|
41
|
+
0x10: "generalReject",
|
|
42
|
+
0x11: "serviceNotSupported",
|
|
43
|
+
0x12: "subFunctionNotSupported",
|
|
44
|
+
0x13: "incorrectMessageLengthOrInvalidFormat",
|
|
45
|
+
0x14: "responseTooLong",
|
|
46
|
+
0x21: "busyRepeatRequest",
|
|
47
|
+
0x22: "conditionsNotCorrect",
|
|
48
|
+
0x24: "requestSequenceError",
|
|
49
|
+
0x25: "noResponseFromSubnetComponent",
|
|
50
|
+
0x26: "failurePreventsExecutionOfRequestedAction",
|
|
51
|
+
0x31: "requestOutOfRange",
|
|
52
|
+
0x33: "securityAccessDenied",
|
|
53
|
+
0x35: "invalidKey",
|
|
54
|
+
0x36: "exceedNumberOfAttempts",
|
|
55
|
+
0x37: "requiredTimeDelayNotExpired",
|
|
56
|
+
0x70: "uploadDownloadNotAccepted",
|
|
57
|
+
0x71: "transferDataSuspended",
|
|
58
|
+
0x72: "generalProgrammingFailure",
|
|
59
|
+
0x73: "wrongBlockSequenceCounter",
|
|
60
|
+
0x78: "requestCorrectlyReceivedResponsePending",
|
|
61
|
+
0x7E: "subFunctionNotSupportedInActiveSession",
|
|
62
|
+
0x7F: "serviceNotSupportedInActiveSession",
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Services that typically have sub-functions
|
|
66
|
+
_SERVICES_WITH_SUBFUNCTIONS = {
|
|
67
|
+
0x10, # DiagnosticSessionControl
|
|
68
|
+
0x11, # ECUReset
|
|
69
|
+
0x19, # ReadDTCInformation
|
|
70
|
+
0x27, # SecurityAccess
|
|
71
|
+
0x28, # CommunicationControl
|
|
72
|
+
0x2F, # InputOutputControlByIdentifier
|
|
73
|
+
0x31, # RoutineControl
|
|
74
|
+
0x3E, # TesterPresent
|
|
75
|
+
0x85, # ControlDTCSetting
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class UDSDecoder:
|
|
80
|
+
"""ISO 14229 UDS protocol decoder.
|
|
81
|
+
|
|
82
|
+
This decoder analyzes CAN messages to identify and decode UDS diagnostic services.
|
|
83
|
+
|
|
84
|
+
UDS message formats:
|
|
85
|
+
- Request: [length/PCI, SID, sub-function?, data...]
|
|
86
|
+
- Positive Response: [length/PCI, SID+0x40, data...]
|
|
87
|
+
- Negative Response: [length/PCI, 0x7F, requested_SID, NRC]
|
|
88
|
+
|
|
89
|
+
Note: The first byte in CAN data may be ISO-TP PCI (Protocol Control Information)
|
|
90
|
+
or the message may be single-frame. This decoder handles both cases.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def is_uds_request(message: CANMessage) -> bool:
|
|
95
|
+
"""Check if CAN message is a UDS request.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
message: CAN message to check.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
True if message appears to be a UDS request.
|
|
102
|
+
"""
|
|
103
|
+
if len(message.data) < 2:
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
# Handle ISO-TP single frame (0x0X where X is length)
|
|
107
|
+
if message.data[0] <= 0x07:
|
|
108
|
+
sid = message.data[1]
|
|
109
|
+
# Direct UDS (no ISO-TP header)
|
|
110
|
+
else:
|
|
111
|
+
sid = message.data[0]
|
|
112
|
+
|
|
113
|
+
return sid in _SERVICE_NAMES
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def is_uds_response(message: CANMessage) -> bool:
|
|
117
|
+
"""Check if CAN message is a UDS response (positive or negative).
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
message: CAN message to check.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
True if message appears to be a UDS response.
|
|
124
|
+
"""
|
|
125
|
+
if len(message.data) < 2:
|
|
126
|
+
return False
|
|
127
|
+
|
|
128
|
+
# Handle ISO-TP single frame
|
|
129
|
+
if message.data[0] <= 0x07:
|
|
130
|
+
first_byte = message.data[1]
|
|
131
|
+
else:
|
|
132
|
+
first_byte = message.data[0]
|
|
133
|
+
|
|
134
|
+
# Negative response
|
|
135
|
+
if first_byte == 0x7F:
|
|
136
|
+
return len(message.data) >= 3
|
|
137
|
+
|
|
138
|
+
# Positive response (SID + 0x40)
|
|
139
|
+
# Response SIDs are in range 0x40-0x7F or 0xC0-0xFF
|
|
140
|
+
if 0x40 <= first_byte < 0x80 or first_byte >= 0xC0:
|
|
141
|
+
response_sid = first_byte - 0x40
|
|
142
|
+
return response_sid in _SERVICE_NAMES
|
|
143
|
+
|
|
144
|
+
return False
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def decode_service(message: CANMessage) -> UDSService | UDSNegativeResponse | None:
|
|
148
|
+
"""Decode UDS service from CAN message.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
message: CAN message to decode.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
UDSService, UDSNegativeResponse, or None if not a valid UDS message.
|
|
155
|
+
"""
|
|
156
|
+
if len(message.data) < 2:
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
# Check for ISO-TP single frame header (0x0X = length)
|
|
160
|
+
iso_tp_offset = 0
|
|
161
|
+
uds_length = None
|
|
162
|
+
if message.data[0] <= 0x07:
|
|
163
|
+
iso_tp_offset = 1
|
|
164
|
+
uds_length = message.data[0] # Length field tells us actual UDS payload size
|
|
165
|
+
|
|
166
|
+
# Extract UDS data (respecting length if ISO-TP)
|
|
167
|
+
if uds_length is not None:
|
|
168
|
+
# ISO-TP: extract exactly uds_length bytes starting after length byte
|
|
169
|
+
if len(message.data) < iso_tp_offset + uds_length:
|
|
170
|
+
return None
|
|
171
|
+
data = message.data[iso_tp_offset : iso_tp_offset + uds_length]
|
|
172
|
+
else:
|
|
173
|
+
# Direct UDS: use all remaining bytes
|
|
174
|
+
data = message.data[iso_tp_offset:]
|
|
175
|
+
|
|
176
|
+
if not data:
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
first_byte = data[0]
|
|
180
|
+
|
|
181
|
+
# Negative response: [0x7F, requested_SID, NRC]
|
|
182
|
+
if first_byte == 0x7F:
|
|
183
|
+
if len(data) < 3:
|
|
184
|
+
return None
|
|
185
|
+
requested_sid = data[1]
|
|
186
|
+
nrc = data[2]
|
|
187
|
+
nrc_name = _NRC_NAMES.get(nrc, f"unknownNRC_0x{nrc:02X}")
|
|
188
|
+
return UDSNegativeResponse(
|
|
189
|
+
requested_sid=requested_sid,
|
|
190
|
+
nrc=nrc,
|
|
191
|
+
nrc_name=nrc_name,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Check for positive response (SID + 0x40)
|
|
195
|
+
# Response SIDs are in range 0x40-0x7F (corresponding to request SIDs 0x00-0x3F)
|
|
196
|
+
# and 0xC0-0xFF (corresponding to request SIDs 0x80-0xBF)
|
|
197
|
+
if 0x40 <= first_byte < 0x80:
|
|
198
|
+
# Positive response to service 0x00-0x3F
|
|
199
|
+
sid = first_byte - 0x40
|
|
200
|
+
is_request = False
|
|
201
|
+
elif first_byte >= 0xC0:
|
|
202
|
+
# Positive response to service 0x80-0xBF
|
|
203
|
+
sid = first_byte - 0x40
|
|
204
|
+
is_request = False
|
|
205
|
+
else:
|
|
206
|
+
# Request (0x00-0x3F or 0x80-0xBF)
|
|
207
|
+
sid = first_byte
|
|
208
|
+
is_request = True
|
|
209
|
+
|
|
210
|
+
# Unknown service
|
|
211
|
+
if sid not in _SERVICE_NAMES:
|
|
212
|
+
return None
|
|
213
|
+
|
|
214
|
+
service_name = _SERVICE_NAMES[sid]
|
|
215
|
+
|
|
216
|
+
# Extract sub-function if present
|
|
217
|
+
sub_function = None
|
|
218
|
+
payload_offset = 1
|
|
219
|
+
|
|
220
|
+
if is_request and sid in _SERVICES_WITH_SUBFUNCTIONS:
|
|
221
|
+
if len(data) >= 2:
|
|
222
|
+
# Sub-function may have suppress positive response bit (0x80)
|
|
223
|
+
sub_function = data[1] & 0x7F
|
|
224
|
+
payload_offset = 2
|
|
225
|
+
elif not is_request and sid in _SERVICES_WITH_SUBFUNCTIONS:
|
|
226
|
+
# Response may echo sub-function for some services
|
|
227
|
+
if sid in {0x10, 0x11, 0x27, 0x28, 0x31, 0x3E, 0x85}:
|
|
228
|
+
if len(data) >= 2:
|
|
229
|
+
sub_function = data[1] & 0x7F
|
|
230
|
+
payload_offset = 2
|
|
231
|
+
|
|
232
|
+
# Extract remaining data payload
|
|
233
|
+
payload = data[payload_offset:] if len(data) > payload_offset else b""
|
|
234
|
+
|
|
235
|
+
return UDSService(
|
|
236
|
+
sid=sid,
|
|
237
|
+
name=service_name,
|
|
238
|
+
request=is_request,
|
|
239
|
+
sub_function=sub_function,
|
|
240
|
+
data=payload,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
@staticmethod
|
|
244
|
+
def get_service_name(sid: int) -> str:
|
|
245
|
+
"""Get service name from Service ID.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
sid: Service ID (0x10-0xFF).
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Service name or "Unknown" if not recognized.
|
|
252
|
+
"""
|
|
253
|
+
return _SERVICE_NAMES.get(sid, f"Unknown_0x{sid:02X}")
|
|
254
|
+
|
|
255
|
+
@staticmethod
|
|
256
|
+
def get_nrc_name(nrc: int) -> str:
|
|
257
|
+
"""Get negative response code name.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
nrc: Negative Response Code (0x10-0xFF).
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
NRC name or "unknown" if not recognized.
|
|
264
|
+
"""
|
|
265
|
+
return _NRC_NAMES.get(nrc, f"unknownNRC_0x{nrc:02X}")
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""UDS (Unified Diagnostic Services) data models per ISO 14229.
|
|
2
|
+
|
|
3
|
+
This module defines the core data structures for UDS protocol analysis.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"UDSNegativeResponse",
|
|
12
|
+
"UDSService",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class UDSService:
|
|
18
|
+
"""A decoded UDS service.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
sid: Service ID (0x10-0xFF).
|
|
22
|
+
name: Human-readable service name.
|
|
23
|
+
request: True if request message, False if positive response.
|
|
24
|
+
sub_function: Sub-function byte (if applicable).
|
|
25
|
+
data: Service data payload (excluding SID and sub-function).
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
sid: int
|
|
29
|
+
name: str
|
|
30
|
+
request: bool
|
|
31
|
+
sub_function: int | None = None
|
|
32
|
+
data: bytes = b""
|
|
33
|
+
|
|
34
|
+
def __repr__(self) -> str:
|
|
35
|
+
"""Human-readable representation."""
|
|
36
|
+
msg_type = "Request" if self.request else "Response"
|
|
37
|
+
subfunc = f", sub=0x{self.sub_function:02X}" if self.sub_function is not None else ""
|
|
38
|
+
data_str = self.data.hex().upper() if self.data else ""
|
|
39
|
+
data_part = f", data={data_str}" if data_str else ""
|
|
40
|
+
return f"UDSService(0x{self.sid:02X} {self.name} [{msg_type}]{subfunc}{data_part})"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class UDSNegativeResponse:
|
|
45
|
+
"""A UDS negative response (NRC).
|
|
46
|
+
|
|
47
|
+
Negative responses follow format: [0x7F, requested_SID, NRC]
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
requested_sid: The Service ID that was requested.
|
|
51
|
+
nrc: Negative Response Code (0x10-0xFF).
|
|
52
|
+
nrc_name: Human-readable description of the NRC.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
requested_sid: int
|
|
56
|
+
nrc: int
|
|
57
|
+
nrc_name: str
|
|
58
|
+
|
|
59
|
+
def __repr__(self) -> str:
|
|
60
|
+
"""Human-readable representation."""
|
|
61
|
+
return (
|
|
62
|
+
f"UDSNegativeResponse(requested_SID=0x{self.requested_sid:02X}, "
|
|
63
|
+
f"NRC=0x{self.nrc:02X} [{self.nrc_name}])"
|
|
64
|
+
)
|