oscura 0.5.0__py3-none-any.whl → 0.6.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/__init__.py +0 -48
- oscura/analyzers/digital/edges.py +325 -65
- oscura/analyzers/digital/extraction.py +0 -195
- 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/__init__.py +1 -22
- 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 +2763 -0
- 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/core/schemas/bus_configuration.json +322 -0
- oscura/core/schemas/device_mapping.json +182 -0
- oscura/core/schemas/packet_format.json +418 -0
- oscura/core/schemas/protocol_definition.json +363 -0
- 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 -20
- oscura/export/kaitai_struct.py +513 -0
- oscura/export/scapy_layer.py +801 -0
- oscura/export/wireshark/README.md +15 -15
- 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/README.md +7 -7
- 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 +171 -63
- 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/vcd.py +215 -117
- oscura/loaders/wav.py +155 -68
- oscura/reporting/__init__.py +9 -7
- 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/reporting/templates/index.md +13 -13
- 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/autodetect.py +1 -5
- 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 +11 -3
- 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.6.0.dist-info/METADATA +643 -0
- oscura-0.6.0.dist-info/RECORD +590 -0
- oscura/analyzers/digital/ic_database.py +0 -498
- oscura/analyzers/digital/timing_paths.py +0 -339
- oscura/analyzers/digital/vintage.py +0 -377
- oscura/analyzers/digital/vintage_result.py +0 -148
- oscura/analyzers/protocols/parallel_bus.py +0 -449
- 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/export/wavedrom.py +0 -430
- 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 -338
- 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/exporters/vintage_logic_csv.py +0 -247
- oscura/reporting/vintage_logic_report.py +0 -523
- 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/visualization/digital_advanced.py +0 -718
- oscura/visualization/figure_manager.py +0 -156
- oscura/workflow/__init__.py +0 -13
- oscura-0.5.0.dist-info/METADATA +0 -407
- oscura-0.5.0.dist-info/RECORD +0 -486
- /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/{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.0.dist-info → oscura-0.6.0.dist-info}/WHEEL +0 -0
- {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/entry_points.txt +0 -0
- {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/licenses/LICENSE +0 -0
oscura/export/wavedrom.py
DELETED
|
@@ -1,430 +0,0 @@
|
|
|
1
|
-
"""WaveDrom timing diagram generation.
|
|
2
|
-
|
|
3
|
-
Creates WaveDrom JSON format timing diagrams from digital signals.
|
|
4
|
-
WaveDrom format can be rendered as SVG/PNG using wavedrom-cli or online tools.
|
|
5
|
-
|
|
6
|
-
Example:
|
|
7
|
-
>>> from oscura.export.wavedrom import export_wavedrom, WaveDromBuilder
|
|
8
|
-
>>> builder = WaveDromBuilder()
|
|
9
|
-
>>> builder.add_clock("CLK", period=100e-9)
|
|
10
|
-
>>> builder.add_signal("DATA", edges=[10e-9, 50e-9, 150e-9])
|
|
11
|
-
>>> builder.add_arrow(10e-9, 40e-9, "t_su = 30ns")
|
|
12
|
-
>>> json_output = builder.to_json()
|
|
13
|
-
>>> export_wavedrom(json_output, "timing_diagram.json")
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
from __future__ import annotations
|
|
17
|
-
|
|
18
|
-
import json
|
|
19
|
-
from dataclasses import dataclass
|
|
20
|
-
from pathlib import Path
|
|
21
|
-
from typing import TYPE_CHECKING, Any, Literal
|
|
22
|
-
|
|
23
|
-
import numpy as np
|
|
24
|
-
|
|
25
|
-
if TYPE_CHECKING:
|
|
26
|
-
from oscura.core.types import DigitalTrace, WaveformTrace
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@dataclass
|
|
30
|
-
class WaveDromSignal:
|
|
31
|
-
"""A WaveDrom signal definition.
|
|
32
|
-
|
|
33
|
-
Attributes:
|
|
34
|
-
name: Signal name.
|
|
35
|
-
wave: Wave string (WaveDrom format).
|
|
36
|
-
data: Optional data labels.
|
|
37
|
-
node: Optional node markers for arrows.
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
name: str
|
|
41
|
-
wave: str
|
|
42
|
-
data: list[str] | None = None
|
|
43
|
-
node: str | None = None
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@dataclass
|
|
47
|
-
class WaveDromEdge:
|
|
48
|
-
"""A WaveDrom edge/arrow annotation.
|
|
49
|
-
|
|
50
|
-
Attributes:
|
|
51
|
-
from_node: Source node name.
|
|
52
|
-
to_node: Destination node name.
|
|
53
|
-
label: Arrow label text.
|
|
54
|
-
style: Arrow style.
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
from_node: str
|
|
58
|
-
to_node: str
|
|
59
|
-
label: str
|
|
60
|
-
style: str = ""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class WaveDromBuilder:
|
|
64
|
-
"""Builder for WaveDrom timing diagrams.
|
|
65
|
-
|
|
66
|
-
Example:
|
|
67
|
-
>>> builder = WaveDromBuilder(title="74LS74 Setup Time")
|
|
68
|
-
>>> builder.add_clock("CLK", period=100e-9, start_time=0)
|
|
69
|
-
>>> builder.add_signal("D", edges=[10e-9, 50e-9])
|
|
70
|
-
>>> builder.add_arrow(10e-9, 40e-9, "t_su = 30ns")
|
|
71
|
-
>>> json_str = builder.to_json()
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
def __init__(
|
|
75
|
-
self,
|
|
76
|
-
*,
|
|
77
|
-
title: str | None = None,
|
|
78
|
-
time_scale: float = 1e-9, # Default to nanoseconds
|
|
79
|
-
):
|
|
80
|
-
"""Initialize WaveDrom builder.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
title: Optional diagram title.
|
|
84
|
-
time_scale: Time scale for signal conversion (default 1ns).
|
|
85
|
-
"""
|
|
86
|
-
self.title = title
|
|
87
|
-
self.time_scale = time_scale
|
|
88
|
-
self.signals: list[WaveDromSignal] = []
|
|
89
|
-
self.edges: list[WaveDromEdge] = []
|
|
90
|
-
self.config: dict[str, Any] = {"hscale": 2, "skin": "narrow"}
|
|
91
|
-
self._time_offset = 0.0
|
|
92
|
-
self._time_end = 0.0
|
|
93
|
-
|
|
94
|
-
def add_clock(
|
|
95
|
-
self,
|
|
96
|
-
name: str,
|
|
97
|
-
*,
|
|
98
|
-
period: float,
|
|
99
|
-
start_time: float = 0.0,
|
|
100
|
-
duty_cycle: float = 0.5,
|
|
101
|
-
initial_state: Literal["high", "low"] = "low",
|
|
102
|
-
duration: float | None = None,
|
|
103
|
-
) -> None:
|
|
104
|
-
"""Add a clock signal.
|
|
105
|
-
|
|
106
|
-
Args:
|
|
107
|
-
name: Signal name.
|
|
108
|
-
period: Clock period in seconds.
|
|
109
|
-
start_time: Start time in seconds.
|
|
110
|
-
duty_cycle: Duty cycle (0.0-1.0).
|
|
111
|
-
initial_state: Initial clock state.
|
|
112
|
-
duration: Optional duration (defaults to auto-calculated).
|
|
113
|
-
"""
|
|
114
|
-
if duration is None:
|
|
115
|
-
duration = max(self._time_end - start_time, period * 10)
|
|
116
|
-
|
|
117
|
-
# Convert to time steps
|
|
118
|
-
time_steps = int((start_time - self._time_offset) / self.time_scale)
|
|
119
|
-
num_periods = int(duration / period)
|
|
120
|
-
|
|
121
|
-
# Build wave string
|
|
122
|
-
wave = "." * time_steps # Leading dots
|
|
123
|
-
|
|
124
|
-
if initial_state == "low":
|
|
125
|
-
wave += "p" * num_periods # pulsing clock
|
|
126
|
-
else:
|
|
127
|
-
wave += "n" * num_periods # inverted pulsing clock
|
|
128
|
-
|
|
129
|
-
self.signals.append(WaveDromSignal(name=name, wave=wave))
|
|
130
|
-
self._time_end = max(self._time_end, start_time + duration)
|
|
131
|
-
|
|
132
|
-
def add_signal(
|
|
133
|
-
self,
|
|
134
|
-
name: str,
|
|
135
|
-
*,
|
|
136
|
-
edges: list[float] | None = None,
|
|
137
|
-
wave_string: str | None = None,
|
|
138
|
-
data: list[str] | None = None,
|
|
139
|
-
nodes: str | None = None,
|
|
140
|
-
) -> None:
|
|
141
|
-
"""Add a digital signal.
|
|
142
|
-
|
|
143
|
-
Args:
|
|
144
|
-
name: Signal name.
|
|
145
|
-
edges: List of edge timestamps (rising/falling alternating).
|
|
146
|
-
wave_string: Direct WaveDrom wave string (overrides edges).
|
|
147
|
-
data: Optional data labels.
|
|
148
|
-
nodes: Optional node markers (e.g., "A.B.C").
|
|
149
|
-
"""
|
|
150
|
-
if wave_string is not None:
|
|
151
|
-
# Use direct wave string
|
|
152
|
-
self.signals.append(WaveDromSignal(name=name, wave=wave_string, data=data, node=nodes))
|
|
153
|
-
return
|
|
154
|
-
|
|
155
|
-
if edges is None:
|
|
156
|
-
raise ValueError("Must provide either edges or wave_string")
|
|
157
|
-
|
|
158
|
-
# Convert edges to wave string
|
|
159
|
-
wave = self._edges_to_wave(edges)
|
|
160
|
-
self.signals.append(WaveDromSignal(name=name, wave=wave, data=data, node=nodes))
|
|
161
|
-
|
|
162
|
-
def add_data_bus(
|
|
163
|
-
self,
|
|
164
|
-
name: str,
|
|
165
|
-
*,
|
|
166
|
-
transitions: list[tuple[float, str]],
|
|
167
|
-
initial_value: str = "x",
|
|
168
|
-
) -> None:
|
|
169
|
-
"""Add a data bus with labeled values.
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
name: Bus name.
|
|
173
|
-
transitions: List of (timestamp, value) tuples.
|
|
174
|
-
initial_value: Initial bus value.
|
|
175
|
-
"""
|
|
176
|
-
if not transitions:
|
|
177
|
-
raise ValueError("Must provide at least one transition")
|
|
178
|
-
|
|
179
|
-
# Sort by timestamp
|
|
180
|
-
transitions_sorted = sorted(transitions, key=lambda x: x[0])
|
|
181
|
-
|
|
182
|
-
# Build wave string and data labels
|
|
183
|
-
wave = ""
|
|
184
|
-
data: list[str] = []
|
|
185
|
-
current_time = self._time_offset
|
|
186
|
-
|
|
187
|
-
for timestamp, value in transitions_sorted:
|
|
188
|
-
# Add stable periods
|
|
189
|
-
steps = int((timestamp - current_time) / self.time_scale)
|
|
190
|
-
if steps > 0:
|
|
191
|
-
wave += "." * (steps - 1)
|
|
192
|
-
|
|
193
|
-
# Add transition
|
|
194
|
-
wave += "="
|
|
195
|
-
data.append(value)
|
|
196
|
-
current_time = timestamp
|
|
197
|
-
|
|
198
|
-
self.signals.append(WaveDromSignal(name=name, wave=wave, data=data))
|
|
199
|
-
|
|
200
|
-
def add_arrow(
|
|
201
|
-
self,
|
|
202
|
-
from_time: float,
|
|
203
|
-
to_time: float,
|
|
204
|
-
label: str,
|
|
205
|
-
*,
|
|
206
|
-
from_signal_idx: int = 0,
|
|
207
|
-
to_signal_idx: int = 0,
|
|
208
|
-
) -> None:
|
|
209
|
-
"""Add an arrow annotation between two time points.
|
|
210
|
-
|
|
211
|
-
Args:
|
|
212
|
-
from_time: Start time in seconds.
|
|
213
|
-
to_time: End time in seconds.
|
|
214
|
-
label: Arrow label text.
|
|
215
|
-
from_signal_idx: Source signal index.
|
|
216
|
-
to_signal_idx: Destination signal index.
|
|
217
|
-
"""
|
|
218
|
-
# Create node markers
|
|
219
|
-
from_node = f"A{len(self.edges)}"
|
|
220
|
-
to_node = f"B{len(self.edges)}"
|
|
221
|
-
|
|
222
|
-
# Add nodes to signals (simplified - would need to track positions)
|
|
223
|
-
self.edges.append(WaveDromEdge(from_node=from_node, to_node=to_node, label=label))
|
|
224
|
-
|
|
225
|
-
def add_group(self, name: str, signals: list[WaveDromSignal]) -> None:
|
|
226
|
-
"""Add a group of signals.
|
|
227
|
-
|
|
228
|
-
Args:
|
|
229
|
-
name: Group name.
|
|
230
|
-
signals: List of signals in group.
|
|
231
|
-
"""
|
|
232
|
-
# WaveDrom groups are represented as nested lists
|
|
233
|
-
# This is a simplified implementation
|
|
234
|
-
|
|
235
|
-
def _edges_to_wave(self, edges: list[float]) -> str:
|
|
236
|
-
"""Convert edge timestamps to WaveDrom wave string.
|
|
237
|
-
|
|
238
|
-
Args:
|
|
239
|
-
edges: List of edge timestamps.
|
|
240
|
-
|
|
241
|
-
Returns:
|
|
242
|
-
WaveDrom wave string.
|
|
243
|
-
"""
|
|
244
|
-
if not edges:
|
|
245
|
-
return "0"
|
|
246
|
-
|
|
247
|
-
wave = ""
|
|
248
|
-
current_time = self._time_offset
|
|
249
|
-
state = 0 # Start low
|
|
250
|
-
|
|
251
|
-
for edge_time in sorted(edges):
|
|
252
|
-
# Calculate steps to this edge
|
|
253
|
-
steps = int((edge_time - current_time) / self.time_scale)
|
|
254
|
-
|
|
255
|
-
# Add stable period
|
|
256
|
-
if steps > 0:
|
|
257
|
-
wave += "." * (steps - 1)
|
|
258
|
-
|
|
259
|
-
# Add transition
|
|
260
|
-
if state == 0:
|
|
261
|
-
wave += "1" # Rising edge
|
|
262
|
-
state = 1
|
|
263
|
-
else:
|
|
264
|
-
wave += "0" # Falling edge
|
|
265
|
-
state = 0
|
|
266
|
-
|
|
267
|
-
current_time = edge_time
|
|
268
|
-
|
|
269
|
-
return wave if wave else "0"
|
|
270
|
-
|
|
271
|
-
def to_dict(self) -> dict[str, Any]:
|
|
272
|
-
"""Export to WaveDrom dictionary.
|
|
273
|
-
|
|
274
|
-
Returns:
|
|
275
|
-
Dictionary in WaveDrom JSON format.
|
|
276
|
-
"""
|
|
277
|
-
result: dict[str, Any] = {}
|
|
278
|
-
|
|
279
|
-
if self.title:
|
|
280
|
-
result["head"] = {"text": self.title}
|
|
281
|
-
|
|
282
|
-
# Build signal list
|
|
283
|
-
signal_list: list[dict[str, Any]] = []
|
|
284
|
-
for sig in self.signals:
|
|
285
|
-
sig_dict: dict[str, Any] = {"name": sig.name, "wave": sig.wave}
|
|
286
|
-
if sig.data:
|
|
287
|
-
sig_dict["data"] = sig.data
|
|
288
|
-
if sig.node:
|
|
289
|
-
sig_dict["node"] = sig.node
|
|
290
|
-
signal_list.append(sig_dict)
|
|
291
|
-
|
|
292
|
-
result["signal"] = signal_list
|
|
293
|
-
|
|
294
|
-
# Add edges if any
|
|
295
|
-
if self.edges:
|
|
296
|
-
edge_list = [f"{e.from_node}{e.style}>{e.to_node} {e.label}" for e in self.edges]
|
|
297
|
-
result["edge"] = edge_list
|
|
298
|
-
|
|
299
|
-
# Add configuration
|
|
300
|
-
if self.config:
|
|
301
|
-
result["config"] = self.config
|
|
302
|
-
|
|
303
|
-
return result
|
|
304
|
-
|
|
305
|
-
def to_json(self, *, indent: int = 2) -> str:
|
|
306
|
-
"""Export to WaveDrom JSON string.
|
|
307
|
-
|
|
308
|
-
Args:
|
|
309
|
-
indent: JSON indentation level.
|
|
310
|
-
|
|
311
|
-
Returns:
|
|
312
|
-
JSON string.
|
|
313
|
-
"""
|
|
314
|
-
return json.dumps(self.to_dict(), indent=indent)
|
|
315
|
-
|
|
316
|
-
def save(self, filepath: str | Path) -> None:
|
|
317
|
-
"""Save to file.
|
|
318
|
-
|
|
319
|
-
Args:
|
|
320
|
-
filepath: Output file path.
|
|
321
|
-
"""
|
|
322
|
-
filepath = Path(filepath)
|
|
323
|
-
with filepath.open("w") as f:
|
|
324
|
-
f.write(self.to_json())
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
def from_digital_trace(
|
|
328
|
-
trace: DigitalTrace,
|
|
329
|
-
*,
|
|
330
|
-
name: str = "signal",
|
|
331
|
-
start_time: float = 0.0,
|
|
332
|
-
duration: float | None = None,
|
|
333
|
-
) -> WaveDromSignal:
|
|
334
|
-
"""Create WaveDrom signal from DigitalTrace.
|
|
335
|
-
|
|
336
|
-
Args:
|
|
337
|
-
trace: Input digital trace.
|
|
338
|
-
name: Signal name.
|
|
339
|
-
start_time: Start time offset.
|
|
340
|
-
duration: Optional duration limit.
|
|
341
|
-
|
|
342
|
-
Returns:
|
|
343
|
-
WaveDromSignal object.
|
|
344
|
-
"""
|
|
345
|
-
# Extract edges from digital trace
|
|
346
|
-
data = trace.data
|
|
347
|
-
transitions = np.diff(data.astype(np.int8))
|
|
348
|
-
|
|
349
|
-
edges: list[float] = []
|
|
350
|
-
time_base = trace.metadata.time_base
|
|
351
|
-
|
|
352
|
-
for i, trans in enumerate(transitions):
|
|
353
|
-
if trans != 0:
|
|
354
|
-
edges.append((i + 1) * time_base + start_time)
|
|
355
|
-
|
|
356
|
-
# Limit duration if specified
|
|
357
|
-
if duration is not None:
|
|
358
|
-
edges = [e for e in edges if e < start_time + duration]
|
|
359
|
-
|
|
360
|
-
# Build wave string
|
|
361
|
-
builder = WaveDromBuilder(time_scale=time_base)
|
|
362
|
-
builder.add_signal(name, edges=edges)
|
|
363
|
-
|
|
364
|
-
return builder.signals[0]
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
def export_wavedrom(
|
|
368
|
-
signals: dict[str, WaveformTrace | DigitalTrace],
|
|
369
|
-
filepath: str | Path,
|
|
370
|
-
*,
|
|
371
|
-
title: str | None = None,
|
|
372
|
-
time_scale: float = 1e-9,
|
|
373
|
-
annotations: list[tuple[float, float, str]] | None = None,
|
|
374
|
-
) -> None:
|
|
375
|
-
"""Export signals to WaveDrom JSON file.
|
|
376
|
-
|
|
377
|
-
Args:
|
|
378
|
-
signals: Dictionary mapping signal names to traces.
|
|
379
|
-
filepath: Output file path.
|
|
380
|
-
title: Optional diagram title.
|
|
381
|
-
time_scale: Time scale for conversion (default 1ns).
|
|
382
|
-
annotations: Optional list of (from_time, to_time, label) tuples.
|
|
383
|
-
|
|
384
|
-
Example:
|
|
385
|
-
>>> signals = {
|
|
386
|
-
... "CLK": clock_trace,
|
|
387
|
-
... "DATA": data_trace,
|
|
388
|
-
... "CS": cs_trace,
|
|
389
|
-
... }
|
|
390
|
-
>>> export_wavedrom(signals, "timing.json", title="SPI Transaction")
|
|
391
|
-
"""
|
|
392
|
-
builder = WaveDromBuilder(title=title, time_scale=time_scale)
|
|
393
|
-
|
|
394
|
-
# Add signals
|
|
395
|
-
for name, trace in signals.items():
|
|
396
|
-
# Detect if clock-like
|
|
397
|
-
from oscura.analyzers.waveform.measurements import frequency
|
|
398
|
-
from oscura.core.types import WaveformTrace
|
|
399
|
-
|
|
400
|
-
# frequency() only works with WaveformTrace, skip for DigitalTrace
|
|
401
|
-
if isinstance(trace, WaveformTrace):
|
|
402
|
-
freq = frequency(trace)
|
|
403
|
-
else:
|
|
404
|
-
freq = np.nan
|
|
405
|
-
if not np.isnan(freq) and freq > 0:
|
|
406
|
-
# Looks like a clock
|
|
407
|
-
period = float(1.0 / freq)
|
|
408
|
-
builder.add_clock(name, period=period)
|
|
409
|
-
else:
|
|
410
|
-
# Regular signal - extract edges
|
|
411
|
-
from oscura.analyzers.digital import detect_edges
|
|
412
|
-
|
|
413
|
-
edges = detect_edges(trace)
|
|
414
|
-
builder.add_signal(name, edges=list(edges))
|
|
415
|
-
|
|
416
|
-
# Add annotations
|
|
417
|
-
if annotations:
|
|
418
|
-
for from_t, to_t, label in annotations:
|
|
419
|
-
builder.add_arrow(from_t, to_t, label)
|
|
420
|
-
|
|
421
|
-
builder.save(filepath)
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
__all__ = [
|
|
425
|
-
"WaveDromBuilder",
|
|
426
|
-
"WaveDromEdge",
|
|
427
|
-
"WaveDromSignal",
|
|
428
|
-
"export_wavedrom",
|
|
429
|
-
"from_digital_trace",
|
|
430
|
-
]
|
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
|
-
]
|