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,415 @@
|
|
|
1
|
+
"""Automatic protocol decoding without user configuration.
|
|
2
|
+
|
|
3
|
+
This module provides one-shot protocol decode that auto-detects parameters
|
|
4
|
+
(baud rate, polarity, bit order) and decodes common protocols.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
>>> from oscura.discovery import decode_protocol
|
|
9
|
+
>>> result = decode_protocol(trace)
|
|
10
|
+
>>> print(f"Protocol: {result.protocol}")
|
|
11
|
+
>>> print(f"Decoded {len(result.data)} bytes")
|
|
12
|
+
>>> for byte_data in result.data[:10]:
|
|
13
|
+
... print(f"0x{byte_data.value:02X} (confidence: {byte_data.confidence:.2f})")
|
|
14
|
+
|
|
15
|
+
References:
|
|
16
|
+
Protocol specifications: UART (EIA/TIA-232), SPI (Motorola), I2C (NXP)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from dataclasses import dataclass, field
|
|
22
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
23
|
+
|
|
24
|
+
import numpy as np
|
|
25
|
+
|
|
26
|
+
from oscura.core.types import DigitalTrace, WaveformTrace
|
|
27
|
+
from oscura.discovery.signal_detector import characterize_signal
|
|
28
|
+
|
|
29
|
+
if TYPE_CHECKING:
|
|
30
|
+
from numpy.typing import NDArray
|
|
31
|
+
|
|
32
|
+
ProtocolType = Literal["UART", "SPI", "I2C", "unknown"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class DecodedByte:
|
|
37
|
+
"""Single decoded byte with confidence.
|
|
38
|
+
|
|
39
|
+
Attributes:
|
|
40
|
+
value: Byte value (0-255).
|
|
41
|
+
offset: Byte offset in decoded stream.
|
|
42
|
+
confidence: Decode confidence (0.0-1.0).
|
|
43
|
+
has_error: Whether byte has detected errors.
|
|
44
|
+
error_type: Type of error if present.
|
|
45
|
+
error_description: Plain-language error description.
|
|
46
|
+
|
|
47
|
+
Example:
|
|
48
|
+
>>> byte_data = DecodedByte(value=0x48, offset=0, confidence=0.95)
|
|
49
|
+
>>> print(f"Byte: 0x{byte_data.value:02X}, char: {chr(byte_data.value)}")
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
value: int
|
|
53
|
+
offset: int
|
|
54
|
+
confidence: float
|
|
55
|
+
has_error: bool = False
|
|
56
|
+
error_type: str | None = None
|
|
57
|
+
error_description: str | None = None
|
|
58
|
+
|
|
59
|
+
def __post_init__(self) -> None:
|
|
60
|
+
"""Validate byte data."""
|
|
61
|
+
if not 0 <= self.value <= 255:
|
|
62
|
+
raise ValueError(f"Byte value must be 0-255, got {self.value}")
|
|
63
|
+
if not 0.0 <= self.confidence <= 1.0:
|
|
64
|
+
raise ValueError(f"Confidence must be 0.0-1.0, got {self.confidence}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class DecodeResult:
|
|
69
|
+
"""Protocol decode result with auto-detected parameters.
|
|
70
|
+
|
|
71
|
+
Attributes:
|
|
72
|
+
protocol: Detected protocol name.
|
|
73
|
+
overall_confidence: Overall decode confidence (0.0-1.0).
|
|
74
|
+
detected_params: Auto-detected protocol parameters.
|
|
75
|
+
data: List of decoded bytes with per-byte confidence.
|
|
76
|
+
frame_count: Number of frames/packets decoded.
|
|
77
|
+
error_count: Number of errors detected.
|
|
78
|
+
|
|
79
|
+
Example:
|
|
80
|
+
>>> result = decode_protocol(trace)
|
|
81
|
+
>>> print(f"Protocol: {result.protocol}")
|
|
82
|
+
>>> print(f"Confidence: {result.overall_confidence:.2f}")
|
|
83
|
+
>>> print(f"Parameters: {result.detected_params}")
|
|
84
|
+
>>> print(f"Decoded {len(result.data)} bytes with {result.error_count} errors")
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
protocol: ProtocolType
|
|
88
|
+
overall_confidence: float
|
|
89
|
+
detected_params: dict[str, Any] = field(default_factory=dict)
|
|
90
|
+
data: list[DecodedByte] = field(default_factory=list)
|
|
91
|
+
frame_count: int = 0
|
|
92
|
+
error_count: int = 0
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def decode_protocol(
|
|
96
|
+
trace: WaveformTrace | DigitalTrace,
|
|
97
|
+
*,
|
|
98
|
+
protocol_hint: ProtocolType | None = None,
|
|
99
|
+
params_hint: dict[str, Any] | None = None,
|
|
100
|
+
confidence_threshold: float = 0.7,
|
|
101
|
+
return_errors: bool = True,
|
|
102
|
+
) -> DecodeResult:
|
|
103
|
+
"""Automatically decode protocol without user configuration.
|
|
104
|
+
|
|
105
|
+
Auto-detects protocol type, parameters (baud rate, polarity, bit order),
|
|
106
|
+
and decodes data with per-byte confidence scores.
|
|
107
|
+
|
|
108
|
+
Supported protocols:
|
|
109
|
+
- UART: Auto-detects baud rate, parity, stop bits
|
|
110
|
+
- SPI: Auto-detects mode (CPOL/CPHA), bit order
|
|
111
|
+
- I2C: Auto-detects clock rate, addressing mode
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
trace: Input waveform or digital trace.
|
|
115
|
+
protocol_hint: Optional protocol hint to narrow detection.
|
|
116
|
+
params_hint: Optional parameter hints (e.g., approximate clock freq).
|
|
117
|
+
confidence_threshold: Minimum confidence for valid bytes.
|
|
118
|
+
return_errors: Whether to include error information.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
DecodeResult with protocol, parameters, and decoded data.
|
|
122
|
+
|
|
123
|
+
Raises:
|
|
124
|
+
ValueError: If trace is empty or invalid.
|
|
125
|
+
|
|
126
|
+
Example:
|
|
127
|
+
>>> # Automatic decode with no configuration
|
|
128
|
+
>>> result = decode_protocol(trace)
|
|
129
|
+
>>> if result.overall_confidence >= 0.8:
|
|
130
|
+
... print(f"High confidence {result.protocol} decode")
|
|
131
|
+
... for byte_data in result.data:
|
|
132
|
+
... print(f"0x{byte_data.value:02X}")
|
|
133
|
+
|
|
134
|
+
>>> # Decode with hint to speed up detection
|
|
135
|
+
>>> result = decode_protocol(trace, protocol_hint='UART')
|
|
136
|
+
>>> print(f"Baud rate: {result.detected_params['baud_rate']}")
|
|
137
|
+
|
|
138
|
+
References:
|
|
139
|
+
DISC-010: One-Shot Protocol Decode
|
|
140
|
+
"""
|
|
141
|
+
# Validate input
|
|
142
|
+
if len(trace) == 0:
|
|
143
|
+
raise ValueError("Cannot decode empty trace")
|
|
144
|
+
|
|
145
|
+
# Auto-detect protocol if no hint provided
|
|
146
|
+
if protocol_hint is None:
|
|
147
|
+
char_result = characterize_signal(trace)
|
|
148
|
+
|
|
149
|
+
# Map signal types to protocols
|
|
150
|
+
if char_result.signal_type == "uart":
|
|
151
|
+
protocol_hint = "UART"
|
|
152
|
+
elif char_result.signal_type == "spi":
|
|
153
|
+
protocol_hint = "SPI"
|
|
154
|
+
elif char_result.signal_type == "i2c":
|
|
155
|
+
protocol_hint = "I2C"
|
|
156
|
+
# Try UART as default for digital signals
|
|
157
|
+
elif char_result.signal_type == "digital":
|
|
158
|
+
protocol_hint = "UART"
|
|
159
|
+
else:
|
|
160
|
+
return DecodeResult(
|
|
161
|
+
protocol="unknown",
|
|
162
|
+
overall_confidence=0.0,
|
|
163
|
+
detected_params={},
|
|
164
|
+
data=[],
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Decode based on detected/hinted protocol
|
|
168
|
+
if protocol_hint == "UART":
|
|
169
|
+
return _decode_uart_auto(trace, params_hint, confidence_threshold, return_errors)
|
|
170
|
+
elif protocol_hint == "SPI":
|
|
171
|
+
return _decode_spi_auto(trace, params_hint, confidence_threshold, return_errors)
|
|
172
|
+
elif protocol_hint == "I2C":
|
|
173
|
+
return _decode_i2c_auto(trace, params_hint, confidence_threshold, return_errors)
|
|
174
|
+
else:
|
|
175
|
+
return DecodeResult(
|
|
176
|
+
protocol="unknown",
|
|
177
|
+
overall_confidence=0.0,
|
|
178
|
+
detected_params={},
|
|
179
|
+
data=[],
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _decode_uart_auto(
|
|
184
|
+
trace: WaveformTrace | DigitalTrace,
|
|
185
|
+
params_hint: dict[str, Any] | None,
|
|
186
|
+
confidence_threshold: float,
|
|
187
|
+
return_errors: bool,
|
|
188
|
+
) -> DecodeResult:
|
|
189
|
+
"""Auto-decode UART with parameter detection.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
trace: Input trace.
|
|
193
|
+
params_hint: Optional parameter hints.
|
|
194
|
+
confidence_threshold: Minimum confidence threshold.
|
|
195
|
+
return_errors: Whether to include errors.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
DecodeResult for UART.
|
|
199
|
+
"""
|
|
200
|
+
from oscura.analyzers.protocols.uart import UARTDecoder
|
|
201
|
+
|
|
202
|
+
# Get data array
|
|
203
|
+
if isinstance(trace, WaveformTrace):
|
|
204
|
+
data = trace.data
|
|
205
|
+
sample_rate = trace.metadata.sample_rate
|
|
206
|
+
else:
|
|
207
|
+
data = trace.data.astype(np.float64)
|
|
208
|
+
sample_rate = trace.metadata.sample_rate
|
|
209
|
+
|
|
210
|
+
# Auto-detect baud rate if not provided
|
|
211
|
+
if params_hint and "baud_rate" in params_hint:
|
|
212
|
+
baud_rate = params_hint["baud_rate"]
|
|
213
|
+
else:
|
|
214
|
+
baud_rate = _detect_baud_rate(data, sample_rate)
|
|
215
|
+
|
|
216
|
+
# Default UART parameters (8N1)
|
|
217
|
+
data_bits = params_hint.get("data_bits", 8) if params_hint else 8
|
|
218
|
+
parity = params_hint.get("parity", "none") if params_hint else "none"
|
|
219
|
+
stop_bits = params_hint.get("stop_bits", 1) if params_hint else 1
|
|
220
|
+
|
|
221
|
+
# Create decoder with detected parameters
|
|
222
|
+
decoder = UARTDecoder(
|
|
223
|
+
baudrate=baud_rate,
|
|
224
|
+
data_bits=data_bits,
|
|
225
|
+
parity=parity, # type: ignore[arg-type]
|
|
226
|
+
stop_bits=stop_bits,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Decode
|
|
230
|
+
try:
|
|
231
|
+
packets = list(decoder.decode(trace))
|
|
232
|
+
except Exception:
|
|
233
|
+
# Decode failed
|
|
234
|
+
return DecodeResult(
|
|
235
|
+
protocol="UART",
|
|
236
|
+
overall_confidence=0.3,
|
|
237
|
+
detected_params={"baud_rate": baud_rate},
|
|
238
|
+
data=[],
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# Convert to DecodedByte format
|
|
242
|
+
decoded_bytes: list[DecodedByte] = []
|
|
243
|
+
error_count = 0
|
|
244
|
+
|
|
245
|
+
for i, packet in enumerate(packets):
|
|
246
|
+
for byte_val in packet.data:
|
|
247
|
+
# Calculate confidence based on errors
|
|
248
|
+
has_error = len(packet.errors) > 0
|
|
249
|
+
if has_error:
|
|
250
|
+
confidence = 0.65
|
|
251
|
+
error_count += 1
|
|
252
|
+
else:
|
|
253
|
+
confidence = 0.95
|
|
254
|
+
|
|
255
|
+
decoded_bytes.append(
|
|
256
|
+
DecodedByte(
|
|
257
|
+
value=byte_val,
|
|
258
|
+
offset=i,
|
|
259
|
+
confidence=confidence,
|
|
260
|
+
has_error=has_error,
|
|
261
|
+
error_type=packet.errors[0] if packet.errors else None,
|
|
262
|
+
error_description=packet.errors[0] if packet.errors else None,
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
# Calculate overall confidence
|
|
267
|
+
if decoded_bytes:
|
|
268
|
+
avg_confidence = np.mean([b.confidence for b in decoded_bytes])
|
|
269
|
+
overall_confidence = float(round(float(avg_confidence), 2))
|
|
270
|
+
else:
|
|
271
|
+
overall_confidence = 0.0
|
|
272
|
+
|
|
273
|
+
return DecodeResult(
|
|
274
|
+
protocol="UART",
|
|
275
|
+
overall_confidence=overall_confidence,
|
|
276
|
+
detected_params={
|
|
277
|
+
"baud_rate": baud_rate,
|
|
278
|
+
"data_bits": data_bits,
|
|
279
|
+
"parity": parity,
|
|
280
|
+
"stop_bits": stop_bits,
|
|
281
|
+
},
|
|
282
|
+
data=decoded_bytes,
|
|
283
|
+
frame_count=len(packets),
|
|
284
|
+
error_count=error_count,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _decode_spi_auto(
|
|
289
|
+
trace: WaveformTrace | DigitalTrace,
|
|
290
|
+
params_hint: dict[str, Any] | None,
|
|
291
|
+
confidence_threshold: float,
|
|
292
|
+
return_errors: bool,
|
|
293
|
+
) -> DecodeResult:
|
|
294
|
+
"""Auto-decode SPI with parameter detection.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
trace: Input trace.
|
|
298
|
+
params_hint: Optional parameter hints.
|
|
299
|
+
confidence_threshold: Minimum confidence threshold.
|
|
300
|
+
return_errors: Whether to include errors.
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
DecodeResult for SPI.
|
|
304
|
+
"""
|
|
305
|
+
# SPI requires multiple channels (clock, MOSI, optionally MISO)
|
|
306
|
+
# Single-channel auto-decode is limited
|
|
307
|
+
# Return low-confidence result indicating more channels needed
|
|
308
|
+
|
|
309
|
+
return DecodeResult(
|
|
310
|
+
protocol="SPI",
|
|
311
|
+
overall_confidence=0.4,
|
|
312
|
+
detected_params={"note": "SPI requires clock and data channels"},
|
|
313
|
+
data=[],
|
|
314
|
+
frame_count=0,
|
|
315
|
+
error_count=0,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def _decode_i2c_auto(
|
|
320
|
+
trace: WaveformTrace | DigitalTrace,
|
|
321
|
+
params_hint: dict[str, Any] | None,
|
|
322
|
+
confidence_threshold: float,
|
|
323
|
+
return_errors: bool,
|
|
324
|
+
) -> DecodeResult:
|
|
325
|
+
"""Auto-decode I2C with parameter detection.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
trace: Input trace.
|
|
329
|
+
params_hint: Optional parameter hints.
|
|
330
|
+
confidence_threshold: Minimum confidence threshold.
|
|
331
|
+
return_errors: Whether to include errors.
|
|
332
|
+
|
|
333
|
+
Returns:
|
|
334
|
+
DecodeResult for I2C.
|
|
335
|
+
"""
|
|
336
|
+
# I2C requires both SDA and SCL channels
|
|
337
|
+
# Single-channel auto-decode is limited
|
|
338
|
+
# Return low-confidence result indicating more channels needed
|
|
339
|
+
|
|
340
|
+
return DecodeResult(
|
|
341
|
+
protocol="I2C",
|
|
342
|
+
overall_confidence=0.4,
|
|
343
|
+
detected_params={"note": "I2C requires SDA and SCL channels"},
|
|
344
|
+
data=[],
|
|
345
|
+
frame_count=0,
|
|
346
|
+
error_count=0,
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _detect_baud_rate(data: NDArray[np.floating[Any]], sample_rate: float) -> int:
|
|
351
|
+
"""Auto-detect UART baud rate from signal.
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
data: Signal data array.
|
|
355
|
+
sample_rate: Sample rate in Hz.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
Detected baud rate in bps.
|
|
359
|
+
"""
|
|
360
|
+
# Threshold signal to digital
|
|
361
|
+
threshold = (np.max(data) + np.min(data)) / 2
|
|
362
|
+
digital = data > threshold
|
|
363
|
+
|
|
364
|
+
# Find edges
|
|
365
|
+
edges = np.where(np.diff(digital.astype(int)) != 0)[0]
|
|
366
|
+
|
|
367
|
+
if len(edges) < 10:
|
|
368
|
+
return 115200 # Default fallback
|
|
369
|
+
|
|
370
|
+
# Analyze edge intervals to find bit period
|
|
371
|
+
intervals = np.diff(edges)
|
|
372
|
+
|
|
373
|
+
# Use histogram to find most common interval (bit period)
|
|
374
|
+
hist, bin_edges = np.histogram(intervals, bins=50)
|
|
375
|
+
peak_bin = np.argmax(hist)
|
|
376
|
+
bit_period_samples = (bin_edges[peak_bin] + bin_edges[peak_bin + 1]) / 2
|
|
377
|
+
|
|
378
|
+
# Calculate baud rate
|
|
379
|
+
estimated_baud = int(sample_rate / bit_period_samples)
|
|
380
|
+
|
|
381
|
+
# Snap to common baud rates
|
|
382
|
+
common_bauds = [
|
|
383
|
+
300,
|
|
384
|
+
600,
|
|
385
|
+
1200,
|
|
386
|
+
2400,
|
|
387
|
+
4800,
|
|
388
|
+
9600,
|
|
389
|
+
14400,
|
|
390
|
+
19200,
|
|
391
|
+
28800,
|
|
392
|
+
38400,
|
|
393
|
+
57600,
|
|
394
|
+
115200,
|
|
395
|
+
230400,
|
|
396
|
+
460800,
|
|
397
|
+
921600,
|
|
398
|
+
]
|
|
399
|
+
|
|
400
|
+
closest_baud = min(common_bauds, key=lambda x: abs(x - estimated_baud))
|
|
401
|
+
|
|
402
|
+
# Validate: should be within 5% of detected rate
|
|
403
|
+
if abs(closest_baud - estimated_baud) / estimated_baud < 0.05:
|
|
404
|
+
return closest_baud
|
|
405
|
+
else:
|
|
406
|
+
# Use estimated rate if no close match
|
|
407
|
+
return estimated_baud
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
__all__ = [
|
|
411
|
+
"DecodeResult",
|
|
412
|
+
"DecodedByte",
|
|
413
|
+
"ProtocolType",
|
|
414
|
+
"decode_protocol",
|
|
415
|
+
]
|