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
@@ -70,12 +70,12 @@ def plot_eye(
70
70
  colorbar: Show colorbar for density plot.
71
71
 
72
72
  Returns:
73
- Matplotlib Figure object.
73
+ Matplotlib Figure object with eye diagram.
74
74
 
75
75
  Raises:
76
76
  ImportError: If matplotlib is not available.
77
77
  InsufficientDataError: If trace is too short for analysis.
78
- ValueError: If clock recovery failed.
78
+ ValueError: If clock recovery failed or axes has no figure.
79
79
 
80
80
  Example:
81
81
  >>> # With known bit rate
@@ -90,35 +90,82 @@ def plot_eye(
90
90
  IEEE 802.3: Ethernet eye diagram specifications
91
91
  JEDEC JESD65B: High-Speed Interface Eye Diagram Measurements
92
92
  """
93
+ _validate_matplotlib_available()
94
+ _validate_trace_length(trace, min_samples=100)
95
+
96
+ bit_rate, samples_per_bit = _determine_timing_parameters(
97
+ trace, bit_rate, clock_recovery, samples_per_bit
98
+ )
99
+
100
+ fig, ax = _prepare_figure(ax)
101
+ data, n_bits, time_ui = _prepare_eye_data(trace, samples_per_bit)
102
+
103
+ _plot_eye_traces(ax, fig, data, n_bits, samples_per_bit, time_ui, cmap, alpha, colorbar)
104
+ _format_eye_plot(ax, bit_rate, title)
105
+
106
+ if show_measurements:
107
+ eye_metrics = _calculate_eye_metrics(data, samples_per_bit, n_bits)
108
+ _add_eye_measurements(ax, eye_metrics, time_ui)
109
+
110
+ fig.tight_layout()
111
+ return fig
112
+
113
+
114
+ def _validate_matplotlib_available() -> None:
115
+ """Validate matplotlib is available for plotting.
116
+
117
+ Raises:
118
+ ImportError: If matplotlib not installed.
119
+ """
93
120
  if not HAS_MATPLOTLIB:
94
121
  raise ImportError("matplotlib is required for visualization")
95
122
 
96
- if len(trace.data) < 100:
123
+
124
+ def _validate_trace_length(trace: WaveformTrace, min_samples: int) -> None:
125
+ """Validate trace has sufficient samples.
126
+
127
+ Args:
128
+ trace: Waveform trace to validate.
129
+ min_samples: Minimum required samples.
130
+
131
+ Raises:
132
+ InsufficientDataError: If trace too short.
133
+ """
134
+ if len(trace.data) < min_samples:
97
135
  raise InsufficientDataError(
98
- "Eye diagram requires at least 100 samples",
99
- required=100,
136
+ f"Eye diagram requires at least {min_samples} samples",
137
+ required=min_samples,
100
138
  available=len(trace.data),
101
139
  analysis_type="eye_diagram",
102
140
  )
103
141
 
104
- # Recover clock if bit_rate not provided
105
- if bit_rate is None:
106
- from oscura.analyzers.digital.timing import (
107
- recover_clock_edge,
108
- recover_clock_fft,
109
- )
110
142
 
111
- result = recover_clock_fft(trace) if clock_recovery == "fft" else recover_clock_edge(trace)
143
+ def _determine_timing_parameters(
144
+ trace: WaveformTrace,
145
+ bit_rate: float | None,
146
+ clock_recovery: Literal["fft", "edge"],
147
+ samples_per_bit: int | None,
148
+ ) -> tuple[float, int]:
149
+ """Determine bit rate and samples per bit.
150
+
151
+ Args:
152
+ trace: Input waveform trace.
153
+ bit_rate: Bit rate or None for auto-recovery.
154
+ clock_recovery: Clock recovery method.
155
+ samples_per_bit: Samples per bit or None for auto-calculation.
112
156
 
113
- if np.isnan(result.frequency):
114
- raise ValueError("Clock recovery failed - cannot determine bit rate")
157
+ Returns:
158
+ Tuple of (bit_rate, samples_per_bit).
115
159
 
116
- bit_rate = result.frequency
117
- bit_period = result.period
160
+ Raises:
161
+ ValueError: If clock recovery fails.
162
+ InsufficientDataError: If too few samples per bit.
163
+ """
164
+ if bit_rate is None:
165
+ bit_rate, bit_period = _recover_clock(trace, clock_recovery)
118
166
  else:
119
167
  bit_period = 1.0 / bit_rate
120
168
 
121
- # Calculate samples per bit
122
169
  if samples_per_bit is None:
123
170
  samples_per_bit = int(bit_period / trace.metadata.time_base)
124
171
 
@@ -130,16 +177,69 @@ def plot_eye(
130
177
  analysis_type="eye_diagram",
131
178
  )
132
179
 
133
- # Create figure
180
+ return bit_rate, samples_per_bit
181
+
182
+
183
+ def _recover_clock(trace: WaveformTrace, method: Literal["fft", "edge"]) -> tuple[float, float]:
184
+ """Recover clock from signal.
185
+
186
+ Args:
187
+ trace: Input trace.
188
+ method: Recovery method.
189
+
190
+ Returns:
191
+ Tuple of (bit_rate, bit_period).
192
+
193
+ Raises:
194
+ ValueError: If recovery fails.
195
+ """
196
+ from oscura.analyzers.digital.timing import recover_clock_edge, recover_clock_fft
197
+
198
+ result = recover_clock_fft(trace) if method == "fft" else recover_clock_edge(trace)
199
+
200
+ if np.isnan(result.frequency):
201
+ raise ValueError("Clock recovery failed - cannot determine bit rate")
202
+
203
+ return result.frequency, result.period
204
+
205
+
206
+ def _prepare_figure(ax: Axes | None) -> tuple[Figure, Axes]:
207
+ """Prepare matplotlib figure and axes.
208
+
209
+ Args:
210
+ ax: Existing axes or None to create new.
211
+
212
+ Returns:
213
+ Tuple of (figure, axes).
214
+
215
+ Raises:
216
+ ValueError: If axes has no associated figure.
217
+ """
134
218
  if ax is None:
135
- fig, ax = plt.subplots(figsize=(8, 6))
136
- else:
137
- fig_temp = ax.get_figure()
138
- if fig_temp is None:
139
- raise ValueError("Axes must have an associated figure")
140
- fig = cast("Figure", fig_temp)
219
+ fig, ax_new = plt.subplots(figsize=(8, 6))
220
+ return fig, ax_new
221
+
222
+ fig_temp = ax.get_figure()
223
+ if fig_temp is None:
224
+ raise ValueError("Axes must have an associated figure")
225
+ return cast("Figure", fig_temp), ax
226
+
227
+
228
+ def _prepare_eye_data(
229
+ trace: WaveformTrace, samples_per_bit: int
230
+ ) -> tuple[NDArray[np.floating[Any]], int, NDArray[np.float64]]:
231
+ """Prepare data for eye diagram plotting.
232
+
233
+ Args:
234
+ trace: Input trace.
235
+ samples_per_bit: Samples per bit period.
236
+
237
+ Returns:
238
+ Tuple of (data, n_bits, time_ui).
141
239
 
142
- # Extract overlaid bit periods
240
+ Raises:
241
+ InsufficientDataError: If not enough bit periods.
242
+ """
143
243
  data = trace.data
144
244
  n_bits = len(data) // samples_per_bit
145
245
 
@@ -151,75 +251,126 @@ def plot_eye(
151
251
  analysis_type="eye_diagram",
152
252
  )
153
253
 
154
- # Time axis for one bit period (normalized to UI - Unit Interval)
155
254
  time_ui = np.linspace(0, 1, samples_per_bit)
255
+ return data, n_bits, time_ui
156
256
 
157
- # Overlay traces with density tracking
158
- if cmap != "none":
159
- # Use density plot (histogram2d)
160
- all_times: list[np.floating[Any]] = []
161
- all_voltages: list[np.floating[Any]] = []
162
-
163
- for i in range(n_bits - 1):
164
- start_idx = i * samples_per_bit
165
- end_idx = start_idx + samples_per_bit
166
- if end_idx <= len(data):
167
- all_times.extend(time_ui)
168
- all_voltages.extend(data[start_idx:end_idx])
169
-
170
- # Create 2D histogram
171
- h, xedges, yedges = np.histogram2d(
172
- all_times,
173
- all_voltages,
174
- bins=[200, 200],
175
- )
176
257
 
177
- # Plot as image
178
- extent_list = [float(xedges[0]), float(xedges[-1]), float(yedges[0]), float(yedges[-1])]
179
- im = ax.imshow(
180
- h.T,
181
- extent=tuple(extent_list), # type: ignore[arg-type]
182
- origin="lower",
183
- aspect="auto",
184
- cmap=cmap,
185
- interpolation="bilinear",
186
- )
258
+ def _plot_eye_traces(
259
+ ax: Axes,
260
+ fig: Figure,
261
+ data: NDArray[np.floating[Any]],
262
+ n_bits: int,
263
+ samples_per_bit: int,
264
+ time_ui: NDArray[np.float64],
265
+ cmap: str,
266
+ alpha: float,
267
+ colorbar: bool,
268
+ ) -> None:
269
+ """Plot eye traces as density or line overlay.
187
270
 
188
- if colorbar:
189
- fig.colorbar(im, ax=ax, label="Sample Density")
271
+ Args:
272
+ ax: Matplotlib axes.
273
+ fig: Matplotlib figure.
274
+ data: Waveform data.
275
+ n_bits: Number of bit periods.
276
+ samples_per_bit: Samples per bit.
277
+ time_ui: Time axis in UI.
278
+ cmap: Colormap name.
279
+ alpha: Transparency.
280
+ colorbar: Show colorbar.
281
+ """
282
+ if cmap != "none":
283
+ _plot_density_eye(ax, fig, data, n_bits, samples_per_bit, time_ui, cmap, colorbar)
190
284
  else:
191
- # Simple line overlay
192
- for i in range(min(n_bits - 1, 1000)): # Limit to 1000 traces for performance
193
- start_idx = i * samples_per_bit
194
- end_idx = start_idx + samples_per_bit
195
- if end_idx <= len(data):
196
- ax.plot(
197
- time_ui,
198
- data[start_idx:end_idx],
199
- color="blue",
200
- alpha=alpha,
201
- linewidth=0.5,
202
- )
203
-
204
- # Labels and formatting
205
- ax.set_xlabel("Time (UI)")
206
- ax.set_ylabel("Voltage (V)")
207
- ax.set_xlim(0, 1)
285
+ _plot_line_eye(ax, data, n_bits, samples_per_bit, time_ui, alpha)
208
286
 
209
- if title:
210
- ax.set_title(title)
211
- else:
212
- ax.set_title(f"Eye Diagram @ {bit_rate / 1e6:.1f} Mbps")
213
287
 
214
- ax.grid(True, alpha=0.3)
288
+ def _plot_density_eye(
289
+ ax: Axes,
290
+ fig: Figure,
291
+ data: NDArray[np.floating[Any]],
292
+ n_bits: int,
293
+ samples_per_bit: int,
294
+ time_ui: NDArray[np.float64],
295
+ cmap: str,
296
+ colorbar: bool,
297
+ ) -> None:
298
+ """Plot eye diagram as density heatmap.
215
299
 
216
- # Add eye opening measurements
217
- if show_measurements:
218
- eye_metrics = _calculate_eye_metrics(data, samples_per_bit, n_bits)
219
- _add_eye_measurements(ax, eye_metrics, time_ui)
300
+ Args:
301
+ ax: Axes to plot on.
302
+ fig: Figure for colorbar.
303
+ data: Waveform data.
304
+ n_bits: Number of bits.
305
+ samples_per_bit: Samples per bit.
306
+ time_ui: Time in UI.
307
+ cmap: Colormap.
308
+ colorbar: Show colorbar.
309
+ """
310
+ all_times: list[np.floating[Any]] = []
311
+ all_voltages: list[np.floating[Any]] = []
220
312
 
221
- fig.tight_layout()
222
- return fig
313
+ for i in range(n_bits - 1):
314
+ start_idx = i * samples_per_bit
315
+ end_idx = start_idx + samples_per_bit
316
+ if end_idx <= len(data):
317
+ all_times.extend(time_ui)
318
+ all_voltages.extend(data[start_idx:end_idx])
319
+
320
+ h, xedges, yedges = np.histogram2d(all_times, all_voltages, bins=[200, 200])
321
+ extent_list = [float(xedges[0]), float(xedges[-1]), float(yedges[0]), float(yedges[-1])]
322
+
323
+ im = ax.imshow(
324
+ h.T,
325
+ extent=tuple(extent_list), # type: ignore[arg-type]
326
+ origin="lower",
327
+ aspect="auto",
328
+ cmap=cmap,
329
+ interpolation="bilinear",
330
+ )
331
+
332
+ if colorbar:
333
+ fig.colorbar(im, ax=ax, label="Sample Density")
334
+
335
+
336
+ def _plot_line_eye(
337
+ ax: Axes,
338
+ data: NDArray[np.floating[Any]],
339
+ n_bits: int,
340
+ samples_per_bit: int,
341
+ time_ui: NDArray[np.float64],
342
+ alpha: float,
343
+ ) -> None:
344
+ """Plot eye diagram as overlaid lines.
345
+
346
+ Args:
347
+ ax: Axes to plot on.
348
+ data: Waveform data.
349
+ n_bits: Number of bits.
350
+ samples_per_bit: Samples per bit.
351
+ time_ui: Time in UI.
352
+ alpha: Line transparency.
353
+ """
354
+ for i in range(min(n_bits - 1, 1000)): # Limit for performance
355
+ start_idx = i * samples_per_bit
356
+ end_idx = start_idx + samples_per_bit
357
+ if end_idx <= len(data):
358
+ ax.plot(time_ui, data[start_idx:end_idx], color="blue", alpha=alpha, linewidth=0.5)
359
+
360
+
361
+ def _format_eye_plot(ax: Axes, bit_rate: float, title: str | None) -> None:
362
+ """Format eye diagram plot labels and styling.
363
+
364
+ Args:
365
+ ax: Axes to format.
366
+ bit_rate: Bit rate for title.
367
+ title: Custom title or None.
368
+ """
369
+ ax.set_xlabel("Time (UI)")
370
+ ax.set_ylabel("Voltage (V)")
371
+ ax.set_xlim(0, 1)
372
+ ax.set_title(title if title else f"Eye Diagram @ {bit_rate / 1e6:.1f} Mbps")
373
+ ax.grid(True, alpha=0.3)
223
374
 
224
375
 
225
376
  def _calculate_eye_metrics(