oscura 0.5.1__py3-none-any.whl → 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oscura/__init__.py +169 -167
- oscura/analyzers/__init__.py +3 -0
- oscura/analyzers/classification.py +659 -0
- oscura/analyzers/digital/edges.py +325 -65
- oscura/analyzers/digital/quality.py +293 -166
- oscura/analyzers/digital/timing.py +260 -115
- oscura/analyzers/digital/timing_numba.py +334 -0
- oscura/analyzers/entropy.py +605 -0
- oscura/analyzers/eye/diagram.py +176 -109
- oscura/analyzers/eye/metrics.py +5 -5
- oscura/analyzers/jitter/__init__.py +6 -4
- oscura/analyzers/jitter/ber.py +52 -52
- oscura/analyzers/jitter/classification.py +156 -0
- oscura/analyzers/jitter/decomposition.py +163 -113
- oscura/analyzers/jitter/spectrum.py +80 -64
- oscura/analyzers/ml/__init__.py +39 -0
- oscura/analyzers/ml/features.py +600 -0
- oscura/analyzers/ml/signal_classifier.py +604 -0
- oscura/analyzers/packet/daq.py +246 -158
- oscura/analyzers/packet/parser.py +12 -1
- oscura/analyzers/packet/payload.py +50 -2110
- oscura/analyzers/packet/payload_analysis.py +361 -181
- oscura/analyzers/packet/payload_patterns.py +133 -70
- oscura/analyzers/packet/stream.py +84 -23
- oscura/analyzers/patterns/__init__.py +26 -5
- oscura/analyzers/patterns/anomaly_detection.py +908 -0
- oscura/analyzers/patterns/clustering.py +169 -108
- oscura/analyzers/patterns/clustering_optimized.py +227 -0
- oscura/analyzers/patterns/discovery.py +1 -1
- oscura/analyzers/patterns/matching.py +581 -197
- oscura/analyzers/patterns/pattern_mining.py +778 -0
- oscura/analyzers/patterns/periodic.py +121 -38
- oscura/analyzers/patterns/sequences.py +175 -78
- oscura/analyzers/power/conduction.py +1 -1
- oscura/analyzers/power/soa.py +6 -6
- oscura/analyzers/power/switching.py +250 -110
- oscura/analyzers/protocol/__init__.py +17 -1
- oscura/analyzers/protocols/base.py +6 -6
- oscura/analyzers/protocols/ble/__init__.py +38 -0
- oscura/analyzers/protocols/ble/analyzer.py +809 -0
- oscura/analyzers/protocols/ble/uuids.py +288 -0
- oscura/analyzers/protocols/can.py +257 -127
- oscura/analyzers/protocols/can_fd.py +107 -80
- oscura/analyzers/protocols/flexray.py +139 -80
- oscura/analyzers/protocols/hdlc.py +93 -58
- oscura/analyzers/protocols/i2c.py +247 -106
- oscura/analyzers/protocols/i2s.py +138 -86
- oscura/analyzers/protocols/industrial/__init__.py +40 -0
- oscura/analyzers/protocols/industrial/bacnet/__init__.py +33 -0
- oscura/analyzers/protocols/industrial/bacnet/analyzer.py +708 -0
- oscura/analyzers/protocols/industrial/bacnet/encoding.py +412 -0
- oscura/analyzers/protocols/industrial/bacnet/services.py +622 -0
- oscura/analyzers/protocols/industrial/ethercat/__init__.py +30 -0
- oscura/analyzers/protocols/industrial/ethercat/analyzer.py +474 -0
- oscura/analyzers/protocols/industrial/ethercat/mailbox.py +339 -0
- oscura/analyzers/protocols/industrial/ethercat/topology.py +166 -0
- oscura/analyzers/protocols/industrial/modbus/__init__.py +31 -0
- oscura/analyzers/protocols/industrial/modbus/analyzer.py +525 -0
- oscura/analyzers/protocols/industrial/modbus/crc.py +79 -0
- oscura/analyzers/protocols/industrial/modbus/functions.py +436 -0
- oscura/analyzers/protocols/industrial/opcua/__init__.py +21 -0
- oscura/analyzers/protocols/industrial/opcua/analyzer.py +552 -0
- oscura/analyzers/protocols/industrial/opcua/datatypes.py +446 -0
- oscura/analyzers/protocols/industrial/opcua/services.py +264 -0
- oscura/analyzers/protocols/industrial/profinet/__init__.py +23 -0
- oscura/analyzers/protocols/industrial/profinet/analyzer.py +441 -0
- oscura/analyzers/protocols/industrial/profinet/dcp.py +263 -0
- oscura/analyzers/protocols/industrial/profinet/ptcp.py +200 -0
- oscura/analyzers/protocols/jtag.py +180 -98
- oscura/analyzers/protocols/lin.py +219 -114
- oscura/analyzers/protocols/manchester.py +4 -4
- oscura/analyzers/protocols/onewire.py +253 -149
- oscura/analyzers/protocols/parallel_bus/__init__.py +20 -0
- oscura/analyzers/protocols/parallel_bus/centronics.py +92 -0
- oscura/analyzers/protocols/parallel_bus/gpib.py +137 -0
- oscura/analyzers/protocols/spi.py +192 -95
- oscura/analyzers/protocols/swd.py +321 -167
- oscura/analyzers/protocols/uart.py +267 -125
- oscura/analyzers/protocols/usb.py +235 -131
- oscura/analyzers/side_channel/power.py +17 -12
- oscura/analyzers/signal/__init__.py +15 -0
- oscura/analyzers/signal/timing_analysis.py +1086 -0
- oscura/analyzers/signal_integrity/__init__.py +4 -1
- oscura/analyzers/signal_integrity/sparams.py +2 -19
- oscura/analyzers/spectral/chunked.py +129 -60
- oscura/analyzers/spectral/chunked_fft.py +300 -94
- oscura/analyzers/spectral/chunked_wavelet.py +100 -80
- oscura/analyzers/statistical/checksum.py +376 -217
- oscura/analyzers/statistical/classification.py +229 -107
- oscura/analyzers/statistical/entropy.py +78 -53
- oscura/analyzers/statistics/correlation.py +407 -211
- oscura/analyzers/statistics/outliers.py +2 -2
- oscura/analyzers/statistics/streaming.py +30 -5
- oscura/analyzers/validation.py +216 -101
- oscura/analyzers/waveform/measurements.py +9 -0
- oscura/analyzers/waveform/measurements_with_uncertainty.py +31 -15
- oscura/analyzers/waveform/spectral.py +500 -228
- oscura/api/__init__.py +31 -5
- oscura/api/dsl/__init__.py +582 -0
- oscura/{dsl → api/dsl}/commands.py +43 -76
- oscura/{dsl → api/dsl}/interpreter.py +26 -51
- oscura/{dsl → api/dsl}/parser.py +107 -77
- oscura/{dsl → api/dsl}/repl.py +2 -2
- oscura/api/dsl.py +1 -1
- oscura/{integrations → api/integrations}/__init__.py +1 -1
- oscura/{integrations → api/integrations}/llm.py +201 -102
- oscura/api/operators.py +3 -3
- oscura/api/optimization.py +144 -30
- oscura/api/rest_server.py +921 -0
- oscura/api/server/__init__.py +17 -0
- oscura/api/server/dashboard.py +850 -0
- oscura/api/server/static/README.md +34 -0
- oscura/api/server/templates/base.html +181 -0
- oscura/api/server/templates/export.html +120 -0
- oscura/api/server/templates/home.html +284 -0
- oscura/api/server/templates/protocols.html +58 -0
- oscura/api/server/templates/reports.html +43 -0
- oscura/api/server/templates/session_detail.html +89 -0
- oscura/api/server/templates/sessions.html +83 -0
- oscura/api/server/templates/waveforms.html +73 -0
- oscura/automotive/__init__.py +8 -1
- oscura/automotive/can/__init__.py +10 -0
- oscura/automotive/can/checksum.py +3 -1
- oscura/automotive/can/dbc_generator.py +590 -0
- oscura/automotive/can/message_wrapper.py +121 -74
- oscura/automotive/can/patterns.py +98 -21
- oscura/automotive/can/session.py +292 -56
- oscura/automotive/can/state_machine.py +6 -3
- oscura/automotive/can/stimulus_response.py +97 -75
- oscura/automotive/dbc/__init__.py +10 -2
- oscura/automotive/dbc/generator.py +84 -56
- oscura/automotive/dbc/parser.py +6 -6
- oscura/automotive/dtc/data.json +17 -102
- oscura/automotive/dtc/database.py +2 -2
- oscura/automotive/flexray/__init__.py +31 -0
- oscura/automotive/flexray/analyzer.py +504 -0
- oscura/automotive/flexray/crc.py +185 -0
- oscura/automotive/flexray/fibex.py +449 -0
- oscura/automotive/j1939/__init__.py +45 -8
- oscura/automotive/j1939/analyzer.py +605 -0
- oscura/automotive/j1939/spns.py +326 -0
- oscura/automotive/j1939/transport.py +306 -0
- oscura/automotive/lin/__init__.py +47 -0
- oscura/automotive/lin/analyzer.py +612 -0
- oscura/automotive/loaders/blf.py +13 -2
- oscura/automotive/loaders/csv_can.py +143 -72
- oscura/automotive/loaders/dispatcher.py +50 -2
- oscura/automotive/loaders/mdf.py +86 -45
- oscura/automotive/loaders/pcap.py +111 -61
- oscura/automotive/uds/__init__.py +4 -0
- oscura/automotive/uds/analyzer.py +725 -0
- oscura/automotive/uds/decoder.py +140 -58
- oscura/automotive/uds/models.py +7 -1
- oscura/automotive/visualization.py +1 -1
- oscura/cli/analyze.py +348 -0
- oscura/cli/batch.py +142 -122
- oscura/cli/benchmark.py +275 -0
- oscura/cli/characterize.py +137 -82
- oscura/cli/compare.py +224 -131
- oscura/cli/completion.py +250 -0
- oscura/cli/config_cmd.py +361 -0
- oscura/cli/decode.py +164 -87
- oscura/cli/export.py +286 -0
- oscura/cli/main.py +115 -31
- oscura/{onboarding → cli/onboarding}/__init__.py +3 -3
- oscura/{onboarding → cli/onboarding}/help.py +80 -58
- oscura/{onboarding → cli/onboarding}/tutorials.py +97 -72
- oscura/{onboarding → cli/onboarding}/wizard.py +55 -36
- oscura/cli/progress.py +147 -0
- oscura/cli/shell.py +157 -135
- oscura/cli/validate_cmd.py +204 -0
- oscura/cli/visualize.py +158 -0
- oscura/convenience.py +125 -79
- oscura/core/__init__.py +4 -2
- oscura/core/backend_selector.py +3 -3
- oscura/core/cache.py +126 -15
- oscura/core/cancellation.py +1 -1
- oscura/{config → core/config}/__init__.py +20 -11
- oscura/{config → core/config}/defaults.py +1 -1
- oscura/{config → core/config}/loader.py +7 -5
- oscura/{config → core/config}/memory.py +5 -5
- oscura/{config → core/config}/migration.py +1 -1
- oscura/{config → core/config}/pipeline.py +99 -23
- oscura/{config → core/config}/preferences.py +1 -1
- oscura/{config → core/config}/protocol.py +3 -3
- oscura/{config → core/config}/schema.py +426 -272
- oscura/{config → core/config}/settings.py +1 -1
- oscura/{config → core/config}/thresholds.py +195 -153
- oscura/core/correlation.py +5 -6
- oscura/core/cross_domain.py +0 -2
- oscura/core/debug.py +9 -5
- oscura/{extensibility → core/extensibility}/docs.py +158 -70
- oscura/{extensibility → core/extensibility}/extensions.py +160 -76
- oscura/{extensibility → core/extensibility}/logging.py +1 -1
- oscura/{extensibility → core/extensibility}/measurements.py +1 -1
- oscura/{extensibility → core/extensibility}/plugins.py +1 -1
- oscura/{extensibility → core/extensibility}/templates.py +73 -3
- oscura/{extensibility → core/extensibility}/validation.py +1 -1
- oscura/core/gpu_backend.py +11 -7
- oscura/core/log_query.py +101 -11
- oscura/core/logging.py +126 -54
- oscura/core/logging_advanced.py +5 -5
- oscura/core/memory_limits.py +108 -70
- oscura/core/memory_monitor.py +2 -2
- oscura/core/memory_progress.py +7 -7
- oscura/core/memory_warnings.py +1 -1
- oscura/core/numba_backend.py +13 -13
- oscura/{plugins → core/plugins}/__init__.py +9 -9
- oscura/{plugins → core/plugins}/base.py +7 -7
- oscura/{plugins → core/plugins}/cli.py +3 -3
- oscura/{plugins → core/plugins}/discovery.py +186 -106
- oscura/{plugins → core/plugins}/lifecycle.py +1 -1
- oscura/{plugins → core/plugins}/manager.py +7 -7
- oscura/{plugins → core/plugins}/registry.py +3 -3
- oscura/{plugins → core/plugins}/versioning.py +1 -1
- oscura/core/progress.py +16 -1
- oscura/core/provenance.py +8 -2
- oscura/{schemas → core/schemas}/__init__.py +2 -2
- oscura/{schemas → core/schemas}/device_mapping.json +2 -8
- oscura/{schemas → core/schemas}/packet_format.json +4 -24
- oscura/{schemas → core/schemas}/protocol_definition.json +2 -12
- oscura/core/types.py +4 -0
- oscura/core/uncertainty.py +3 -3
- oscura/correlation/__init__.py +52 -0
- oscura/correlation/multi_protocol.py +811 -0
- oscura/discovery/auto_decoder.py +117 -35
- oscura/discovery/comparison.py +191 -86
- oscura/discovery/quality_validator.py +155 -68
- oscura/discovery/signal_detector.py +196 -79
- oscura/export/__init__.py +18 -8
- oscura/export/kaitai_struct.py +513 -0
- oscura/export/scapy_layer.py +801 -0
- oscura/export/wireshark/generator.py +1 -1
- oscura/export/wireshark/templates/dissector.lua.j2 +2 -2
- oscura/export/wireshark_dissector.py +746 -0
- oscura/guidance/wizard.py +207 -111
- oscura/hardware/__init__.py +19 -0
- oscura/{acquisition → hardware/acquisition}/__init__.py +4 -4
- oscura/{acquisition → hardware/acquisition}/file.py +2 -2
- oscura/{acquisition → hardware/acquisition}/hardware.py +7 -7
- oscura/{acquisition → hardware/acquisition}/saleae.py +15 -12
- oscura/{acquisition → hardware/acquisition}/socketcan.py +1 -1
- oscura/{acquisition → hardware/acquisition}/streaming.py +2 -2
- oscura/{acquisition → hardware/acquisition}/synthetic.py +3 -3
- oscura/{acquisition → hardware/acquisition}/visa.py +33 -11
- oscura/hardware/firmware/__init__.py +29 -0
- oscura/hardware/firmware/pattern_recognition.py +874 -0
- oscura/hardware/hal_detector.py +736 -0
- oscura/hardware/security/__init__.py +37 -0
- oscura/hardware/security/side_channel_detector.py +1126 -0
- oscura/inference/__init__.py +4 -0
- oscura/inference/active_learning/observation_table.py +4 -1
- oscura/inference/alignment.py +216 -123
- oscura/inference/bayesian.py +113 -33
- oscura/inference/crc_reverse.py +101 -55
- oscura/inference/logic.py +6 -2
- oscura/inference/message_format.py +342 -183
- oscura/inference/protocol.py +95 -44
- oscura/inference/protocol_dsl.py +180 -82
- oscura/inference/signal_intelligence.py +1439 -706
- oscura/inference/spectral.py +99 -57
- oscura/inference/state_machine.py +810 -158
- oscura/inference/stream.py +270 -110
- oscura/iot/__init__.py +34 -0
- oscura/iot/coap/__init__.py +32 -0
- oscura/iot/coap/analyzer.py +668 -0
- oscura/iot/coap/options.py +212 -0
- oscura/iot/lorawan/__init__.py +21 -0
- oscura/iot/lorawan/crypto.py +206 -0
- oscura/iot/lorawan/decoder.py +801 -0
- oscura/iot/lorawan/mac_commands.py +341 -0
- oscura/iot/mqtt/__init__.py +27 -0
- oscura/iot/mqtt/analyzer.py +999 -0
- oscura/iot/mqtt/properties.py +315 -0
- oscura/iot/zigbee/__init__.py +31 -0
- oscura/iot/zigbee/analyzer.py +615 -0
- oscura/iot/zigbee/security.py +153 -0
- oscura/iot/zigbee/zcl.py +349 -0
- oscura/jupyter/display.py +125 -45
- oscura/{exploratory → jupyter/exploratory}/__init__.py +8 -8
- oscura/{exploratory → jupyter/exploratory}/error_recovery.py +298 -141
- oscura/jupyter/exploratory/fuzzy.py +746 -0
- oscura/{exploratory → jupyter/exploratory}/fuzzy_advanced.py +258 -100
- oscura/{exploratory → jupyter/exploratory}/legacy.py +464 -242
- oscura/{exploratory → jupyter/exploratory}/parse.py +167 -145
- oscura/{exploratory → jupyter/exploratory}/recovery.py +119 -87
- oscura/jupyter/exploratory/sync.py +612 -0
- oscura/{exploratory → jupyter/exploratory}/unknown.py +299 -176
- oscura/jupyter/magic.py +4 -4
- oscura/{ui → jupyter/ui}/__init__.py +2 -2
- oscura/{ui → jupyter/ui}/formatters.py +3 -3
- oscura/{ui → jupyter/ui}/progressive_display.py +153 -82
- oscura/loaders/__init__.py +183 -67
- oscura/loaders/binary.py +88 -1
- oscura/loaders/chipwhisperer.py +153 -137
- oscura/loaders/configurable.py +208 -86
- oscura/loaders/csv_loader.py +458 -215
- oscura/loaders/hdf5_loader.py +278 -119
- oscura/loaders/lazy.py +87 -54
- oscura/loaders/mmap_loader.py +1 -1
- oscura/loaders/numpy_loader.py +253 -116
- oscura/loaders/pcap.py +226 -151
- oscura/loaders/rigol.py +110 -49
- oscura/loaders/sigrok.py +201 -78
- oscura/loaders/tdms.py +81 -58
- oscura/loaders/tektronix.py +291 -174
- oscura/loaders/touchstone.py +182 -87
- oscura/loaders/tss.py +456 -0
- oscura/loaders/vcd.py +215 -117
- oscura/loaders/wav.py +155 -68
- oscura/reporting/__init__.py +9 -0
- oscura/reporting/analyze.py +352 -146
- oscura/reporting/argument_preparer.py +69 -14
- oscura/reporting/auto_report.py +97 -61
- oscura/reporting/batch.py +131 -58
- oscura/reporting/chart_selection.py +57 -45
- oscura/reporting/comparison.py +63 -17
- oscura/reporting/content/executive.py +76 -24
- oscura/reporting/core_formats/multi_format.py +11 -8
- oscura/reporting/engine.py +312 -158
- oscura/reporting/enhanced_reports.py +949 -0
- oscura/reporting/export.py +86 -43
- oscura/reporting/formatting/numbers.py +69 -42
- oscura/reporting/html.py +139 -58
- oscura/reporting/index.py +137 -65
- oscura/reporting/output.py +158 -67
- oscura/reporting/pdf.py +67 -102
- oscura/reporting/plots.py +191 -112
- oscura/reporting/sections.py +88 -47
- oscura/reporting/standards.py +104 -61
- oscura/reporting/summary_generator.py +75 -55
- oscura/reporting/tables.py +138 -54
- oscura/reporting/templates/enhanced/protocol_re.html +525 -0
- oscura/sessions/__init__.py +14 -23
- oscura/sessions/base.py +3 -3
- oscura/sessions/blackbox.py +106 -10
- oscura/sessions/generic.py +2 -2
- oscura/sessions/legacy.py +783 -0
- oscura/side_channel/__init__.py +63 -0
- oscura/side_channel/dpa.py +1025 -0
- oscura/utils/__init__.py +15 -1
- oscura/utils/bitwise.py +118 -0
- oscura/{builders → utils/builders}/__init__.py +1 -1
- oscura/{comparison → utils/comparison}/__init__.py +6 -6
- oscura/{comparison → utils/comparison}/compare.py +202 -101
- oscura/{comparison → utils/comparison}/golden.py +83 -63
- oscura/{comparison → utils/comparison}/limits.py +313 -89
- oscura/{comparison → utils/comparison}/mask.py +151 -45
- oscura/{comparison → utils/comparison}/trace_diff.py +1 -1
- oscura/{comparison → utils/comparison}/visualization.py +147 -89
- oscura/{component → utils/component}/__init__.py +3 -3
- oscura/{component → utils/component}/impedance.py +122 -58
- oscura/{component → utils/component}/reactive.py +165 -168
- oscura/{component → utils/component}/transmission_line.py +3 -3
- oscura/{filtering → utils/filtering}/__init__.py +6 -6
- oscura/{filtering → utils/filtering}/base.py +1 -1
- oscura/{filtering → utils/filtering}/convenience.py +2 -2
- oscura/{filtering → utils/filtering}/design.py +169 -93
- oscura/{filtering → utils/filtering}/filters.py +2 -2
- oscura/{filtering → utils/filtering}/introspection.py +2 -2
- oscura/utils/geometry.py +31 -0
- oscura/utils/imports.py +184 -0
- oscura/utils/lazy.py +1 -1
- oscura/{math → utils/math}/__init__.py +2 -2
- oscura/{math → utils/math}/arithmetic.py +114 -48
- oscura/{math → utils/math}/interpolation.py +139 -106
- oscura/utils/memory.py +129 -66
- oscura/utils/memory_advanced.py +92 -9
- oscura/utils/memory_extensions.py +10 -8
- oscura/{optimization → utils/optimization}/__init__.py +1 -1
- oscura/{optimization → utils/optimization}/search.py +2 -2
- oscura/utils/performance/__init__.py +58 -0
- oscura/utils/performance/caching.py +889 -0
- oscura/utils/performance/lsh_clustering.py +333 -0
- oscura/utils/performance/memory_optimizer.py +699 -0
- oscura/utils/performance/optimizations.py +675 -0
- oscura/utils/performance/parallel.py +654 -0
- oscura/utils/performance/profiling.py +661 -0
- oscura/{pipeline → utils/pipeline}/base.py +1 -1
- oscura/{pipeline → utils/pipeline}/composition.py +1 -1
- oscura/{pipeline → utils/pipeline}/parallel.py +3 -2
- oscura/{pipeline → utils/pipeline}/pipeline.py +1 -1
- oscura/{pipeline → utils/pipeline}/reverse_engineering.py +412 -221
- oscura/{search → utils/search}/__init__.py +3 -3
- oscura/{search → utils/search}/anomaly.py +188 -58
- oscura/utils/search/context.py +294 -0
- oscura/{search → utils/search}/pattern.py +138 -10
- oscura/utils/serial.py +51 -0
- oscura/utils/storage/__init__.py +61 -0
- oscura/utils/storage/database.py +1166 -0
- oscura/{streaming → utils/streaming}/chunked.py +302 -143
- oscura/{streaming → utils/streaming}/progressive.py +1 -1
- oscura/{streaming → utils/streaming}/realtime.py +3 -2
- oscura/{triggering → utils/triggering}/__init__.py +6 -6
- oscura/{triggering → utils/triggering}/base.py +6 -6
- oscura/{triggering → utils/triggering}/edge.py +2 -2
- oscura/{triggering → utils/triggering}/pattern.py +2 -2
- oscura/{triggering → utils/triggering}/pulse.py +115 -74
- oscura/{triggering → utils/triggering}/window.py +2 -2
- oscura/utils/validation.py +32 -0
- oscura/validation/__init__.py +121 -0
- oscura/{compliance → validation/compliance}/__init__.py +5 -5
- oscura/{compliance → validation/compliance}/advanced.py +5 -5
- oscura/{compliance → validation/compliance}/masks.py +1 -1
- oscura/{compliance → validation/compliance}/reporting.py +127 -53
- oscura/{compliance → validation/compliance}/testing.py +114 -52
- oscura/validation/compliance_tests.py +915 -0
- oscura/validation/fuzzer.py +990 -0
- oscura/validation/grammar_tests.py +596 -0
- oscura/validation/grammar_validator.py +904 -0
- oscura/validation/hil_testing.py +977 -0
- oscura/{quality → validation/quality}/__init__.py +4 -4
- oscura/{quality → validation/quality}/ensemble.py +251 -171
- oscura/{quality → validation/quality}/explainer.py +3 -3
- oscura/{quality → validation/quality}/scoring.py +1 -1
- oscura/{quality → validation/quality}/warnings.py +4 -4
- oscura/validation/regression_suite.py +808 -0
- oscura/validation/replay.py +788 -0
- oscura/{testing → validation/testing}/__init__.py +2 -2
- oscura/{testing → validation/testing}/synthetic.py +5 -5
- oscura/visualization/__init__.py +9 -0
- oscura/visualization/accessibility.py +1 -1
- oscura/visualization/annotations.py +64 -67
- oscura/visualization/colors.py +7 -7
- oscura/visualization/digital.py +180 -81
- oscura/visualization/eye.py +236 -85
- oscura/visualization/interactive.py +320 -143
- oscura/visualization/jitter.py +587 -247
- oscura/visualization/layout.py +169 -134
- oscura/visualization/optimization.py +103 -52
- oscura/visualization/palettes.py +1 -1
- oscura/visualization/power.py +427 -211
- oscura/visualization/power_extended.py +626 -297
- oscura/visualization/presets.py +2 -0
- oscura/visualization/protocols.py +495 -181
- oscura/visualization/render.py +79 -63
- oscura/visualization/reverse_engineering.py +171 -124
- oscura/visualization/signal_integrity.py +460 -279
- oscura/visualization/specialized.py +190 -100
- oscura/visualization/spectral.py +670 -255
- oscura/visualization/thumbnails.py +166 -137
- oscura/visualization/waveform.py +150 -63
- oscura/workflows/__init__.py +3 -0
- oscura/{batch → workflows/batch}/__init__.py +5 -5
- oscura/{batch → workflows/batch}/advanced.py +150 -75
- oscura/workflows/batch/aggregate.py +531 -0
- oscura/workflows/batch/analyze.py +236 -0
- oscura/{batch → workflows/batch}/logging.py +2 -2
- oscura/{batch → workflows/batch}/metrics.py +1 -1
- oscura/workflows/complete_re.py +1144 -0
- oscura/workflows/compliance.py +44 -54
- oscura/workflows/digital.py +197 -51
- oscura/workflows/legacy/__init__.py +12 -0
- oscura/{workflow → workflows/legacy}/dag.py +4 -1
- oscura/workflows/multi_trace.py +9 -9
- oscura/workflows/power.py +42 -62
- oscura/workflows/protocol.py +82 -49
- oscura/workflows/reverse_engineering.py +351 -150
- oscura/workflows/signal_integrity.py +157 -82
- oscura-0.7.0.dist-info/METADATA +661 -0
- oscura-0.7.0.dist-info/RECORD +591 -0
- oscura/batch/aggregate.py +0 -300
- oscura/batch/analyze.py +0 -139
- oscura/dsl/__init__.py +0 -73
- oscura/exceptions.py +0 -59
- oscura/exploratory/fuzzy.py +0 -513
- oscura/exploratory/sync.py +0 -384
- oscura/exporters/__init__.py +0 -94
- oscura/exporters/csv.py +0 -303
- oscura/exporters/exporters.py +0 -44
- oscura/exporters/hdf5.py +0 -217
- oscura/exporters/html_export.py +0 -701
- oscura/exporters/json_export.py +0 -291
- oscura/exporters/markdown_export.py +0 -367
- oscura/exporters/matlab_export.py +0 -354
- oscura/exporters/npz_export.py +0 -219
- oscura/exporters/spice_export.py +0 -210
- oscura/search/context.py +0 -149
- oscura/session/__init__.py +0 -34
- oscura/session/annotations.py +0 -289
- oscura/session/history.py +0 -313
- oscura/session/session.py +0 -520
- oscura/workflow/__init__.py +0 -13
- oscura-0.5.1.dist-info/METADATA +0 -583
- oscura-0.5.1.dist-info/RECORD +0 -481
- /oscura/core/{config.py → config/legacy.py} +0 -0
- /oscura/{extensibility → core/extensibility}/__init__.py +0 -0
- /oscura/{extensibility → core/extensibility}/registry.py +0 -0
- /oscura/{plugins → core/plugins}/isolation.py +0 -0
- /oscura/{schemas → core/schemas}/bus_configuration.json +0 -0
- /oscura/{builders → utils/builders}/signal_builder.py +0 -0
- /oscura/{optimization → utils/optimization}/parallel.py +0 -0
- /oscura/{pipeline → utils/pipeline}/__init__.py +0 -0
- /oscura/{streaming → utils/streaming}/__init__.py +0 -0
- {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/WHEEL +0 -0
- {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/entry_points.txt +0 -0
- {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/licenses/LICENSE +0 -0
oscura/exploratory/sync.py
DELETED
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
"""Fuzzy synchronization pattern search for corrupted data.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
This module provides fuzzy pattern matching for finding sync words and markers
|
|
5
|
-
in noisy or corrupted logic analyzer captures, with configurable bit error
|
|
6
|
-
tolerance using Hamming distance.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
from dataclasses import dataclass
|
|
12
|
-
from enum import Enum
|
|
13
|
-
from typing import Literal
|
|
14
|
-
|
|
15
|
-
import numpy as np
|
|
16
|
-
from numpy.typing import NDArray
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class RecoveryStrategy(Enum):
|
|
20
|
-
"""Error recovery strategies for corrupted packets.
|
|
21
|
-
|
|
22
|
-
Attributes:
|
|
23
|
-
NEXT_SYNC: Skip to next sync word when corruption detected
|
|
24
|
-
SKIP_BYTES: Skip fixed byte count and retry parsing
|
|
25
|
-
HEURISTIC: Use statistical packet length model for recovery
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
NEXT_SYNC = "next_sync"
|
|
29
|
-
SKIP_BYTES = "skip_bytes"
|
|
30
|
-
HEURISTIC = "heuristic"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@dataclass
|
|
34
|
-
class SyncMatch:
|
|
35
|
-
"""Result from fuzzy sync pattern search.
|
|
36
|
-
|
|
37
|
-
Attributes:
|
|
38
|
-
index: Starting position of match in bits or bytes
|
|
39
|
-
matched_value: The actual value that matched (may differ from pattern)
|
|
40
|
-
hamming_distance: Number of bit errors in the match
|
|
41
|
-
confidence: Match confidence (1.0 - bit_errors/pattern_length)
|
|
42
|
-
pattern_length: Length of pattern in bits
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
index: int
|
|
46
|
-
matched_value: int
|
|
47
|
-
hamming_distance: int
|
|
48
|
-
confidence: float
|
|
49
|
-
pattern_length: int
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@dataclass
|
|
53
|
-
class PacketParseResult:
|
|
54
|
-
"""Result from robust packet parsing.
|
|
55
|
-
|
|
56
|
-
Attributes:
|
|
57
|
-
packets: List of successfully parsed packet data
|
|
58
|
-
valid: List of validity flags for each packet
|
|
59
|
-
errors: List of error types ('length_corruption', 'sync_lost', None)
|
|
60
|
-
error_positions: Byte positions where errors occurred
|
|
61
|
-
recovery_count: Number of times recovery was triggered
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
packets: list[bytes]
|
|
65
|
-
valid: list[bool]
|
|
66
|
-
errors: list[str | None]
|
|
67
|
-
error_positions: list[int]
|
|
68
|
-
recovery_count: int
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def hamming_distance(a: int, b: int, pattern_bits: int) -> int:
|
|
72
|
-
"""Calculate Hamming distance between two integers.
|
|
73
|
-
|
|
74
|
-
Args:
|
|
75
|
-
a: First integer
|
|
76
|
-
b: Second integer
|
|
77
|
-
pattern_bits: Number of bits to compare (8, 16, 32, or 64)
|
|
78
|
-
|
|
79
|
-
Returns:
|
|
80
|
-
Number of differing bits
|
|
81
|
-
|
|
82
|
-
Examples:
|
|
83
|
-
>>> hamming_distance(0b10101010, 0b10101011, 8)
|
|
84
|
-
1
|
|
85
|
-
>>> hamming_distance(0xAA55, 0xAA54, 16)
|
|
86
|
-
1
|
|
87
|
-
"""
|
|
88
|
-
# XOR gives 1s where bits differ
|
|
89
|
-
diff = a ^ b
|
|
90
|
-
# Mask to pattern length
|
|
91
|
-
mask = (1 << pattern_bits) - 1
|
|
92
|
-
diff &= mask
|
|
93
|
-
# Count set bits (population count)
|
|
94
|
-
return (diff).bit_count()
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def fuzzy_sync_search(
|
|
98
|
-
data: NDArray[np.uint8],
|
|
99
|
-
pattern: int,
|
|
100
|
-
*,
|
|
101
|
-
pattern_bits: Literal[8, 16, 32, 64] = 8,
|
|
102
|
-
max_errors: int = 2,
|
|
103
|
-
min_confidence: float = 0.85,
|
|
104
|
-
) -> list[SyncMatch]:
|
|
105
|
-
"""Find sync patterns with bit error tolerance using Hamming distance.
|
|
106
|
-
|
|
107
|
-
: Searches for sync words even with bit errors,
|
|
108
|
-
essential for recovering corrupted logic analyzer captures.
|
|
109
|
-
|
|
110
|
-
Performance targets (DAQ-001):
|
|
111
|
-
- ≥10 MB/s for max_errors=2
|
|
112
|
-
- ≥5 MB/s for max_errors=4
|
|
113
|
-
- ≥1 MB/s for max_errors=8
|
|
114
|
-
|
|
115
|
-
Confidence scoring (DAQ-001):
|
|
116
|
-
- ≥0.95 (0-1 bit errors): Highly reliable
|
|
117
|
-
- 0.85-0.95 (2-4 bit errors): Reliable
|
|
118
|
-
- <0.85 (>4 bit errors): Verify manually
|
|
119
|
-
|
|
120
|
-
Args:
|
|
121
|
-
data: Input byte array to search
|
|
122
|
-
pattern: Sync pattern to find (e.g., 0xAA55F0F0 for 32-bit)
|
|
123
|
-
pattern_bits: Pattern length in bits (8, 16, 32, or 64)
|
|
124
|
-
max_errors: Maximum tolerable bit errors (0-8)
|
|
125
|
-
min_confidence: Minimum confidence threshold (0.0-1.0)
|
|
126
|
-
|
|
127
|
-
Returns:
|
|
128
|
-
List of SyncMatch objects with position, matched value, distance,
|
|
129
|
-
and confidence score
|
|
130
|
-
|
|
131
|
-
Raises:
|
|
132
|
-
ValueError: If pattern_bits not in [8, 16, 32, 64]
|
|
133
|
-
ValueError: If max_errors < 0 or > 8
|
|
134
|
-
ValueError: If min_confidence not in [0.0, 1.0]
|
|
135
|
-
|
|
136
|
-
Examples:
|
|
137
|
-
>>> data = np.array([0xAA, 0x55, 0xF0, 0xF0, 0xFF], dtype=np.uint8)
|
|
138
|
-
>>> # Find exact match
|
|
139
|
-
>>> matches = fuzzy_sync_search(data, 0xAA55, pattern_bits=16)
|
|
140
|
-
>>> print(matches[0].confidence)
|
|
141
|
-
1.0
|
|
142
|
-
|
|
143
|
-
>>> # Find with 1 bit error (0xAA54 instead of 0xAA55)
|
|
144
|
-
>>> data = np.array([0xAA, 0x54, 0x00], dtype=np.uint8)
|
|
145
|
-
>>> matches = fuzzy_sync_search(data, 0xAA55, pattern_bits=16, max_errors=2)
|
|
146
|
-
>>> print(matches[0].hamming_distance)
|
|
147
|
-
1
|
|
148
|
-
|
|
149
|
-
References:
|
|
150
|
-
DAQ-001: Fuzzy Bit Pattern Search with Hamming Distance Tolerance
|
|
151
|
-
"""
|
|
152
|
-
if pattern_bits not in (8, 16, 32, 64):
|
|
153
|
-
raise ValueError("pattern_bits must be 8, 16, 32, or 64")
|
|
154
|
-
|
|
155
|
-
if max_errors < 0 or max_errors > 8:
|
|
156
|
-
raise ValueError("max_errors must be in range [0, 8]")
|
|
157
|
-
|
|
158
|
-
if not 0.0 <= min_confidence <= 1.0:
|
|
159
|
-
raise ValueError("min_confidence must be in range [0.0, 1.0]")
|
|
160
|
-
|
|
161
|
-
pattern_bytes = pattern_bits // 8
|
|
162
|
-
if len(data) < pattern_bytes:
|
|
163
|
-
return []
|
|
164
|
-
|
|
165
|
-
matches: list[SyncMatch] = []
|
|
166
|
-
|
|
167
|
-
# Sliding window search
|
|
168
|
-
for i in range(len(data) - pattern_bytes + 1):
|
|
169
|
-
# Extract window and convert to integer
|
|
170
|
-
window = data[i : i + pattern_bytes]
|
|
171
|
-
|
|
172
|
-
# Convert bytes to integer (big-endian)
|
|
173
|
-
if pattern_bytes == 1:
|
|
174
|
-
value = int(window[0])
|
|
175
|
-
elif pattern_bytes == 2:
|
|
176
|
-
value = (int(window[0]) << 8) | int(window[1])
|
|
177
|
-
elif pattern_bytes == 4:
|
|
178
|
-
value = (
|
|
179
|
-
(int(window[0]) << 24)
|
|
180
|
-
| (int(window[1]) << 16)
|
|
181
|
-
| (int(window[2]) << 8)
|
|
182
|
-
| int(window[3])
|
|
183
|
-
)
|
|
184
|
-
else: # 8 bytes
|
|
185
|
-
value = 0
|
|
186
|
-
for j in range(8):
|
|
187
|
-
value = (value << 8) | int(window[j])
|
|
188
|
-
|
|
189
|
-
# Calculate Hamming distance
|
|
190
|
-
dist = hamming_distance(value, pattern, pattern_bits)
|
|
191
|
-
|
|
192
|
-
# Check if within error tolerance
|
|
193
|
-
if dist <= max_errors:
|
|
194
|
-
confidence = 1.0 - (dist / pattern_bits)
|
|
195
|
-
|
|
196
|
-
if confidence >= min_confidence:
|
|
197
|
-
matches.append(
|
|
198
|
-
SyncMatch(
|
|
199
|
-
index=i,
|
|
200
|
-
matched_value=value,
|
|
201
|
-
hamming_distance=dist,
|
|
202
|
-
confidence=confidence,
|
|
203
|
-
pattern_length=pattern_bits,
|
|
204
|
-
)
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
return matches
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
def parse_variable_length_packets(
|
|
211
|
-
data: NDArray[np.uint8],
|
|
212
|
-
*,
|
|
213
|
-
sync_pattern: int | None = None,
|
|
214
|
-
sync_bits: Literal[8, 16, 32, 64] = 16,
|
|
215
|
-
length_offset: int = 2,
|
|
216
|
-
length_size: int = 2,
|
|
217
|
-
min_packet_size: int = 4,
|
|
218
|
-
max_packet_size: int = 1024,
|
|
219
|
-
recovery_strategy: RecoveryStrategy = RecoveryStrategy.NEXT_SYNC,
|
|
220
|
-
skip_bytes: int = 1,
|
|
221
|
-
) -> PacketParseResult:
|
|
222
|
-
"""Parse variable-length packets with error recovery.
|
|
223
|
-
|
|
224
|
-
: Robust parsing that continues after corruption,
|
|
225
|
-
falling back to sync word search when length fields are corrupted.
|
|
226
|
-
|
|
227
|
-
Error detection (DAQ-002):
|
|
228
|
-
- Invalid if: length=0, length>max_packet_size, or length&0xFF00=0xFF00
|
|
229
|
-
- Suspicious if: length < min_expected or length > 90th_percentile×2 # noqa: RUF002
|
|
230
|
-
|
|
231
|
-
Recovery strategies (DAQ-002):
|
|
232
|
-
- next_sync: Skip to next sync word (requires sync_pattern)
|
|
233
|
-
- skip_bytes: Skip fixed byte count and retry
|
|
234
|
-
- heuristic: Use statistical packet length model
|
|
235
|
-
|
|
236
|
-
Args:
|
|
237
|
-
data: Input byte array containing packets
|
|
238
|
-
sync_pattern: Optional sync word to search for on errors
|
|
239
|
-
sync_bits: Sync pattern length in bits
|
|
240
|
-
length_offset: Byte offset to length field from start
|
|
241
|
-
length_size: Length field size in bytes (1 or 2)
|
|
242
|
-
min_packet_size: Minimum valid packet size in bytes
|
|
243
|
-
max_packet_size: Maximum valid packet size in bytes
|
|
244
|
-
recovery_strategy: Strategy to use when corruption detected
|
|
245
|
-
skip_bytes: Number of bytes to skip for SKIP_BYTES strategy
|
|
246
|
-
|
|
247
|
-
Returns:
|
|
248
|
-
PacketParseResult with parsed packets and error information
|
|
249
|
-
|
|
250
|
-
Raises:
|
|
251
|
-
ValueError: If length_size not 1 or 2
|
|
252
|
-
ValueError: If recovery_strategy is NEXT_SYNC without sync_pattern
|
|
253
|
-
|
|
254
|
-
Examples:
|
|
255
|
-
>>> # Simple TLV parsing with sync word
|
|
256
|
-
>>> data = np.array([0xAA, 0x55, 0x00, 0x04, 0x01, 0x02], dtype=np.uint8)
|
|
257
|
-
>>> result = parse_variable_length_packets(
|
|
258
|
-
... data, sync_pattern=0xAA55, length_offset=2
|
|
259
|
-
... )
|
|
260
|
-
>>> len(result.packets)
|
|
261
|
-
1
|
|
262
|
-
|
|
263
|
-
References:
|
|
264
|
-
DAQ-002: Robust Variable-Length Packet Parsing with Error Recovery
|
|
265
|
-
"""
|
|
266
|
-
if length_size not in (1, 2):
|
|
267
|
-
raise ValueError("length_size must be 1 or 2")
|
|
268
|
-
|
|
269
|
-
if recovery_strategy == RecoveryStrategy.NEXT_SYNC and sync_pattern is None:
|
|
270
|
-
raise ValueError("NEXT_SYNC strategy requires sync_pattern")
|
|
271
|
-
|
|
272
|
-
packets: list[bytes] = []
|
|
273
|
-
valid: list[bool] = []
|
|
274
|
-
errors: list[str | None] = []
|
|
275
|
-
error_positions: list[int] = []
|
|
276
|
-
recovery_count = 0
|
|
277
|
-
|
|
278
|
-
# Track packet lengths for heuristic recovery
|
|
279
|
-
packet_lengths: list[int] = []
|
|
280
|
-
|
|
281
|
-
pos = 0
|
|
282
|
-
while pos < len(data):
|
|
283
|
-
# Try to parse packet at current position
|
|
284
|
-
|
|
285
|
-
# Check if we have enough data for header
|
|
286
|
-
if pos + length_offset + length_size > len(data):
|
|
287
|
-
break
|
|
288
|
-
|
|
289
|
-
# Extract length field
|
|
290
|
-
length_pos = pos + length_offset
|
|
291
|
-
if length_size == 1:
|
|
292
|
-
pkt_length = int(data[length_pos])
|
|
293
|
-
else: # 2 bytes
|
|
294
|
-
pkt_length = (int(data[length_pos]) << 8) | int(data[length_pos + 1])
|
|
295
|
-
|
|
296
|
-
# Validate length field
|
|
297
|
-
is_valid_length = True
|
|
298
|
-
error_type = None
|
|
299
|
-
|
|
300
|
-
# Check for obviously corrupted lengths
|
|
301
|
-
if (
|
|
302
|
-
pkt_length == 0
|
|
303
|
-
or pkt_length > max_packet_size
|
|
304
|
-
or (length_size == 2 and (pkt_length & 0xFF00) == 0xFF00)
|
|
305
|
-
or pkt_length < min_packet_size
|
|
306
|
-
):
|
|
307
|
-
is_valid_length = False
|
|
308
|
-
error_type = "length_corruption"
|
|
309
|
-
|
|
310
|
-
# Check suspiciously large length (heuristic)
|
|
311
|
-
if is_valid_length and len(packet_lengths) >= 10:
|
|
312
|
-
p90 = np.percentile(packet_lengths, 90)
|
|
313
|
-
if pkt_length > p90 * 2:
|
|
314
|
-
is_valid_length = False
|
|
315
|
-
error_type = "length_corruption"
|
|
316
|
-
|
|
317
|
-
if is_valid_length:
|
|
318
|
-
# Length looks good, try to extract packet
|
|
319
|
-
packet_end = pos + pkt_length
|
|
320
|
-
|
|
321
|
-
if packet_end <= len(data):
|
|
322
|
-
# Successfully extract packet
|
|
323
|
-
packet_data = bytes(data[pos:packet_end])
|
|
324
|
-
packets.append(packet_data)
|
|
325
|
-
valid.append(True)
|
|
326
|
-
errors.append(None)
|
|
327
|
-
packet_lengths.append(pkt_length)
|
|
328
|
-
pos = packet_end
|
|
329
|
-
else:
|
|
330
|
-
# Packet extends beyond data
|
|
331
|
-
errors.append("truncated")
|
|
332
|
-
error_positions.append(pos)
|
|
333
|
-
break
|
|
334
|
-
else:
|
|
335
|
-
# Length field corrupted - apply recovery
|
|
336
|
-
recovery_count += 1
|
|
337
|
-
error_positions.append(pos)
|
|
338
|
-
|
|
339
|
-
if recovery_strategy == RecoveryStrategy.NEXT_SYNC:
|
|
340
|
-
# Search for next sync word
|
|
341
|
-
assert sync_pattern is not None # Validated at function start
|
|
342
|
-
search_start = pos + 1
|
|
343
|
-
search_data = data[search_start:]
|
|
344
|
-
|
|
345
|
-
if len(search_data) >= sync_bits // 8:
|
|
346
|
-
matches = fuzzy_sync_search(
|
|
347
|
-
search_data,
|
|
348
|
-
sync_pattern,
|
|
349
|
-
pattern_bits=sync_bits,
|
|
350
|
-
max_errors=0, # type: ignore[arg-type]
|
|
351
|
-
)
|
|
352
|
-
|
|
353
|
-
if matches:
|
|
354
|
-
# Found sync, jump to it
|
|
355
|
-
pos = search_start + matches[0].index
|
|
356
|
-
errors.append("sync_lost")
|
|
357
|
-
else:
|
|
358
|
-
# No more syncs found
|
|
359
|
-
break
|
|
360
|
-
else:
|
|
361
|
-
break
|
|
362
|
-
|
|
363
|
-
elif recovery_strategy == RecoveryStrategy.SKIP_BYTES:
|
|
364
|
-
# Skip fixed bytes and retry
|
|
365
|
-
pos += skip_bytes
|
|
366
|
-
errors.append(error_type)
|
|
367
|
-
|
|
368
|
-
elif recovery_strategy == RecoveryStrategy.HEURISTIC:
|
|
369
|
-
# Use median packet length as guess
|
|
370
|
-
if packet_lengths:
|
|
371
|
-
guess_length = int(np.median(packet_lengths))
|
|
372
|
-
pos += guess_length
|
|
373
|
-
else:
|
|
374
|
-
# No history, skip minimal amount
|
|
375
|
-
pos += min_packet_size
|
|
376
|
-
errors.append(error_type)
|
|
377
|
-
|
|
378
|
-
return PacketParseResult(
|
|
379
|
-
packets=packets,
|
|
380
|
-
valid=valid,
|
|
381
|
-
errors=errors,
|
|
382
|
-
error_positions=error_positions,
|
|
383
|
-
recovery_count=recovery_count,
|
|
384
|
-
)
|
oscura/exporters/__init__.py
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"""Data export module for Oscura.
|
|
2
|
-
|
|
3
|
-
Provides export functionality to various file formats including CSV, HDF5,
|
|
4
|
-
JSON, MATLAB, Markdown, HTML, NumPy NPZ, and SPICE PWL.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Example:
|
|
8
|
-
>>> from oscura.exporters import export_csv, export_hdf5, export_json, export_mat
|
|
9
|
-
>>> export_csv(trace, "waveform.csv")
|
|
10
|
-
>>> export_hdf5(trace, "waveform.h5")
|
|
11
|
-
>>> export_json(trace, "waveform.json")
|
|
12
|
-
>>> export_mat(trace, "waveform.mat")
|
|
13
|
-
>>> export_markdown(data, "report.md")
|
|
14
|
-
>>> export_html(data, "report.html")
|
|
15
|
-
>>> export_npz(trace, "waveform.npz")
|
|
16
|
-
>>> export_pwl(trace, "stimulus.pwl")
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
# Import exporters module as namespace for DSL compatibility
|
|
20
|
-
from oscura.exporters import exporters
|
|
21
|
-
from oscura.exporters.csv import (
|
|
22
|
-
export_csv,
|
|
23
|
-
export_multi_trace_csv,
|
|
24
|
-
)
|
|
25
|
-
from oscura.exporters.hdf5 import (
|
|
26
|
-
append_trace,
|
|
27
|
-
export_hdf5,
|
|
28
|
-
export_measurement_results,
|
|
29
|
-
)
|
|
30
|
-
from oscura.exporters.html_export import (
|
|
31
|
-
export_html,
|
|
32
|
-
generate_html_report,
|
|
33
|
-
)
|
|
34
|
-
from oscura.exporters.json_export import (
|
|
35
|
-
OscuraJSONEncoder,
|
|
36
|
-
export_json,
|
|
37
|
-
export_measurements,
|
|
38
|
-
export_protocol_decode,
|
|
39
|
-
load_json,
|
|
40
|
-
)
|
|
41
|
-
from oscura.exporters.markdown_export import (
|
|
42
|
-
export_markdown,
|
|
43
|
-
generate_markdown_report,
|
|
44
|
-
)
|
|
45
|
-
from oscura.exporters.matlab_export import (
|
|
46
|
-
export_mat,
|
|
47
|
-
export_multi_trace_mat,
|
|
48
|
-
)
|
|
49
|
-
from oscura.exporters.npz_export import (
|
|
50
|
-
export_npz,
|
|
51
|
-
load_npz,
|
|
52
|
-
)
|
|
53
|
-
from oscura.exporters.spice_export import (
|
|
54
|
-
export_pwl,
|
|
55
|
-
export_pwl_multi,
|
|
56
|
-
generate_spice_source,
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
__all__ = [
|
|
60
|
-
"OscuraJSONEncoder",
|
|
61
|
-
"append_trace",
|
|
62
|
-
# CSV export (EXP-001)
|
|
63
|
-
"export_csv",
|
|
64
|
-
# HDF5 export (EXP-002)
|
|
65
|
-
"export_hdf5",
|
|
66
|
-
# HTML export (EXP-007)
|
|
67
|
-
"export_html",
|
|
68
|
-
# JSON export (EXP-003)
|
|
69
|
-
"export_json",
|
|
70
|
-
# Markdown export (EXP-006)
|
|
71
|
-
"export_markdown",
|
|
72
|
-
# MATLAB export (EXP-008)
|
|
73
|
-
"export_mat",
|
|
74
|
-
"export_measurement_results",
|
|
75
|
-
"export_measurements",
|
|
76
|
-
"export_multi_trace_csv",
|
|
77
|
-
"export_multi_trace_mat",
|
|
78
|
-
# NPZ export (EXP-004)
|
|
79
|
-
"export_npz",
|
|
80
|
-
"export_protocol_decode",
|
|
81
|
-
# SPICE PWL export (EXP-005)
|
|
82
|
-
"export_pwl",
|
|
83
|
-
"export_pwl_multi",
|
|
84
|
-
"exporters",
|
|
85
|
-
# HTML report generation
|
|
86
|
-
"generate_html_report",
|
|
87
|
-
# Markdown report generation
|
|
88
|
-
"generate_markdown_report",
|
|
89
|
-
# SPICE source generation
|
|
90
|
-
"generate_spice_source",
|
|
91
|
-
"load_json",
|
|
92
|
-
# NPZ loading
|
|
93
|
-
"load_npz",
|
|
94
|
-
]
|