oscura 0.0.1__py3-none-any.whl → 0.1.1__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.1.dist-info/METADATA +300 -0
- oscura-0.1.1.dist-info/RECORD +463 -0
- oscura-0.1.1.dist-info/entry_points.txt +2 -0
- {oscura-0.0.1.dist-info → oscura-0.1.1.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.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Automotive file format loaders.
|
|
2
|
+
|
|
3
|
+
This module provides loaders for common automotive logging file formats:
|
|
4
|
+
- BLF (Vector Binary Logging Format)
|
|
5
|
+
- ASC (Vector ASCII Format)
|
|
6
|
+
- MDF/MF4 (ASAM Measurement Data Format)
|
|
7
|
+
- CSV (Comma-Separated Values)
|
|
8
|
+
- PCAP (Packet Capture - SocketCAN)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"detect_format",
|
|
15
|
+
"load_asc",
|
|
16
|
+
"load_automotive_log",
|
|
17
|
+
"load_blf",
|
|
18
|
+
"load_csv_can",
|
|
19
|
+
"load_mdf",
|
|
20
|
+
"load_pcap",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from oscura.automotive.loaders.asc import load_asc
|
|
25
|
+
from oscura.automotive.loaders.blf import load_blf
|
|
26
|
+
from oscura.automotive.loaders.csv_can import load_csv_can
|
|
27
|
+
from oscura.automotive.loaders.dispatcher import (
|
|
28
|
+
detect_format,
|
|
29
|
+
load_automotive_log,
|
|
30
|
+
)
|
|
31
|
+
from oscura.automotive.loaders.mdf import load_mdf
|
|
32
|
+
from oscura.automotive.loaders.pcap import load_pcap
|
|
33
|
+
except ImportError:
|
|
34
|
+
# Optional dependencies not installed
|
|
35
|
+
pass
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Vector ASC (ASCII Format) file loader.
|
|
2
|
+
|
|
3
|
+
This module provides loading of Vector ASC files. ASC is a human-readable
|
|
4
|
+
text format used by Vector tools for logging CAN bus data.
|
|
5
|
+
|
|
6
|
+
ASC format example:
|
|
7
|
+
date Mon Jul 15 10:30:45.123 2024
|
|
8
|
+
0.000000 1 123 Rx d 8 01 02 03 04 05 06 07 08
|
|
9
|
+
0.010000 1 280 Rx d 8 0A 0B 0C 0D 0E 0F 10 11
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import re
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from oscura.automotive.can.models import CANMessage, CANMessageList
|
|
18
|
+
|
|
19
|
+
__all__ = ["load_asc"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def load_asc(file_path: Path | str) -> CANMessageList:
|
|
23
|
+
"""Load CAN messages from a Vector ASC file.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
file_path: Path to the ASC file.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
CANMessageList containing all parsed CAN messages.
|
|
30
|
+
|
|
31
|
+
Raises:
|
|
32
|
+
FileNotFoundError: If file doesn't exist.
|
|
33
|
+
ValueError: If file cannot be parsed.
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
>>> messages = load_asc("capture.asc")
|
|
37
|
+
>>> print(f"Loaded {len(messages)} messages")
|
|
38
|
+
"""
|
|
39
|
+
path = Path(file_path)
|
|
40
|
+
if not path.exists():
|
|
41
|
+
raise FileNotFoundError(f"ASC file not found: {path}")
|
|
42
|
+
|
|
43
|
+
messages = CANMessageList()
|
|
44
|
+
|
|
45
|
+
# Regex pattern for CAN message lines
|
|
46
|
+
# Format: <timestamp> <channel> <ID> <direction> <type> <DLC> <data bytes>
|
|
47
|
+
# Example: 0.123456 1 123 Rx d 8 01 02 03 04 05 06 07 08
|
|
48
|
+
pattern = re.compile(
|
|
49
|
+
r"^\s*(\d+\.\d+)\s+" # timestamp
|
|
50
|
+
r"(\d+)\s+" # channel
|
|
51
|
+
r"([0-9A-Fa-f]+)\s+" # CAN ID (hex)
|
|
52
|
+
r"(Rx|Tx)\s+" # direction
|
|
53
|
+
r"d\s+" # type (d = data frame)
|
|
54
|
+
r"(\d+)\s+" # DLC
|
|
55
|
+
r"((?:[0-9A-Fa-f]{2}\s*)*)" # data bytes
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
with open(path, encoding="utf-8", errors="ignore") as f:
|
|
60
|
+
for line in f:
|
|
61
|
+
# Skip comments and header lines
|
|
62
|
+
if line.startswith("//") or line.startswith("date"):
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
# Try to parse as CAN message
|
|
66
|
+
match = pattern.match(line)
|
|
67
|
+
if match:
|
|
68
|
+
timestamp_str, channel_str, id_str, direction, dlc_str, data_str = (
|
|
69
|
+
match.groups()
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Parse components
|
|
73
|
+
timestamp = float(timestamp_str)
|
|
74
|
+
channel = int(channel_str)
|
|
75
|
+
arb_id = int(id_str, 16)
|
|
76
|
+
int(dlc_str)
|
|
77
|
+
|
|
78
|
+
# Parse data bytes
|
|
79
|
+
data_bytes = bytes.fromhex(data_str.replace(" ", ""))
|
|
80
|
+
|
|
81
|
+
# Determine if extended ID (typically > 0x7FF)
|
|
82
|
+
is_extended = arb_id > 0x7FF
|
|
83
|
+
|
|
84
|
+
# Create message
|
|
85
|
+
can_msg = CANMessage(
|
|
86
|
+
arbitration_id=arb_id,
|
|
87
|
+
timestamp=timestamp,
|
|
88
|
+
data=data_bytes,
|
|
89
|
+
is_extended=is_extended,
|
|
90
|
+
is_fd=False, # ASC typically doesn't indicate FD
|
|
91
|
+
channel=channel,
|
|
92
|
+
)
|
|
93
|
+
messages.append(can_msg)
|
|
94
|
+
|
|
95
|
+
except Exception as e:
|
|
96
|
+
raise ValueError(f"Failed to parse ASC file {path}: {e}") from e
|
|
97
|
+
|
|
98
|
+
return messages
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Vector BLF (Binary Logging Format) file loader.
|
|
2
|
+
|
|
3
|
+
This module provides loading of Vector BLF files using the python-can library.
|
|
4
|
+
BLF is a proprietary binary format used by Vector tools (CANoe, CANalyzer, etc.)
|
|
5
|
+
for logging CAN bus data.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from oscura.automotive.can.models import CANMessage, CANMessageList
|
|
13
|
+
|
|
14
|
+
__all__ = ["load_blf"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def load_blf(file_path: Path | str) -> CANMessageList:
|
|
18
|
+
"""Load CAN messages from a Vector BLF file.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
file_path: Path to the BLF file.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
CANMessageList containing all parsed CAN messages.
|
|
25
|
+
|
|
26
|
+
Raises:
|
|
27
|
+
ImportError: If python-can is not installed.
|
|
28
|
+
FileNotFoundError: If file doesn't exist.
|
|
29
|
+
ValueError: If file cannot be parsed.
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
>>> messages = load_blf("capture.blf")
|
|
33
|
+
>>> print(f"Loaded {len(messages)} messages")
|
|
34
|
+
>>> print(f"Unique IDs: {len(messages.unique_ids())}")
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
import can # type: ignore[import-untyped]
|
|
38
|
+
except ImportError as e:
|
|
39
|
+
raise ImportError(
|
|
40
|
+
"python-can is required for BLF file support. "
|
|
41
|
+
"Install with: pip install 'oscura[automotive]'"
|
|
42
|
+
) from e
|
|
43
|
+
|
|
44
|
+
path = Path(file_path)
|
|
45
|
+
if not path.exists():
|
|
46
|
+
raise FileNotFoundError(f"BLF file not found: {path}")
|
|
47
|
+
|
|
48
|
+
messages = CANMessageList()
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
# Open BLF file using python-can
|
|
52
|
+
with can.BLFReader(str(path)) as reader:
|
|
53
|
+
for msg in reader:
|
|
54
|
+
# Convert python-can Message to our CANMessage
|
|
55
|
+
# Extract channel number (python-can may return various types)
|
|
56
|
+
channel = 0
|
|
57
|
+
if hasattr(msg, "channel"):
|
|
58
|
+
ch = msg.channel
|
|
59
|
+
if isinstance(ch, int):
|
|
60
|
+
channel = ch
|
|
61
|
+
elif ch is not None:
|
|
62
|
+
channel = int(ch) # type: ignore[arg-type]
|
|
63
|
+
|
|
64
|
+
can_msg = CANMessage(
|
|
65
|
+
arbitration_id=msg.arbitration_id,
|
|
66
|
+
timestamp=msg.timestamp,
|
|
67
|
+
data=bytes(msg.data),
|
|
68
|
+
is_extended=msg.is_extended_id,
|
|
69
|
+
is_fd=msg.is_fd,
|
|
70
|
+
channel=channel,
|
|
71
|
+
)
|
|
72
|
+
messages.append(can_msg)
|
|
73
|
+
|
|
74
|
+
except Exception as e:
|
|
75
|
+
raise ValueError(f"Failed to parse BLF file {path}: {e}") from e
|
|
76
|
+
|
|
77
|
+
return messages
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""CSV CAN log file loader.
|
|
2
|
+
|
|
3
|
+
This module provides loading of CAN data from CSV files.
|
|
4
|
+
Supports various CSV formats commonly used for CAN logging.
|
|
5
|
+
|
|
6
|
+
Common CSV format:
|
|
7
|
+
timestamp,id,data
|
|
8
|
+
0.000000,0x123,0102030405060708
|
|
9
|
+
0.010000,0x280,0A0B0C0D0E0F1011
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import csv
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from oscura.automotive.can.models import CANMessage, CANMessageList
|
|
18
|
+
|
|
19
|
+
__all__ = ["load_csv_can"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def load_csv_can(file_path: Path | str, delimiter: str = ",") -> CANMessageList:
|
|
23
|
+
"""Load CAN messages from a CSV file.
|
|
24
|
+
|
|
25
|
+
This function attempts to automatically detect the CSV column layout
|
|
26
|
+
and parse CAN messages accordingly.
|
|
27
|
+
|
|
28
|
+
Expected columns (case-insensitive, order-independent):
|
|
29
|
+
- timestamp or time: Message timestamp
|
|
30
|
+
- id or can_id or arbitration_id: CAN ID (hex or decimal)
|
|
31
|
+
- data or payload: Data bytes (hex string)
|
|
32
|
+
- Optional: channel, dlc, extended, etc.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
file_path: Path to the CSV file.
|
|
36
|
+
delimiter: CSV delimiter character.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
CANMessageList containing all parsed CAN messages.
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
FileNotFoundError: If file doesn't exist.
|
|
43
|
+
ValueError: If file cannot be parsed or has unexpected format.
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
>>> messages = load_csv_can("capture.csv")
|
|
47
|
+
>>> print(f"Loaded {len(messages)} messages")
|
|
48
|
+
"""
|
|
49
|
+
path = Path(file_path)
|
|
50
|
+
if not path.exists():
|
|
51
|
+
raise FileNotFoundError(f"CSV file not found: {path}")
|
|
52
|
+
|
|
53
|
+
messages = CANMessageList()
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
with open(path, encoding="utf-8") as f:
|
|
57
|
+
reader = csv.DictReader(f, delimiter=delimiter)
|
|
58
|
+
|
|
59
|
+
# Try to detect column names
|
|
60
|
+
if not reader.fieldnames:
|
|
61
|
+
raise ValueError("CSV file has no header row")
|
|
62
|
+
|
|
63
|
+
# Normalize column names to lowercase for easier matching
|
|
64
|
+
fieldnames = [name.lower().strip() for name in reader.fieldnames]
|
|
65
|
+
|
|
66
|
+
# Find required columns
|
|
67
|
+
timestamp_col = None
|
|
68
|
+
id_col = None
|
|
69
|
+
data_col = None
|
|
70
|
+
|
|
71
|
+
for col in fieldnames:
|
|
72
|
+
if "timestamp" in col or col == "time" or col == "t":
|
|
73
|
+
timestamp_col = col
|
|
74
|
+
elif "id" in col or col == "can_id" or col == "arbitration_id":
|
|
75
|
+
id_col = col
|
|
76
|
+
elif "data" in col or col == "payload" or col == "bytes":
|
|
77
|
+
data_col = col
|
|
78
|
+
|
|
79
|
+
if not all([timestamp_col, id_col, data_col]):
|
|
80
|
+
raise ValueError(
|
|
81
|
+
f"CSV file missing required columns. "
|
|
82
|
+
f"Found: {fieldnames}. "
|
|
83
|
+
f"Need: timestamp, id, data"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Parse messages
|
|
87
|
+
for row_dict in reader:
|
|
88
|
+
# Create lowercase dict for case-insensitive access
|
|
89
|
+
row = {k.lower().strip(): v for k, v in row_dict.items()}
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
# Parse timestamp
|
|
93
|
+
timestamp = float(row[timestamp_col])
|
|
94
|
+
|
|
95
|
+
# Parse ID (handle hex or decimal)
|
|
96
|
+
id_str = row[id_col].strip()
|
|
97
|
+
if id_str.startswith("0x") or id_str.startswith("0X"):
|
|
98
|
+
arb_id = int(id_str, 16)
|
|
99
|
+
else:
|
|
100
|
+
# Try as int first, then hex
|
|
101
|
+
try:
|
|
102
|
+
arb_id = int(id_str)
|
|
103
|
+
except ValueError:
|
|
104
|
+
arb_id = int(id_str, 16)
|
|
105
|
+
|
|
106
|
+
# Parse data bytes
|
|
107
|
+
data_str = row[data_col].strip()
|
|
108
|
+
# Remove common separators and spaces
|
|
109
|
+
data_str = data_str.replace(" ", "").replace(":", "").replace("-", "")
|
|
110
|
+
# Remove 0x prefix if present
|
|
111
|
+
if data_str.startswith("0x") or data_str.startswith("0X"):
|
|
112
|
+
data_str = data_str[2:]
|
|
113
|
+
data_bytes = bytes.fromhex(data_str)
|
|
114
|
+
|
|
115
|
+
# Determine if extended (>11 bits = 0x7FF)
|
|
116
|
+
is_extended = arb_id > 0x7FF
|
|
117
|
+
|
|
118
|
+
# Create message
|
|
119
|
+
can_msg = CANMessage(
|
|
120
|
+
arbitration_id=arb_id,
|
|
121
|
+
timestamp=timestamp,
|
|
122
|
+
data=data_bytes,
|
|
123
|
+
is_extended=is_extended,
|
|
124
|
+
is_fd=False,
|
|
125
|
+
channel=0,
|
|
126
|
+
)
|
|
127
|
+
messages.append(can_msg)
|
|
128
|
+
|
|
129
|
+
except (ValueError, KeyError):
|
|
130
|
+
# Skip malformed rows
|
|
131
|
+
continue
|
|
132
|
+
|
|
133
|
+
except Exception as e:
|
|
134
|
+
raise ValueError(f"Failed to parse CSV file {path}: {e}") from e
|
|
135
|
+
|
|
136
|
+
return messages
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Automatic file format detection and loading dispatcher.
|
|
2
|
+
|
|
3
|
+
This module provides automatic detection of automotive log file formats
|
|
4
|
+
and dispatching to the appropriate loader.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from oscura.automotive.can.models import CANMessageList
|
|
14
|
+
|
|
15
|
+
__all__ = ["detect_format", "load_automotive_log"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def detect_format(file_path: Path | str) -> str:
|
|
19
|
+
"""Detect automotive log file format.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
file_path: Path to the file.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
str: Format name: 'blf', 'asc', 'mdf', 'csv', 'pcap', or 'unknown'.
|
|
26
|
+
"""
|
|
27
|
+
path = Path(file_path)
|
|
28
|
+
|
|
29
|
+
# Check extension first
|
|
30
|
+
ext = path.suffix.lower()
|
|
31
|
+
|
|
32
|
+
if ext == ".blf":
|
|
33
|
+
return "blf"
|
|
34
|
+
elif ext == ".asc":
|
|
35
|
+
return "asc"
|
|
36
|
+
elif ext in [".mdf", ".mf4", ".dat"]:
|
|
37
|
+
return "mdf"
|
|
38
|
+
elif ext == ".csv":
|
|
39
|
+
return "csv"
|
|
40
|
+
elif ext in [".pcap", ".pcapng"]:
|
|
41
|
+
return "pcap"
|
|
42
|
+
|
|
43
|
+
# If extension is ambiguous, check file contents
|
|
44
|
+
try:
|
|
45
|
+
with open(path, "rb") as f:
|
|
46
|
+
header = f.read(16)
|
|
47
|
+
|
|
48
|
+
# BLF magic: "LOGG"
|
|
49
|
+
if header[:4] == b"LOGG":
|
|
50
|
+
return "blf"
|
|
51
|
+
|
|
52
|
+
# MDF magic: "MDF" or "HDBlock"
|
|
53
|
+
if b"MDF" in header or b"HD" in header[:8]:
|
|
54
|
+
return "mdf"
|
|
55
|
+
|
|
56
|
+
# PCAP magic
|
|
57
|
+
if header[:4] in [b"\xd4\xc3\xb2\xa1", b"\xa1\xb2\xc3\xd4"]:
|
|
58
|
+
return "pcap"
|
|
59
|
+
|
|
60
|
+
except Exception:
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
# Try as text file
|
|
64
|
+
try:
|
|
65
|
+
with open(path, encoding="utf-8") as f:
|
|
66
|
+
first_line = f.readline().strip()
|
|
67
|
+
|
|
68
|
+
# ASC files typically start with "date" or timestamp
|
|
69
|
+
if first_line.startswith("date") or "CAN" in first_line:
|
|
70
|
+
return "asc"
|
|
71
|
+
|
|
72
|
+
# CSV with CAN data
|
|
73
|
+
if "," in first_line and ("id" in first_line.lower() or "can" in first_line.lower()):
|
|
74
|
+
return "csv"
|
|
75
|
+
|
|
76
|
+
except Exception:
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
return "unknown"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def load_automotive_log(file_path: Path | str) -> CANMessageList:
|
|
83
|
+
"""Load automotive log file, automatically detecting format.
|
|
84
|
+
|
|
85
|
+
This function automatically detects the file format and uses the
|
|
86
|
+
appropriate loader.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
file_path: Path to the automotive log file.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
CANMessageList containing all parsed messages.
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
FileNotFoundError: If the specified file does not exist.
|
|
96
|
+
ValueError: If file format cannot be determined or is unsupported.
|
|
97
|
+
"""
|
|
98
|
+
path = Path(file_path)
|
|
99
|
+
|
|
100
|
+
if not path.exists():
|
|
101
|
+
raise FileNotFoundError(f"File not found: {path}")
|
|
102
|
+
|
|
103
|
+
# Detect format
|
|
104
|
+
fmt = detect_format(path)
|
|
105
|
+
|
|
106
|
+
if fmt == "unknown":
|
|
107
|
+
raise ValueError(f"Unknown or unsupported file format: {path}")
|
|
108
|
+
|
|
109
|
+
# Import and dispatch
|
|
110
|
+
if fmt == "blf":
|
|
111
|
+
from oscura.automotive.loaders.blf import load_blf
|
|
112
|
+
|
|
113
|
+
return load_blf(path)
|
|
114
|
+
|
|
115
|
+
elif fmt == "asc":
|
|
116
|
+
from oscura.automotive.loaders.asc import load_asc
|
|
117
|
+
|
|
118
|
+
return load_asc(path)
|
|
119
|
+
|
|
120
|
+
elif fmt == "mdf":
|
|
121
|
+
from oscura.automotive.loaders.mdf import load_mdf
|
|
122
|
+
|
|
123
|
+
return load_mdf(path)
|
|
124
|
+
|
|
125
|
+
elif fmt == "csv":
|
|
126
|
+
from oscura.automotive.loaders.csv_can import load_csv_can
|
|
127
|
+
|
|
128
|
+
return load_csv_can(path)
|
|
129
|
+
|
|
130
|
+
elif fmt == "pcap":
|
|
131
|
+
from oscura.automotive.loaders.pcap import load_pcap
|
|
132
|
+
|
|
133
|
+
return load_pcap(path)
|
|
134
|
+
|
|
135
|
+
else:
|
|
136
|
+
raise ValueError(f"Unsupported format: {fmt}")
|