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.
Files changed (513) hide show
  1. oscura/__init__.py +169 -167
  2. oscura/analyzers/__init__.py +3 -0
  3. oscura/analyzers/classification.py +659 -0
  4. oscura/analyzers/digital/__init__.py +0 -48
  5. oscura/analyzers/digital/edges.py +325 -65
  6. oscura/analyzers/digital/extraction.py +0 -195
  7. oscura/analyzers/digital/quality.py +293 -166
  8. oscura/analyzers/digital/timing.py +260 -115
  9. oscura/analyzers/digital/timing_numba.py +334 -0
  10. oscura/analyzers/entropy.py +605 -0
  11. oscura/analyzers/eye/diagram.py +176 -109
  12. oscura/analyzers/eye/metrics.py +5 -5
  13. oscura/analyzers/jitter/__init__.py +6 -4
  14. oscura/analyzers/jitter/ber.py +52 -52
  15. oscura/analyzers/jitter/classification.py +156 -0
  16. oscura/analyzers/jitter/decomposition.py +163 -113
  17. oscura/analyzers/jitter/spectrum.py +80 -64
  18. oscura/analyzers/ml/__init__.py +39 -0
  19. oscura/analyzers/ml/features.py +600 -0
  20. oscura/analyzers/ml/signal_classifier.py +604 -0
  21. oscura/analyzers/packet/daq.py +246 -158
  22. oscura/analyzers/packet/parser.py +12 -1
  23. oscura/analyzers/packet/payload.py +50 -2110
  24. oscura/analyzers/packet/payload_analysis.py +361 -181
  25. oscura/analyzers/packet/payload_patterns.py +133 -70
  26. oscura/analyzers/packet/stream.py +84 -23
  27. oscura/analyzers/patterns/__init__.py +26 -5
  28. oscura/analyzers/patterns/anomaly_detection.py +908 -0
  29. oscura/analyzers/patterns/clustering.py +169 -108
  30. oscura/analyzers/patterns/clustering_optimized.py +227 -0
  31. oscura/analyzers/patterns/discovery.py +1 -1
  32. oscura/analyzers/patterns/matching.py +581 -197
  33. oscura/analyzers/patterns/pattern_mining.py +778 -0
  34. oscura/analyzers/patterns/periodic.py +121 -38
  35. oscura/analyzers/patterns/sequences.py +175 -78
  36. oscura/analyzers/power/conduction.py +1 -1
  37. oscura/analyzers/power/soa.py +6 -6
  38. oscura/analyzers/power/switching.py +250 -110
  39. oscura/analyzers/protocol/__init__.py +17 -1
  40. oscura/analyzers/protocols/__init__.py +1 -22
  41. oscura/analyzers/protocols/base.py +6 -6
  42. oscura/analyzers/protocols/ble/__init__.py +38 -0
  43. oscura/analyzers/protocols/ble/analyzer.py +809 -0
  44. oscura/analyzers/protocols/ble/uuids.py +288 -0
  45. oscura/analyzers/protocols/can.py +257 -127
  46. oscura/analyzers/protocols/can_fd.py +107 -80
  47. oscura/analyzers/protocols/flexray.py +139 -80
  48. oscura/analyzers/protocols/hdlc.py +93 -58
  49. oscura/analyzers/protocols/i2c.py +247 -106
  50. oscura/analyzers/protocols/i2s.py +138 -86
  51. oscura/analyzers/protocols/industrial/__init__.py +40 -0
  52. oscura/analyzers/protocols/industrial/bacnet/__init__.py +33 -0
  53. oscura/analyzers/protocols/industrial/bacnet/analyzer.py +708 -0
  54. oscura/analyzers/protocols/industrial/bacnet/encoding.py +412 -0
  55. oscura/analyzers/protocols/industrial/bacnet/services.py +622 -0
  56. oscura/analyzers/protocols/industrial/ethercat/__init__.py +30 -0
  57. oscura/analyzers/protocols/industrial/ethercat/analyzer.py +474 -0
  58. oscura/analyzers/protocols/industrial/ethercat/mailbox.py +339 -0
  59. oscura/analyzers/protocols/industrial/ethercat/topology.py +166 -0
  60. oscura/analyzers/protocols/industrial/modbus/__init__.py +31 -0
  61. oscura/analyzers/protocols/industrial/modbus/analyzer.py +525 -0
  62. oscura/analyzers/protocols/industrial/modbus/crc.py +79 -0
  63. oscura/analyzers/protocols/industrial/modbus/functions.py +436 -0
  64. oscura/analyzers/protocols/industrial/opcua/__init__.py +21 -0
  65. oscura/analyzers/protocols/industrial/opcua/analyzer.py +552 -0
  66. oscura/analyzers/protocols/industrial/opcua/datatypes.py +446 -0
  67. oscura/analyzers/protocols/industrial/opcua/services.py +264 -0
  68. oscura/analyzers/protocols/industrial/profinet/__init__.py +23 -0
  69. oscura/analyzers/protocols/industrial/profinet/analyzer.py +441 -0
  70. oscura/analyzers/protocols/industrial/profinet/dcp.py +263 -0
  71. oscura/analyzers/protocols/industrial/profinet/ptcp.py +200 -0
  72. oscura/analyzers/protocols/jtag.py +180 -98
  73. oscura/analyzers/protocols/lin.py +219 -114
  74. oscura/analyzers/protocols/manchester.py +4 -4
  75. oscura/analyzers/protocols/onewire.py +253 -149
  76. oscura/analyzers/protocols/parallel_bus/__init__.py +20 -0
  77. oscura/analyzers/protocols/parallel_bus/centronics.py +92 -0
  78. oscura/analyzers/protocols/parallel_bus/gpib.py +137 -0
  79. oscura/analyzers/protocols/spi.py +192 -95
  80. oscura/analyzers/protocols/swd.py +321 -167
  81. oscura/analyzers/protocols/uart.py +267 -125
  82. oscura/analyzers/protocols/usb.py +235 -131
  83. oscura/analyzers/side_channel/power.py +17 -12
  84. oscura/analyzers/signal/__init__.py +15 -0
  85. oscura/analyzers/signal/timing_analysis.py +1086 -0
  86. oscura/analyzers/signal_integrity/__init__.py +4 -1
  87. oscura/analyzers/signal_integrity/sparams.py +2 -19
  88. oscura/analyzers/spectral/chunked.py +129 -60
  89. oscura/analyzers/spectral/chunked_fft.py +300 -94
  90. oscura/analyzers/spectral/chunked_wavelet.py +100 -80
  91. oscura/analyzers/statistical/checksum.py +376 -217
  92. oscura/analyzers/statistical/classification.py +229 -107
  93. oscura/analyzers/statistical/entropy.py +78 -53
  94. oscura/analyzers/statistics/correlation.py +407 -211
  95. oscura/analyzers/statistics/outliers.py +2 -2
  96. oscura/analyzers/statistics/streaming.py +30 -5
  97. oscura/analyzers/validation.py +216 -101
  98. oscura/analyzers/waveform/measurements.py +9 -0
  99. oscura/analyzers/waveform/measurements_with_uncertainty.py +31 -15
  100. oscura/analyzers/waveform/spectral.py +500 -228
  101. oscura/api/__init__.py +31 -5
  102. oscura/api/dsl/__init__.py +582 -0
  103. oscura/{dsl → api/dsl}/commands.py +43 -76
  104. oscura/{dsl → api/dsl}/interpreter.py +26 -51
  105. oscura/{dsl → api/dsl}/parser.py +107 -77
  106. oscura/{dsl → api/dsl}/repl.py +2 -2
  107. oscura/api/dsl.py +1 -1
  108. oscura/{integrations → api/integrations}/__init__.py +1 -1
  109. oscura/{integrations → api/integrations}/llm.py +201 -102
  110. oscura/api/operators.py +3 -3
  111. oscura/api/optimization.py +144 -30
  112. oscura/api/rest_server.py +921 -0
  113. oscura/api/server/__init__.py +17 -0
  114. oscura/api/server/dashboard.py +850 -0
  115. oscura/api/server/static/README.md +34 -0
  116. oscura/api/server/templates/base.html +181 -0
  117. oscura/api/server/templates/export.html +120 -0
  118. oscura/api/server/templates/home.html +284 -0
  119. oscura/api/server/templates/protocols.html +58 -0
  120. oscura/api/server/templates/reports.html +43 -0
  121. oscura/api/server/templates/session_detail.html +89 -0
  122. oscura/api/server/templates/sessions.html +83 -0
  123. oscura/api/server/templates/waveforms.html +73 -0
  124. oscura/automotive/__init__.py +8 -1
  125. oscura/automotive/can/__init__.py +10 -0
  126. oscura/automotive/can/checksum.py +3 -1
  127. oscura/automotive/can/dbc_generator.py +590 -0
  128. oscura/automotive/can/message_wrapper.py +121 -74
  129. oscura/automotive/can/patterns.py +98 -21
  130. oscura/automotive/can/session.py +292 -56
  131. oscura/automotive/can/state_machine.py +6 -3
  132. oscura/automotive/can/stimulus_response.py +97 -75
  133. oscura/automotive/dbc/__init__.py +10 -2
  134. oscura/automotive/dbc/generator.py +84 -56
  135. oscura/automotive/dbc/parser.py +6 -6
  136. oscura/automotive/dtc/data.json +2763 -0
  137. oscura/automotive/dtc/database.py +2 -2
  138. oscura/automotive/flexray/__init__.py +31 -0
  139. oscura/automotive/flexray/analyzer.py +504 -0
  140. oscura/automotive/flexray/crc.py +185 -0
  141. oscura/automotive/flexray/fibex.py +449 -0
  142. oscura/automotive/j1939/__init__.py +45 -8
  143. oscura/automotive/j1939/analyzer.py +605 -0
  144. oscura/automotive/j1939/spns.py +326 -0
  145. oscura/automotive/j1939/transport.py +306 -0
  146. oscura/automotive/lin/__init__.py +47 -0
  147. oscura/automotive/lin/analyzer.py +612 -0
  148. oscura/automotive/loaders/blf.py +13 -2
  149. oscura/automotive/loaders/csv_can.py +143 -72
  150. oscura/automotive/loaders/dispatcher.py +50 -2
  151. oscura/automotive/loaders/mdf.py +86 -45
  152. oscura/automotive/loaders/pcap.py +111 -61
  153. oscura/automotive/uds/__init__.py +4 -0
  154. oscura/automotive/uds/analyzer.py +725 -0
  155. oscura/automotive/uds/decoder.py +140 -58
  156. oscura/automotive/uds/models.py +7 -1
  157. oscura/automotive/visualization.py +1 -1
  158. oscura/cli/analyze.py +348 -0
  159. oscura/cli/batch.py +142 -122
  160. oscura/cli/benchmark.py +275 -0
  161. oscura/cli/characterize.py +137 -82
  162. oscura/cli/compare.py +224 -131
  163. oscura/cli/completion.py +250 -0
  164. oscura/cli/config_cmd.py +361 -0
  165. oscura/cli/decode.py +164 -87
  166. oscura/cli/export.py +286 -0
  167. oscura/cli/main.py +115 -31
  168. oscura/{onboarding → cli/onboarding}/__init__.py +3 -3
  169. oscura/{onboarding → cli/onboarding}/help.py +80 -58
  170. oscura/{onboarding → cli/onboarding}/tutorials.py +97 -72
  171. oscura/{onboarding → cli/onboarding}/wizard.py +55 -36
  172. oscura/cli/progress.py +147 -0
  173. oscura/cli/shell.py +157 -135
  174. oscura/cli/validate_cmd.py +204 -0
  175. oscura/cli/visualize.py +158 -0
  176. oscura/convenience.py +125 -79
  177. oscura/core/__init__.py +4 -2
  178. oscura/core/backend_selector.py +3 -3
  179. oscura/core/cache.py +126 -15
  180. oscura/core/cancellation.py +1 -1
  181. oscura/{config → core/config}/__init__.py +20 -11
  182. oscura/{config → core/config}/defaults.py +1 -1
  183. oscura/{config → core/config}/loader.py +7 -5
  184. oscura/{config → core/config}/memory.py +5 -5
  185. oscura/{config → core/config}/migration.py +1 -1
  186. oscura/{config → core/config}/pipeline.py +99 -23
  187. oscura/{config → core/config}/preferences.py +1 -1
  188. oscura/{config → core/config}/protocol.py +3 -3
  189. oscura/{config → core/config}/schema.py +426 -272
  190. oscura/{config → core/config}/settings.py +1 -1
  191. oscura/{config → core/config}/thresholds.py +195 -153
  192. oscura/core/correlation.py +5 -6
  193. oscura/core/cross_domain.py +0 -2
  194. oscura/core/debug.py +9 -5
  195. oscura/{extensibility → core/extensibility}/docs.py +158 -70
  196. oscura/{extensibility → core/extensibility}/extensions.py +160 -76
  197. oscura/{extensibility → core/extensibility}/logging.py +1 -1
  198. oscura/{extensibility → core/extensibility}/measurements.py +1 -1
  199. oscura/{extensibility → core/extensibility}/plugins.py +1 -1
  200. oscura/{extensibility → core/extensibility}/templates.py +73 -3
  201. oscura/{extensibility → core/extensibility}/validation.py +1 -1
  202. oscura/core/gpu_backend.py +11 -7
  203. oscura/core/log_query.py +101 -11
  204. oscura/core/logging.py +126 -54
  205. oscura/core/logging_advanced.py +5 -5
  206. oscura/core/memory_limits.py +108 -70
  207. oscura/core/memory_monitor.py +2 -2
  208. oscura/core/memory_progress.py +7 -7
  209. oscura/core/memory_warnings.py +1 -1
  210. oscura/core/numba_backend.py +13 -13
  211. oscura/{plugins → core/plugins}/__init__.py +9 -9
  212. oscura/{plugins → core/plugins}/base.py +7 -7
  213. oscura/{plugins → core/plugins}/cli.py +3 -3
  214. oscura/{plugins → core/plugins}/discovery.py +186 -106
  215. oscura/{plugins → core/plugins}/lifecycle.py +1 -1
  216. oscura/{plugins → core/plugins}/manager.py +7 -7
  217. oscura/{plugins → core/plugins}/registry.py +3 -3
  218. oscura/{plugins → core/plugins}/versioning.py +1 -1
  219. oscura/core/progress.py +16 -1
  220. oscura/core/provenance.py +8 -2
  221. oscura/{schemas → core/schemas}/__init__.py +2 -2
  222. oscura/core/schemas/bus_configuration.json +322 -0
  223. oscura/core/schemas/device_mapping.json +182 -0
  224. oscura/core/schemas/packet_format.json +418 -0
  225. oscura/core/schemas/protocol_definition.json +363 -0
  226. oscura/core/types.py +4 -0
  227. oscura/core/uncertainty.py +3 -3
  228. oscura/correlation/__init__.py +52 -0
  229. oscura/correlation/multi_protocol.py +811 -0
  230. oscura/discovery/auto_decoder.py +117 -35
  231. oscura/discovery/comparison.py +191 -86
  232. oscura/discovery/quality_validator.py +155 -68
  233. oscura/discovery/signal_detector.py +196 -79
  234. oscura/export/__init__.py +18 -20
  235. oscura/export/kaitai_struct.py +513 -0
  236. oscura/export/scapy_layer.py +801 -0
  237. oscura/export/wireshark/README.md +15 -15
  238. oscura/export/wireshark/generator.py +1 -1
  239. oscura/export/wireshark/templates/dissector.lua.j2 +2 -2
  240. oscura/export/wireshark_dissector.py +746 -0
  241. oscura/guidance/wizard.py +207 -111
  242. oscura/hardware/__init__.py +19 -0
  243. oscura/{acquisition → hardware/acquisition}/__init__.py +4 -4
  244. oscura/{acquisition → hardware/acquisition}/file.py +2 -2
  245. oscura/{acquisition → hardware/acquisition}/hardware.py +7 -7
  246. oscura/{acquisition → hardware/acquisition}/saleae.py +15 -12
  247. oscura/{acquisition → hardware/acquisition}/socketcan.py +1 -1
  248. oscura/{acquisition → hardware/acquisition}/streaming.py +2 -2
  249. oscura/{acquisition → hardware/acquisition}/synthetic.py +3 -3
  250. oscura/{acquisition → hardware/acquisition}/visa.py +33 -11
  251. oscura/hardware/firmware/__init__.py +29 -0
  252. oscura/hardware/firmware/pattern_recognition.py +874 -0
  253. oscura/hardware/hal_detector.py +736 -0
  254. oscura/hardware/security/__init__.py +37 -0
  255. oscura/hardware/security/side_channel_detector.py +1126 -0
  256. oscura/inference/__init__.py +4 -0
  257. oscura/inference/active_learning/README.md +7 -7
  258. oscura/inference/active_learning/observation_table.py +4 -1
  259. oscura/inference/alignment.py +216 -123
  260. oscura/inference/bayesian.py +113 -33
  261. oscura/inference/crc_reverse.py +101 -55
  262. oscura/inference/logic.py +6 -2
  263. oscura/inference/message_format.py +342 -183
  264. oscura/inference/protocol.py +95 -44
  265. oscura/inference/protocol_dsl.py +180 -82
  266. oscura/inference/signal_intelligence.py +1439 -706
  267. oscura/inference/spectral.py +99 -57
  268. oscura/inference/state_machine.py +810 -158
  269. oscura/inference/stream.py +270 -110
  270. oscura/iot/__init__.py +34 -0
  271. oscura/iot/coap/__init__.py +32 -0
  272. oscura/iot/coap/analyzer.py +668 -0
  273. oscura/iot/coap/options.py +212 -0
  274. oscura/iot/lorawan/__init__.py +21 -0
  275. oscura/iot/lorawan/crypto.py +206 -0
  276. oscura/iot/lorawan/decoder.py +801 -0
  277. oscura/iot/lorawan/mac_commands.py +341 -0
  278. oscura/iot/mqtt/__init__.py +27 -0
  279. oscura/iot/mqtt/analyzer.py +999 -0
  280. oscura/iot/mqtt/properties.py +315 -0
  281. oscura/iot/zigbee/__init__.py +31 -0
  282. oscura/iot/zigbee/analyzer.py +615 -0
  283. oscura/iot/zigbee/security.py +153 -0
  284. oscura/iot/zigbee/zcl.py +349 -0
  285. oscura/jupyter/display.py +125 -45
  286. oscura/{exploratory → jupyter/exploratory}/__init__.py +8 -8
  287. oscura/{exploratory → jupyter/exploratory}/error_recovery.py +298 -141
  288. oscura/jupyter/exploratory/fuzzy.py +746 -0
  289. oscura/{exploratory → jupyter/exploratory}/fuzzy_advanced.py +258 -100
  290. oscura/{exploratory → jupyter/exploratory}/legacy.py +464 -242
  291. oscura/{exploratory → jupyter/exploratory}/parse.py +167 -145
  292. oscura/{exploratory → jupyter/exploratory}/recovery.py +119 -87
  293. oscura/jupyter/exploratory/sync.py +612 -0
  294. oscura/{exploratory → jupyter/exploratory}/unknown.py +299 -176
  295. oscura/jupyter/magic.py +4 -4
  296. oscura/{ui → jupyter/ui}/__init__.py +2 -2
  297. oscura/{ui → jupyter/ui}/formatters.py +3 -3
  298. oscura/{ui → jupyter/ui}/progressive_display.py +153 -82
  299. oscura/loaders/__init__.py +171 -63
  300. oscura/loaders/binary.py +88 -1
  301. oscura/loaders/chipwhisperer.py +153 -137
  302. oscura/loaders/configurable.py +208 -86
  303. oscura/loaders/csv_loader.py +458 -215
  304. oscura/loaders/hdf5_loader.py +278 -119
  305. oscura/loaders/lazy.py +87 -54
  306. oscura/loaders/mmap_loader.py +1 -1
  307. oscura/loaders/numpy_loader.py +253 -116
  308. oscura/loaders/pcap.py +226 -151
  309. oscura/loaders/rigol.py +110 -49
  310. oscura/loaders/sigrok.py +201 -78
  311. oscura/loaders/tdms.py +81 -58
  312. oscura/loaders/tektronix.py +291 -174
  313. oscura/loaders/touchstone.py +182 -87
  314. oscura/loaders/vcd.py +215 -117
  315. oscura/loaders/wav.py +155 -68
  316. oscura/reporting/__init__.py +9 -7
  317. oscura/reporting/analyze.py +352 -146
  318. oscura/reporting/argument_preparer.py +69 -14
  319. oscura/reporting/auto_report.py +97 -61
  320. oscura/reporting/batch.py +131 -58
  321. oscura/reporting/chart_selection.py +57 -45
  322. oscura/reporting/comparison.py +63 -17
  323. oscura/reporting/content/executive.py +76 -24
  324. oscura/reporting/core_formats/multi_format.py +11 -8
  325. oscura/reporting/engine.py +312 -158
  326. oscura/reporting/enhanced_reports.py +949 -0
  327. oscura/reporting/export.py +86 -43
  328. oscura/reporting/formatting/numbers.py +69 -42
  329. oscura/reporting/html.py +139 -58
  330. oscura/reporting/index.py +137 -65
  331. oscura/reporting/output.py +158 -67
  332. oscura/reporting/pdf.py +67 -102
  333. oscura/reporting/plots.py +191 -112
  334. oscura/reporting/sections.py +88 -47
  335. oscura/reporting/standards.py +104 -61
  336. oscura/reporting/summary_generator.py +75 -55
  337. oscura/reporting/tables.py +138 -54
  338. oscura/reporting/templates/enhanced/protocol_re.html +525 -0
  339. oscura/reporting/templates/index.md +13 -13
  340. oscura/sessions/__init__.py +14 -23
  341. oscura/sessions/base.py +3 -3
  342. oscura/sessions/blackbox.py +106 -10
  343. oscura/sessions/generic.py +2 -2
  344. oscura/sessions/legacy.py +783 -0
  345. oscura/side_channel/__init__.py +63 -0
  346. oscura/side_channel/dpa.py +1025 -0
  347. oscura/utils/__init__.py +15 -1
  348. oscura/utils/autodetect.py +1 -5
  349. oscura/utils/bitwise.py +118 -0
  350. oscura/{builders → utils/builders}/__init__.py +1 -1
  351. oscura/{comparison → utils/comparison}/__init__.py +6 -6
  352. oscura/{comparison → utils/comparison}/compare.py +202 -101
  353. oscura/{comparison → utils/comparison}/golden.py +83 -63
  354. oscura/{comparison → utils/comparison}/limits.py +313 -89
  355. oscura/{comparison → utils/comparison}/mask.py +151 -45
  356. oscura/{comparison → utils/comparison}/trace_diff.py +1 -1
  357. oscura/{comparison → utils/comparison}/visualization.py +147 -89
  358. oscura/{component → utils/component}/__init__.py +3 -3
  359. oscura/{component → utils/component}/impedance.py +122 -58
  360. oscura/{component → utils/component}/reactive.py +165 -168
  361. oscura/{component → utils/component}/transmission_line.py +3 -3
  362. oscura/{filtering → utils/filtering}/__init__.py +6 -6
  363. oscura/{filtering → utils/filtering}/base.py +1 -1
  364. oscura/{filtering → utils/filtering}/convenience.py +2 -2
  365. oscura/{filtering → utils/filtering}/design.py +169 -93
  366. oscura/{filtering → utils/filtering}/filters.py +2 -2
  367. oscura/{filtering → utils/filtering}/introspection.py +2 -2
  368. oscura/utils/geometry.py +31 -0
  369. oscura/utils/imports.py +184 -0
  370. oscura/utils/lazy.py +1 -1
  371. oscura/{math → utils/math}/__init__.py +2 -2
  372. oscura/{math → utils/math}/arithmetic.py +114 -48
  373. oscura/{math → utils/math}/interpolation.py +139 -106
  374. oscura/utils/memory.py +129 -66
  375. oscura/utils/memory_advanced.py +92 -9
  376. oscura/utils/memory_extensions.py +10 -8
  377. oscura/{optimization → utils/optimization}/__init__.py +1 -1
  378. oscura/{optimization → utils/optimization}/search.py +2 -2
  379. oscura/utils/performance/__init__.py +58 -0
  380. oscura/utils/performance/caching.py +889 -0
  381. oscura/utils/performance/lsh_clustering.py +333 -0
  382. oscura/utils/performance/memory_optimizer.py +699 -0
  383. oscura/utils/performance/optimizations.py +675 -0
  384. oscura/utils/performance/parallel.py +654 -0
  385. oscura/utils/performance/profiling.py +661 -0
  386. oscura/{pipeline → utils/pipeline}/base.py +1 -1
  387. oscura/{pipeline → utils/pipeline}/composition.py +11 -3
  388. oscura/{pipeline → utils/pipeline}/parallel.py +3 -2
  389. oscura/{pipeline → utils/pipeline}/pipeline.py +1 -1
  390. oscura/{pipeline → utils/pipeline}/reverse_engineering.py +412 -221
  391. oscura/{search → utils/search}/__init__.py +3 -3
  392. oscura/{search → utils/search}/anomaly.py +188 -58
  393. oscura/utils/search/context.py +294 -0
  394. oscura/{search → utils/search}/pattern.py +138 -10
  395. oscura/utils/serial.py +51 -0
  396. oscura/utils/storage/__init__.py +61 -0
  397. oscura/utils/storage/database.py +1166 -0
  398. oscura/{streaming → utils/streaming}/chunked.py +302 -143
  399. oscura/{streaming → utils/streaming}/progressive.py +1 -1
  400. oscura/{streaming → utils/streaming}/realtime.py +3 -2
  401. oscura/{triggering → utils/triggering}/__init__.py +6 -6
  402. oscura/{triggering → utils/triggering}/base.py +6 -6
  403. oscura/{triggering → utils/triggering}/edge.py +2 -2
  404. oscura/{triggering → utils/triggering}/pattern.py +2 -2
  405. oscura/{triggering → utils/triggering}/pulse.py +115 -74
  406. oscura/{triggering → utils/triggering}/window.py +2 -2
  407. oscura/utils/validation.py +32 -0
  408. oscura/validation/__init__.py +121 -0
  409. oscura/{compliance → validation/compliance}/__init__.py +5 -5
  410. oscura/{compliance → validation/compliance}/advanced.py +5 -5
  411. oscura/{compliance → validation/compliance}/masks.py +1 -1
  412. oscura/{compliance → validation/compliance}/reporting.py +127 -53
  413. oscura/{compliance → validation/compliance}/testing.py +114 -52
  414. oscura/validation/compliance_tests.py +915 -0
  415. oscura/validation/fuzzer.py +990 -0
  416. oscura/validation/grammar_tests.py +596 -0
  417. oscura/validation/grammar_validator.py +904 -0
  418. oscura/validation/hil_testing.py +977 -0
  419. oscura/{quality → validation/quality}/__init__.py +4 -4
  420. oscura/{quality → validation/quality}/ensemble.py +251 -171
  421. oscura/{quality → validation/quality}/explainer.py +3 -3
  422. oscura/{quality → validation/quality}/scoring.py +1 -1
  423. oscura/{quality → validation/quality}/warnings.py +4 -4
  424. oscura/validation/regression_suite.py +808 -0
  425. oscura/validation/replay.py +788 -0
  426. oscura/{testing → validation/testing}/__init__.py +2 -2
  427. oscura/{testing → validation/testing}/synthetic.py +5 -5
  428. oscura/visualization/__init__.py +9 -0
  429. oscura/visualization/accessibility.py +1 -1
  430. oscura/visualization/annotations.py +64 -67
  431. oscura/visualization/colors.py +7 -7
  432. oscura/visualization/digital.py +180 -81
  433. oscura/visualization/eye.py +236 -85
  434. oscura/visualization/interactive.py +320 -143
  435. oscura/visualization/jitter.py +587 -247
  436. oscura/visualization/layout.py +169 -134
  437. oscura/visualization/optimization.py +103 -52
  438. oscura/visualization/palettes.py +1 -1
  439. oscura/visualization/power.py +427 -211
  440. oscura/visualization/power_extended.py +626 -297
  441. oscura/visualization/presets.py +2 -0
  442. oscura/visualization/protocols.py +495 -181
  443. oscura/visualization/render.py +79 -63
  444. oscura/visualization/reverse_engineering.py +171 -124
  445. oscura/visualization/signal_integrity.py +460 -279
  446. oscura/visualization/specialized.py +190 -100
  447. oscura/visualization/spectral.py +670 -255
  448. oscura/visualization/thumbnails.py +166 -137
  449. oscura/visualization/waveform.py +150 -63
  450. oscura/workflows/__init__.py +3 -0
  451. oscura/{batch → workflows/batch}/__init__.py +5 -5
  452. oscura/{batch → workflows/batch}/advanced.py +150 -75
  453. oscura/workflows/batch/aggregate.py +531 -0
  454. oscura/workflows/batch/analyze.py +236 -0
  455. oscura/{batch → workflows/batch}/logging.py +2 -2
  456. oscura/{batch → workflows/batch}/metrics.py +1 -1
  457. oscura/workflows/complete_re.py +1144 -0
  458. oscura/workflows/compliance.py +44 -54
  459. oscura/workflows/digital.py +197 -51
  460. oscura/workflows/legacy/__init__.py +12 -0
  461. oscura/{workflow → workflows/legacy}/dag.py +4 -1
  462. oscura/workflows/multi_trace.py +9 -9
  463. oscura/workflows/power.py +42 -62
  464. oscura/workflows/protocol.py +82 -49
  465. oscura/workflows/reverse_engineering.py +351 -150
  466. oscura/workflows/signal_integrity.py +157 -82
  467. oscura-0.6.0.dist-info/METADATA +643 -0
  468. oscura-0.6.0.dist-info/RECORD +590 -0
  469. oscura/analyzers/digital/ic_database.py +0 -498
  470. oscura/analyzers/digital/timing_paths.py +0 -339
  471. oscura/analyzers/digital/vintage.py +0 -377
  472. oscura/analyzers/digital/vintage_result.py +0 -148
  473. oscura/analyzers/protocols/parallel_bus.py +0 -449
  474. oscura/batch/aggregate.py +0 -300
  475. oscura/batch/analyze.py +0 -139
  476. oscura/dsl/__init__.py +0 -73
  477. oscura/exceptions.py +0 -59
  478. oscura/exploratory/fuzzy.py +0 -513
  479. oscura/exploratory/sync.py +0 -384
  480. oscura/export/wavedrom.py +0 -430
  481. oscura/exporters/__init__.py +0 -94
  482. oscura/exporters/csv.py +0 -303
  483. oscura/exporters/exporters.py +0 -44
  484. oscura/exporters/hdf5.py +0 -217
  485. oscura/exporters/html_export.py +0 -701
  486. oscura/exporters/json_export.py +0 -338
  487. oscura/exporters/markdown_export.py +0 -367
  488. oscura/exporters/matlab_export.py +0 -354
  489. oscura/exporters/npz_export.py +0 -219
  490. oscura/exporters/spice_export.py +0 -210
  491. oscura/exporters/vintage_logic_csv.py +0 -247
  492. oscura/reporting/vintage_logic_report.py +0 -523
  493. oscura/search/context.py +0 -149
  494. oscura/session/__init__.py +0 -34
  495. oscura/session/annotations.py +0 -289
  496. oscura/session/history.py +0 -313
  497. oscura/session/session.py +0 -520
  498. oscura/visualization/digital_advanced.py +0 -718
  499. oscura/visualization/figure_manager.py +0 -156
  500. oscura/workflow/__init__.py +0 -13
  501. oscura-0.5.0.dist-info/METADATA +0 -407
  502. oscura-0.5.0.dist-info/RECORD +0 -486
  503. /oscura/core/{config.py → config/legacy.py} +0 -0
  504. /oscura/{extensibility → core/extensibility}/__init__.py +0 -0
  505. /oscura/{extensibility → core/extensibility}/registry.py +0 -0
  506. /oscura/{plugins → core/plugins}/isolation.py +0 -0
  507. /oscura/{builders → utils/builders}/signal_builder.py +0 -0
  508. /oscura/{optimization → utils/optimization}/parallel.py +0 -0
  509. /oscura/{pipeline → utils/pipeline}/__init__.py +0 -0
  510. /oscura/{streaming → utils/streaming}/__init__.py +0 -0
  511. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/WHEEL +0 -0
  512. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/entry_points.txt +0 -0
  513. {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
- ]
@@ -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
- ]