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,150 @@
|
|
|
1
|
+
"""Protocol decoder package.
|
|
2
|
+
|
|
3
|
+
Provides protocol decoders for common serial and automotive protocols including
|
|
4
|
+
UART, SPI, I2C, CAN, LIN, FlexRay, JTAG, SWD, I2S, USB, HDLC, Manchester, CAN-FD,
|
|
5
|
+
and 1-Wire.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from oscura.analyzers.protocols.base import (
|
|
9
|
+
Annotation,
|
|
10
|
+
AnnotationLevel,
|
|
11
|
+
AsyncDecoder,
|
|
12
|
+
ChannelDef,
|
|
13
|
+
DecoderState,
|
|
14
|
+
OptionDef,
|
|
15
|
+
ProtocolDecoder,
|
|
16
|
+
SyncDecoder,
|
|
17
|
+
)
|
|
18
|
+
from oscura.analyzers.protocols.can import (
|
|
19
|
+
CAN_BITRATES,
|
|
20
|
+
CANDecoder,
|
|
21
|
+
CANFrame,
|
|
22
|
+
CANFrameType,
|
|
23
|
+
decode_can,
|
|
24
|
+
)
|
|
25
|
+
from oscura.analyzers.protocols.can_fd import (
|
|
26
|
+
CANFD_DLC_TO_LENGTH,
|
|
27
|
+
CANFDDecoder,
|
|
28
|
+
CANFDFrame,
|
|
29
|
+
CANFDFrameType,
|
|
30
|
+
decode_can_fd,
|
|
31
|
+
)
|
|
32
|
+
from oscura.analyzers.protocols.flexray import (
|
|
33
|
+
FlexRayDecoder,
|
|
34
|
+
FlexRayFrame,
|
|
35
|
+
FlexRaySegment,
|
|
36
|
+
decode_flexray,
|
|
37
|
+
)
|
|
38
|
+
from oscura.analyzers.protocols.hdlc import HDLCDecoder, decode_hdlc
|
|
39
|
+
from oscura.analyzers.protocols.i2c import I2CDecoder, decode_i2c
|
|
40
|
+
from oscura.analyzers.protocols.i2s import I2SDecoder, I2SMode, decode_i2s
|
|
41
|
+
from oscura.analyzers.protocols.jtag import (
|
|
42
|
+
JTAG_INSTRUCTIONS,
|
|
43
|
+
JTAGDecoder,
|
|
44
|
+
TAPState,
|
|
45
|
+
decode_jtag,
|
|
46
|
+
)
|
|
47
|
+
from oscura.analyzers.protocols.lin import LINDecoder, LINVersion, decode_lin
|
|
48
|
+
from oscura.analyzers.protocols.manchester import (
|
|
49
|
+
ManchesterDecoder,
|
|
50
|
+
ManchesterMode,
|
|
51
|
+
decode_manchester,
|
|
52
|
+
)
|
|
53
|
+
from oscura.analyzers.protocols.onewire import (
|
|
54
|
+
FAMILY_CODES,
|
|
55
|
+
ROM_COMMAND_NAMES,
|
|
56
|
+
OneWireDecoder,
|
|
57
|
+
OneWireMode,
|
|
58
|
+
OneWireROMCommand,
|
|
59
|
+
OneWireROMID,
|
|
60
|
+
OneWireTimings,
|
|
61
|
+
decode_onewire,
|
|
62
|
+
)
|
|
63
|
+
from oscura.analyzers.protocols.spi import SPIDecoder, decode_spi
|
|
64
|
+
from oscura.analyzers.protocols.swd import SWDDecoder, SWDResponse, decode_swd
|
|
65
|
+
from oscura.analyzers.protocols.uart import UARTDecoder, decode_uart
|
|
66
|
+
from oscura.analyzers.protocols.usb import (
|
|
67
|
+
PID_NAMES,
|
|
68
|
+
USBPID,
|
|
69
|
+
USBDecoder,
|
|
70
|
+
USBSpeed,
|
|
71
|
+
decode_usb,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
__all__ = [
|
|
75
|
+
"CANFD_DLC_TO_LENGTH",
|
|
76
|
+
"CAN_BITRATES",
|
|
77
|
+
# 1-Wire (PRO-007)
|
|
78
|
+
"FAMILY_CODES",
|
|
79
|
+
"JTAG_INSTRUCTIONS",
|
|
80
|
+
"PID_NAMES",
|
|
81
|
+
"ROM_COMMAND_NAMES",
|
|
82
|
+
"USBPID",
|
|
83
|
+
"Annotation",
|
|
84
|
+
"AnnotationLevel",
|
|
85
|
+
"AsyncDecoder",
|
|
86
|
+
# CAN (PRO-005)
|
|
87
|
+
"CANDecoder",
|
|
88
|
+
# CAN-FD (PRO-015)
|
|
89
|
+
"CANFDDecoder",
|
|
90
|
+
"CANFDFrame",
|
|
91
|
+
"CANFDFrameType",
|
|
92
|
+
"CANFrame",
|
|
93
|
+
"CANFrameType",
|
|
94
|
+
"ChannelDef",
|
|
95
|
+
"DecoderState",
|
|
96
|
+
# FlexRay (PRO-016)
|
|
97
|
+
"FlexRayDecoder",
|
|
98
|
+
"FlexRayFrame",
|
|
99
|
+
"FlexRaySegment",
|
|
100
|
+
# HDLC (PRO-013)
|
|
101
|
+
"HDLCDecoder",
|
|
102
|
+
# I2C (PRO-004)
|
|
103
|
+
"I2CDecoder",
|
|
104
|
+
# I2S (PRO-011)
|
|
105
|
+
"I2SDecoder",
|
|
106
|
+
"I2SMode",
|
|
107
|
+
# JTAG (PRO-009)
|
|
108
|
+
"JTAGDecoder",
|
|
109
|
+
# LIN (PRO-008)
|
|
110
|
+
"LINDecoder",
|
|
111
|
+
"LINVersion",
|
|
112
|
+
# Manchester (PRO-014)
|
|
113
|
+
"ManchesterDecoder",
|
|
114
|
+
"ManchesterMode",
|
|
115
|
+
# 1-Wire
|
|
116
|
+
"OneWireDecoder",
|
|
117
|
+
"OneWireMode",
|
|
118
|
+
"OneWireROMCommand",
|
|
119
|
+
"OneWireROMID",
|
|
120
|
+
"OneWireTimings",
|
|
121
|
+
"OptionDef",
|
|
122
|
+
# Base
|
|
123
|
+
"ProtocolDecoder",
|
|
124
|
+
# SPI (PRO-003)
|
|
125
|
+
"SPIDecoder",
|
|
126
|
+
# SWD (PRO-010)
|
|
127
|
+
"SWDDecoder",
|
|
128
|
+
"SWDResponse",
|
|
129
|
+
"SyncDecoder",
|
|
130
|
+
"TAPState",
|
|
131
|
+
# UART (PRO-002)
|
|
132
|
+
"UARTDecoder",
|
|
133
|
+
# USB (PRO-012)
|
|
134
|
+
"USBDecoder",
|
|
135
|
+
"USBSpeed",
|
|
136
|
+
"decode_can",
|
|
137
|
+
"decode_can_fd",
|
|
138
|
+
"decode_flexray",
|
|
139
|
+
"decode_hdlc",
|
|
140
|
+
"decode_i2c",
|
|
141
|
+
"decode_i2s",
|
|
142
|
+
"decode_jtag",
|
|
143
|
+
"decode_lin",
|
|
144
|
+
"decode_manchester",
|
|
145
|
+
"decode_onewire",
|
|
146
|
+
"decode_spi",
|
|
147
|
+
"decode_swd",
|
|
148
|
+
"decode_uart",
|
|
149
|
+
"decode_usb",
|
|
150
|
+
]
|
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
"""Protocol decoder base class (sigrok-inspired).
|
|
2
|
+
|
|
3
|
+
This module provides the base class for protocol decoders,
|
|
4
|
+
following a sigrok-inspired API for consistency with the
|
|
5
|
+
open-source protocol decoding ecosystem.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
>>> from oscura.analyzers.protocols.base import ProtocolDecoder
|
|
10
|
+
>>> class UARTDecoder(ProtocolDecoder):
|
|
11
|
+
... id = "uart"
|
|
12
|
+
... name = "UART"
|
|
13
|
+
... channels = [{"id": "rx", "name": "RX", "desc": "Receive data"}]
|
|
14
|
+
... def decode(self, trace):
|
|
15
|
+
... # Implementation
|
|
16
|
+
... pass
|
|
17
|
+
|
|
18
|
+
References:
|
|
19
|
+
sigrok Protocol Decoder API: https://sigrok.org/wiki/Protocol_decoder_API
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from abc import ABC, abstractmethod
|
|
25
|
+
from dataclasses import dataclass, field
|
|
26
|
+
from enum import IntEnum
|
|
27
|
+
from typing import TYPE_CHECKING, Any
|
|
28
|
+
|
|
29
|
+
import numpy as np
|
|
30
|
+
|
|
31
|
+
from oscura.core.types import DigitalTrace, ProtocolPacket
|
|
32
|
+
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
from collections.abc import Iterator
|
|
35
|
+
|
|
36
|
+
from numpy.typing import NDArray
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AnnotationLevel(IntEnum):
|
|
40
|
+
"""Annotation hierarchy levels.
|
|
41
|
+
|
|
42
|
+
Protocol decoders use multiple annotation levels for different
|
|
43
|
+
levels of detail, from raw bits to high-level interpretations.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
BITS = 0 # Raw bit values
|
|
47
|
+
BYTES = 1 # Byte values
|
|
48
|
+
WORDS = 2 # Words/frames
|
|
49
|
+
FIELDS = 3 # Named fields
|
|
50
|
+
PACKETS = 4 # Complete packets
|
|
51
|
+
MESSAGES = 5 # High-level messages
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class Annotation:
|
|
56
|
+
"""Protocol annotation at a specific time range.
|
|
57
|
+
|
|
58
|
+
Attributes:
|
|
59
|
+
start_time: Start time in seconds.
|
|
60
|
+
end_time: End time in seconds.
|
|
61
|
+
level: Annotation level (bits, bytes, packets, etc.).
|
|
62
|
+
text: Human-readable annotation text.
|
|
63
|
+
data: Raw data associated with annotation.
|
|
64
|
+
metadata: Additional annotation metadata.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
start_time: float
|
|
68
|
+
end_time: float
|
|
69
|
+
level: AnnotationLevel
|
|
70
|
+
text: str
|
|
71
|
+
data: bytes | None = None
|
|
72
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@dataclass
|
|
76
|
+
class ChannelDef:
|
|
77
|
+
"""Channel definition for protocol decoder.
|
|
78
|
+
|
|
79
|
+
Attributes:
|
|
80
|
+
id: Channel identifier (e.g., "tx", "rx", "clk").
|
|
81
|
+
name: Human-readable name.
|
|
82
|
+
desc: Description of channel purpose.
|
|
83
|
+
required: Whether channel is required.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
id: str
|
|
87
|
+
name: str
|
|
88
|
+
desc: str = ""
|
|
89
|
+
required: bool = True
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass
|
|
93
|
+
class OptionDef:
|
|
94
|
+
"""Option definition for protocol decoder.
|
|
95
|
+
|
|
96
|
+
Attributes:
|
|
97
|
+
id: Option identifier.
|
|
98
|
+
name: Human-readable name.
|
|
99
|
+
desc: Description.
|
|
100
|
+
default: Default value.
|
|
101
|
+
values: List of valid values (if enumerated).
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
id: str
|
|
105
|
+
name: str
|
|
106
|
+
desc: str = ""
|
|
107
|
+
default: Any = None
|
|
108
|
+
values: list[Any] | None = None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class DecoderState:
|
|
112
|
+
"""Base class for decoder state machines.
|
|
113
|
+
|
|
114
|
+
Protocol decoders can subclass this to track their internal state
|
|
115
|
+
during frame/packet decoding.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
def __init__(self) -> None:
|
|
119
|
+
"""Initialize decoder state."""
|
|
120
|
+
self.reset()
|
|
121
|
+
|
|
122
|
+
def reset(self) -> None:
|
|
123
|
+
"""Reset state to initial values."""
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class ProtocolDecoder(ABC):
|
|
127
|
+
"""Base class for protocol decoders.
|
|
128
|
+
|
|
129
|
+
Provides sigrok-inspired API for implementing protocol decoders
|
|
130
|
+
that convert digital traces to decoded protocol packets.
|
|
131
|
+
|
|
132
|
+
Class Attributes:
|
|
133
|
+
api_version: Protocol decoder API version.
|
|
134
|
+
id: Unique decoder identifier.
|
|
135
|
+
name: Human-readable decoder name.
|
|
136
|
+
longname: Full name with description.
|
|
137
|
+
desc: Short description.
|
|
138
|
+
license: License identifier.
|
|
139
|
+
inputs: Required input types (e.g., ["logic"]).
|
|
140
|
+
outputs: Output types produced.
|
|
141
|
+
channels: Required channel definitions.
|
|
142
|
+
optional_channels: Optional channel definitions.
|
|
143
|
+
options: Configurable options.
|
|
144
|
+
annotations: Annotation type definitions.
|
|
145
|
+
|
|
146
|
+
Example:
|
|
147
|
+
>>> class SPIDecoder(ProtocolDecoder):
|
|
148
|
+
... id = "spi"
|
|
149
|
+
... name = "SPI"
|
|
150
|
+
... channels = [
|
|
151
|
+
... ChannelDef("clk", "CLK", "Clock"),
|
|
152
|
+
... ChannelDef("mosi", "MOSI", "Master Out Slave In"),
|
|
153
|
+
... ChannelDef("miso", "MISO", "Master In Slave Out"),
|
|
154
|
+
... ]
|
|
155
|
+
... optional_channels = [
|
|
156
|
+
... ChannelDef("cs", "CS#", "Chip Select", required=False),
|
|
157
|
+
... ]
|
|
158
|
+
... options = [
|
|
159
|
+
... OptionDef("cpol", "Clock Polarity", default=0, values=[0, 1]),
|
|
160
|
+
... OptionDef("cpha", "Clock Phase", default=0, values=[0, 1]),
|
|
161
|
+
... ]
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
# API version
|
|
165
|
+
api_version: int = 3
|
|
166
|
+
|
|
167
|
+
# Decoder identification
|
|
168
|
+
id: str = "unknown"
|
|
169
|
+
name: str = "Unknown"
|
|
170
|
+
longname: str = ""
|
|
171
|
+
desc: str = ""
|
|
172
|
+
license: str = "MIT"
|
|
173
|
+
|
|
174
|
+
# Input/output types
|
|
175
|
+
inputs: list[str] = ["logic"] # noqa: RUF012
|
|
176
|
+
outputs: list[str] = ["packets"] # noqa: RUF012
|
|
177
|
+
|
|
178
|
+
# Channel definitions
|
|
179
|
+
channels: list[ChannelDef] = [] # noqa: RUF012
|
|
180
|
+
optional_channels: list[ChannelDef] = [] # noqa: RUF012
|
|
181
|
+
|
|
182
|
+
# Options
|
|
183
|
+
options: list[OptionDef] = [] # noqa: RUF012
|
|
184
|
+
|
|
185
|
+
# Annotation definitions (override in subclass)
|
|
186
|
+
annotations: list[tuple[str, str]] = [] # noqa: RUF012
|
|
187
|
+
|
|
188
|
+
def __init__(self, **options: Any) -> None:
|
|
189
|
+
"""Initialize decoder with options.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
**options: Decoder-specific options.
|
|
193
|
+
|
|
194
|
+
Raises:
|
|
195
|
+
ValueError: If unknown option is provided
|
|
196
|
+
"""
|
|
197
|
+
self._options: dict[str, Any] = {}
|
|
198
|
+
self._annotations: list[Annotation] = []
|
|
199
|
+
self._packets: list[ProtocolPacket] = []
|
|
200
|
+
self._state = DecoderState()
|
|
201
|
+
|
|
202
|
+
# Set default options
|
|
203
|
+
for opt in self.options:
|
|
204
|
+
self._options[opt.id] = opt.default
|
|
205
|
+
|
|
206
|
+
# Override with provided options
|
|
207
|
+
for key, value in options.items():
|
|
208
|
+
if any(opt.id == key for opt in self.options):
|
|
209
|
+
self._options[key] = value
|
|
210
|
+
else:
|
|
211
|
+
raise ValueError(f"Unknown option: {key}")
|
|
212
|
+
|
|
213
|
+
def get_option(self, name: str) -> Any:
|
|
214
|
+
"""Get option value.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
name: Option name.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
Option value.
|
|
221
|
+
"""
|
|
222
|
+
return self._options.get(name)
|
|
223
|
+
|
|
224
|
+
def set_option(self, name: str, value: Any) -> None:
|
|
225
|
+
"""Set option value.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
name: Option name.
|
|
229
|
+
value: New value.
|
|
230
|
+
"""
|
|
231
|
+
self._options[name] = value
|
|
232
|
+
|
|
233
|
+
def reset(self) -> None:
|
|
234
|
+
"""Reset decoder state.
|
|
235
|
+
|
|
236
|
+
Clears all accumulated annotations and packets, and resets
|
|
237
|
+
the internal state machine to initial state.
|
|
238
|
+
"""
|
|
239
|
+
self._annotations.clear()
|
|
240
|
+
self._packets.clear()
|
|
241
|
+
self._state.reset()
|
|
242
|
+
|
|
243
|
+
def put_annotation(
|
|
244
|
+
self,
|
|
245
|
+
start_time: float,
|
|
246
|
+
end_time: float,
|
|
247
|
+
level: AnnotationLevel,
|
|
248
|
+
text: str,
|
|
249
|
+
data: bytes | None = None,
|
|
250
|
+
**metadata: Any,
|
|
251
|
+
) -> None:
|
|
252
|
+
"""Add an annotation.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
start_time: Start time in seconds.
|
|
256
|
+
end_time: End time in seconds.
|
|
257
|
+
level: Annotation level.
|
|
258
|
+
text: Annotation text.
|
|
259
|
+
data: Associated binary data.
|
|
260
|
+
**metadata: Additional metadata.
|
|
261
|
+
"""
|
|
262
|
+
self._annotations.append(
|
|
263
|
+
Annotation(
|
|
264
|
+
start_time=start_time,
|
|
265
|
+
end_time=end_time,
|
|
266
|
+
level=level,
|
|
267
|
+
text=text,
|
|
268
|
+
data=data,
|
|
269
|
+
metadata=metadata,
|
|
270
|
+
)
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
def put_packet(
|
|
274
|
+
self,
|
|
275
|
+
timestamp: float,
|
|
276
|
+
data: bytes,
|
|
277
|
+
annotations: dict[str, Any] | None = None,
|
|
278
|
+
errors: list[str] | None = None,
|
|
279
|
+
) -> None:
|
|
280
|
+
"""Add a decoded packet.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
timestamp: Packet start time.
|
|
284
|
+
data: Decoded data bytes.
|
|
285
|
+
annotations: Packet annotations.
|
|
286
|
+
errors: Detected errors.
|
|
287
|
+
"""
|
|
288
|
+
self._packets.append(
|
|
289
|
+
ProtocolPacket(
|
|
290
|
+
timestamp=timestamp,
|
|
291
|
+
protocol=self.id,
|
|
292
|
+
data=data,
|
|
293
|
+
annotations=annotations or {},
|
|
294
|
+
errors=errors or [],
|
|
295
|
+
)
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
@abstractmethod
|
|
299
|
+
def decode(
|
|
300
|
+
self,
|
|
301
|
+
trace: DigitalTrace,
|
|
302
|
+
**channels: NDArray[np.bool_],
|
|
303
|
+
) -> Iterator[ProtocolPacket]:
|
|
304
|
+
"""Decode a digital trace.
|
|
305
|
+
|
|
306
|
+
This is the main entry point for decoding. Implementations should
|
|
307
|
+
yield ProtocolPacket objects as they are decoded.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
trace: Primary input trace.
|
|
311
|
+
**channels: Additional channel data by name.
|
|
312
|
+
|
|
313
|
+
Yields:
|
|
314
|
+
Decoded protocol packets.
|
|
315
|
+
|
|
316
|
+
Example:
|
|
317
|
+
>>> decoder = UARTDecoder(baudrate=115200)
|
|
318
|
+
>>> for packet in decoder.decode(trace):
|
|
319
|
+
... print(f"Data: {packet.data.hex()}")
|
|
320
|
+
"""
|
|
321
|
+
|
|
322
|
+
def get_annotations(
|
|
323
|
+
self,
|
|
324
|
+
*,
|
|
325
|
+
level: AnnotationLevel | None = None,
|
|
326
|
+
start_time: float | None = None,
|
|
327
|
+
end_time: float | None = None,
|
|
328
|
+
) -> list[Annotation]:
|
|
329
|
+
"""Get accumulated annotations.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
level: Filter by annotation level.
|
|
333
|
+
start_time: Filter by start time (inclusive).
|
|
334
|
+
end_time: Filter by end time (inclusive).
|
|
335
|
+
|
|
336
|
+
Returns:
|
|
337
|
+
List of matching annotations.
|
|
338
|
+
"""
|
|
339
|
+
result = self._annotations
|
|
340
|
+
|
|
341
|
+
if level is not None:
|
|
342
|
+
result = [a for a in result if a.level == level]
|
|
343
|
+
|
|
344
|
+
if start_time is not None:
|
|
345
|
+
result = [a for a in result if a.end_time >= start_time]
|
|
346
|
+
|
|
347
|
+
if end_time is not None:
|
|
348
|
+
result = [a for a in result if a.start_time <= end_time]
|
|
349
|
+
|
|
350
|
+
return result
|
|
351
|
+
|
|
352
|
+
def get_packets(self) -> list[ProtocolPacket]:
|
|
353
|
+
"""Get all decoded packets.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
List of decoded packets.
|
|
357
|
+
"""
|
|
358
|
+
return list(self._packets)
|
|
359
|
+
|
|
360
|
+
@classmethod
|
|
361
|
+
def get_channel_ids(cls, include_optional: bool = False) -> list[str]:
|
|
362
|
+
"""Get list of channel IDs.
|
|
363
|
+
|
|
364
|
+
Args:
|
|
365
|
+
include_optional: Include optional channels.
|
|
366
|
+
|
|
367
|
+
Returns:
|
|
368
|
+
List of channel ID strings.
|
|
369
|
+
"""
|
|
370
|
+
ids = [ch.id for ch in cls.channels]
|
|
371
|
+
if include_optional:
|
|
372
|
+
ids.extend(ch.id for ch in cls.optional_channels)
|
|
373
|
+
return ids
|
|
374
|
+
|
|
375
|
+
@classmethod
|
|
376
|
+
def get_option_ids(cls) -> list[str]:
|
|
377
|
+
"""Get list of option IDs.
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
List of option ID strings.
|
|
381
|
+
"""
|
|
382
|
+
return [opt.id for opt in cls.options]
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
class SyncDecoder(ProtocolDecoder):
|
|
386
|
+
"""Base class for synchronous protocol decoders.
|
|
387
|
+
|
|
388
|
+
Synchronous protocols use a clock signal for timing. This base class
|
|
389
|
+
provides helpers for clock edge detection and data sampling.
|
|
390
|
+
"""
|
|
391
|
+
|
|
392
|
+
def sample_on_edge(
|
|
393
|
+
self,
|
|
394
|
+
clock: NDArray[np.bool_],
|
|
395
|
+
data: NDArray[np.bool_],
|
|
396
|
+
edge: str = "rising",
|
|
397
|
+
) -> NDArray[np.bool_]:
|
|
398
|
+
"""Sample data on clock edges.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
clock: Clock signal.
|
|
402
|
+
data: Data signal.
|
|
403
|
+
edge: "rising" or "falling".
|
|
404
|
+
|
|
405
|
+
Returns:
|
|
406
|
+
Data values at clock edges.
|
|
407
|
+
"""
|
|
408
|
+
if edge == "rising":
|
|
409
|
+
edges = np.where(~clock[:-1] & clock[1:])[0]
|
|
410
|
+
else:
|
|
411
|
+
edges = np.where(clock[:-1] & ~clock[1:])[0]
|
|
412
|
+
|
|
413
|
+
# Sample data after edge (shifted by 1)
|
|
414
|
+
sample_indices = edges + 1
|
|
415
|
+
sample_indices = sample_indices[sample_indices < len(data)]
|
|
416
|
+
|
|
417
|
+
result: NDArray[np.bool_] = data[sample_indices]
|
|
418
|
+
return result
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
class AsyncDecoder(ProtocolDecoder):
|
|
422
|
+
"""Base class for asynchronous protocol decoders.
|
|
423
|
+
|
|
424
|
+
Asynchronous protocols (like UART) use timing-based sampling without
|
|
425
|
+
a separate clock signal. This base class provides helpers for
|
|
426
|
+
bit-timing and symbol detection.
|
|
427
|
+
"""
|
|
428
|
+
|
|
429
|
+
def __init__(self, baudrate: int = 9600, **options: Any) -> None:
|
|
430
|
+
"""Initialize async decoder.
|
|
431
|
+
|
|
432
|
+
Args:
|
|
433
|
+
baudrate: Bit rate in bps.
|
|
434
|
+
**options: Additional options.
|
|
435
|
+
"""
|
|
436
|
+
super().__init__(**options)
|
|
437
|
+
self._baudrate = baudrate
|
|
438
|
+
|
|
439
|
+
@property
|
|
440
|
+
def baudrate(self) -> int:
|
|
441
|
+
"""Get baud rate."""
|
|
442
|
+
return self._baudrate
|
|
443
|
+
|
|
444
|
+
@baudrate.setter
|
|
445
|
+
def baudrate(self, value: int) -> None:
|
|
446
|
+
"""Set baud rate."""
|
|
447
|
+
self._baudrate = value
|
|
448
|
+
|
|
449
|
+
def bit_time(self, sample_rate: float) -> float:
|
|
450
|
+
"""Get bit time in samples.
|
|
451
|
+
|
|
452
|
+
Args:
|
|
453
|
+
sample_rate: Sample rate in Hz.
|
|
454
|
+
|
|
455
|
+
Returns:
|
|
456
|
+
Number of samples per bit.
|
|
457
|
+
"""
|
|
458
|
+
return sample_rate / self._baudrate
|
|
459
|
+
|
|
460
|
+
def find_start_bit(
|
|
461
|
+
self,
|
|
462
|
+
data: NDArray[np.bool_],
|
|
463
|
+
start_idx: int = 0,
|
|
464
|
+
idle_high: bool = True,
|
|
465
|
+
) -> int | None:
|
|
466
|
+
"""Find start bit transition.
|
|
467
|
+
|
|
468
|
+
Args:
|
|
469
|
+
data: Digital signal.
|
|
470
|
+
start_idx: Start search index.
|
|
471
|
+
idle_high: True if idle is high (standard UART).
|
|
472
|
+
|
|
473
|
+
Returns:
|
|
474
|
+
Index of start bit, or None if not found.
|
|
475
|
+
"""
|
|
476
|
+
search_region = data[start_idx:]
|
|
477
|
+
|
|
478
|
+
if idle_high:
|
|
479
|
+
# Look for falling edge (high to low)
|
|
480
|
+
transitions = np.where(search_region[:-1] & ~search_region[1:])[0]
|
|
481
|
+
else:
|
|
482
|
+
# Look for rising edge (low to high)
|
|
483
|
+
transitions = np.where(~search_region[:-1] & search_region[1:])[0]
|
|
484
|
+
|
|
485
|
+
if len(transitions) == 0:
|
|
486
|
+
return None
|
|
487
|
+
|
|
488
|
+
return int(start_idx + transitions[0])
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
__all__ = [
|
|
492
|
+
"Annotation",
|
|
493
|
+
"AnnotationLevel",
|
|
494
|
+
"AsyncDecoder",
|
|
495
|
+
"ChannelDef",
|
|
496
|
+
"DecoderState",
|
|
497
|
+
"OptionDef",
|
|
498
|
+
"ProtocolDecoder",
|
|
499
|
+
"SyncDecoder",
|
|
500
|
+
]
|