oscura 0.0.1__py3-none-any.whl → 0.1.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 (465) hide show
  1. oscura/__init__.py +813 -8
  2. oscura/__main__.py +392 -0
  3. oscura/analyzers/__init__.py +37 -0
  4. oscura/analyzers/digital/__init__.py +177 -0
  5. oscura/analyzers/digital/bus.py +691 -0
  6. oscura/analyzers/digital/clock.py +805 -0
  7. oscura/analyzers/digital/correlation.py +720 -0
  8. oscura/analyzers/digital/edges.py +632 -0
  9. oscura/analyzers/digital/extraction.py +413 -0
  10. oscura/analyzers/digital/quality.py +878 -0
  11. oscura/analyzers/digital/signal_quality.py +877 -0
  12. oscura/analyzers/digital/thresholds.py +708 -0
  13. oscura/analyzers/digital/timing.py +1104 -0
  14. oscura/analyzers/eye/__init__.py +46 -0
  15. oscura/analyzers/eye/diagram.py +434 -0
  16. oscura/analyzers/eye/metrics.py +555 -0
  17. oscura/analyzers/jitter/__init__.py +83 -0
  18. oscura/analyzers/jitter/ber.py +333 -0
  19. oscura/analyzers/jitter/decomposition.py +759 -0
  20. oscura/analyzers/jitter/measurements.py +413 -0
  21. oscura/analyzers/jitter/spectrum.py +220 -0
  22. oscura/analyzers/measurements.py +40 -0
  23. oscura/analyzers/packet/__init__.py +171 -0
  24. oscura/analyzers/packet/daq.py +1077 -0
  25. oscura/analyzers/packet/metrics.py +437 -0
  26. oscura/analyzers/packet/parser.py +327 -0
  27. oscura/analyzers/packet/payload.py +2156 -0
  28. oscura/analyzers/packet/payload_analysis.py +1312 -0
  29. oscura/analyzers/packet/payload_extraction.py +236 -0
  30. oscura/analyzers/packet/payload_patterns.py +670 -0
  31. oscura/analyzers/packet/stream.py +359 -0
  32. oscura/analyzers/patterns/__init__.py +266 -0
  33. oscura/analyzers/patterns/clustering.py +1036 -0
  34. oscura/analyzers/patterns/discovery.py +539 -0
  35. oscura/analyzers/patterns/learning.py +797 -0
  36. oscura/analyzers/patterns/matching.py +1091 -0
  37. oscura/analyzers/patterns/periodic.py +650 -0
  38. oscura/analyzers/patterns/sequences.py +767 -0
  39. oscura/analyzers/power/__init__.py +116 -0
  40. oscura/analyzers/power/ac_power.py +391 -0
  41. oscura/analyzers/power/basic.py +383 -0
  42. oscura/analyzers/power/conduction.py +314 -0
  43. oscura/analyzers/power/efficiency.py +297 -0
  44. oscura/analyzers/power/ripple.py +356 -0
  45. oscura/analyzers/power/soa.py +372 -0
  46. oscura/analyzers/power/switching.py +479 -0
  47. oscura/analyzers/protocol/__init__.py +150 -0
  48. oscura/analyzers/protocols/__init__.py +150 -0
  49. oscura/analyzers/protocols/base.py +500 -0
  50. oscura/analyzers/protocols/can.py +620 -0
  51. oscura/analyzers/protocols/can_fd.py +448 -0
  52. oscura/analyzers/protocols/flexray.py +405 -0
  53. oscura/analyzers/protocols/hdlc.py +399 -0
  54. oscura/analyzers/protocols/i2c.py +368 -0
  55. oscura/analyzers/protocols/i2s.py +296 -0
  56. oscura/analyzers/protocols/jtag.py +393 -0
  57. oscura/analyzers/protocols/lin.py +445 -0
  58. oscura/analyzers/protocols/manchester.py +333 -0
  59. oscura/analyzers/protocols/onewire.py +501 -0
  60. oscura/analyzers/protocols/spi.py +334 -0
  61. oscura/analyzers/protocols/swd.py +325 -0
  62. oscura/analyzers/protocols/uart.py +393 -0
  63. oscura/analyzers/protocols/usb.py +495 -0
  64. oscura/analyzers/signal_integrity/__init__.py +63 -0
  65. oscura/analyzers/signal_integrity/embedding.py +294 -0
  66. oscura/analyzers/signal_integrity/equalization.py +370 -0
  67. oscura/analyzers/signal_integrity/sparams.py +484 -0
  68. oscura/analyzers/spectral/__init__.py +53 -0
  69. oscura/analyzers/spectral/chunked.py +273 -0
  70. oscura/analyzers/spectral/chunked_fft.py +571 -0
  71. oscura/analyzers/spectral/chunked_wavelet.py +391 -0
  72. oscura/analyzers/spectral/fft.py +92 -0
  73. oscura/analyzers/statistical/__init__.py +250 -0
  74. oscura/analyzers/statistical/checksum.py +923 -0
  75. oscura/analyzers/statistical/chunked_corr.py +228 -0
  76. oscura/analyzers/statistical/classification.py +778 -0
  77. oscura/analyzers/statistical/entropy.py +1113 -0
  78. oscura/analyzers/statistical/ngrams.py +614 -0
  79. oscura/analyzers/statistics/__init__.py +119 -0
  80. oscura/analyzers/statistics/advanced.py +885 -0
  81. oscura/analyzers/statistics/basic.py +263 -0
  82. oscura/analyzers/statistics/correlation.py +630 -0
  83. oscura/analyzers/statistics/distribution.py +298 -0
  84. oscura/analyzers/statistics/outliers.py +463 -0
  85. oscura/analyzers/statistics/streaming.py +93 -0
  86. oscura/analyzers/statistics/trend.py +520 -0
  87. oscura/analyzers/validation.py +598 -0
  88. oscura/analyzers/waveform/__init__.py +36 -0
  89. oscura/analyzers/waveform/measurements.py +943 -0
  90. oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
  91. oscura/analyzers/waveform/spectral.py +1689 -0
  92. oscura/analyzers/waveform/wavelets.py +298 -0
  93. oscura/api/__init__.py +62 -0
  94. oscura/api/dsl.py +538 -0
  95. oscura/api/fluent.py +571 -0
  96. oscura/api/operators.py +498 -0
  97. oscura/api/optimization.py +392 -0
  98. oscura/api/profiling.py +396 -0
  99. oscura/automotive/__init__.py +73 -0
  100. oscura/automotive/can/__init__.py +52 -0
  101. oscura/automotive/can/analysis.py +356 -0
  102. oscura/automotive/can/checksum.py +250 -0
  103. oscura/automotive/can/correlation.py +212 -0
  104. oscura/automotive/can/discovery.py +355 -0
  105. oscura/automotive/can/message_wrapper.py +375 -0
  106. oscura/automotive/can/models.py +385 -0
  107. oscura/automotive/can/patterns.py +381 -0
  108. oscura/automotive/can/session.py +452 -0
  109. oscura/automotive/can/state_machine.py +300 -0
  110. oscura/automotive/can/stimulus_response.py +461 -0
  111. oscura/automotive/dbc/__init__.py +15 -0
  112. oscura/automotive/dbc/generator.py +156 -0
  113. oscura/automotive/dbc/parser.py +146 -0
  114. oscura/automotive/dtc/__init__.py +30 -0
  115. oscura/automotive/dtc/database.py +3036 -0
  116. oscura/automotive/j1939/__init__.py +14 -0
  117. oscura/automotive/j1939/decoder.py +745 -0
  118. oscura/automotive/loaders/__init__.py +35 -0
  119. oscura/automotive/loaders/asc.py +98 -0
  120. oscura/automotive/loaders/blf.py +77 -0
  121. oscura/automotive/loaders/csv_can.py +136 -0
  122. oscura/automotive/loaders/dispatcher.py +136 -0
  123. oscura/automotive/loaders/mdf.py +331 -0
  124. oscura/automotive/loaders/pcap.py +132 -0
  125. oscura/automotive/obd/__init__.py +14 -0
  126. oscura/automotive/obd/decoder.py +707 -0
  127. oscura/automotive/uds/__init__.py +48 -0
  128. oscura/automotive/uds/decoder.py +265 -0
  129. oscura/automotive/uds/models.py +64 -0
  130. oscura/automotive/visualization.py +369 -0
  131. oscura/batch/__init__.py +55 -0
  132. oscura/batch/advanced.py +627 -0
  133. oscura/batch/aggregate.py +300 -0
  134. oscura/batch/analyze.py +139 -0
  135. oscura/batch/logging.py +487 -0
  136. oscura/batch/metrics.py +556 -0
  137. oscura/builders/__init__.py +41 -0
  138. oscura/builders/signal_builder.py +1131 -0
  139. oscura/cli/__init__.py +14 -0
  140. oscura/cli/batch.py +339 -0
  141. oscura/cli/characterize.py +273 -0
  142. oscura/cli/compare.py +775 -0
  143. oscura/cli/decode.py +551 -0
  144. oscura/cli/main.py +247 -0
  145. oscura/cli/shell.py +350 -0
  146. oscura/comparison/__init__.py +66 -0
  147. oscura/comparison/compare.py +397 -0
  148. oscura/comparison/golden.py +487 -0
  149. oscura/comparison/limits.py +391 -0
  150. oscura/comparison/mask.py +434 -0
  151. oscura/comparison/trace_diff.py +30 -0
  152. oscura/comparison/visualization.py +481 -0
  153. oscura/compliance/__init__.py +70 -0
  154. oscura/compliance/advanced.py +756 -0
  155. oscura/compliance/masks.py +363 -0
  156. oscura/compliance/reporting.py +483 -0
  157. oscura/compliance/testing.py +298 -0
  158. oscura/component/__init__.py +38 -0
  159. oscura/component/impedance.py +365 -0
  160. oscura/component/reactive.py +598 -0
  161. oscura/component/transmission_line.py +312 -0
  162. oscura/config/__init__.py +191 -0
  163. oscura/config/defaults.py +254 -0
  164. oscura/config/loader.py +348 -0
  165. oscura/config/memory.py +271 -0
  166. oscura/config/migration.py +458 -0
  167. oscura/config/pipeline.py +1077 -0
  168. oscura/config/preferences.py +530 -0
  169. oscura/config/protocol.py +875 -0
  170. oscura/config/schema.py +713 -0
  171. oscura/config/settings.py +420 -0
  172. oscura/config/thresholds.py +599 -0
  173. oscura/convenience.py +457 -0
  174. oscura/core/__init__.py +299 -0
  175. oscura/core/audit.py +457 -0
  176. oscura/core/backend_selector.py +405 -0
  177. oscura/core/cache.py +590 -0
  178. oscura/core/cancellation.py +439 -0
  179. oscura/core/confidence.py +225 -0
  180. oscura/core/config.py +506 -0
  181. oscura/core/correlation.py +216 -0
  182. oscura/core/cross_domain.py +422 -0
  183. oscura/core/debug.py +301 -0
  184. oscura/core/edge_cases.py +541 -0
  185. oscura/core/exceptions.py +535 -0
  186. oscura/core/gpu_backend.py +523 -0
  187. oscura/core/lazy.py +832 -0
  188. oscura/core/log_query.py +540 -0
  189. oscura/core/logging.py +931 -0
  190. oscura/core/logging_advanced.py +952 -0
  191. oscura/core/memoize.py +171 -0
  192. oscura/core/memory_check.py +274 -0
  193. oscura/core/memory_guard.py +290 -0
  194. oscura/core/memory_limits.py +336 -0
  195. oscura/core/memory_monitor.py +453 -0
  196. oscura/core/memory_progress.py +465 -0
  197. oscura/core/memory_warnings.py +315 -0
  198. oscura/core/numba_backend.py +362 -0
  199. oscura/core/performance.py +352 -0
  200. oscura/core/progress.py +524 -0
  201. oscura/core/provenance.py +358 -0
  202. oscura/core/results.py +331 -0
  203. oscura/core/types.py +504 -0
  204. oscura/core/uncertainty.py +383 -0
  205. oscura/discovery/__init__.py +52 -0
  206. oscura/discovery/anomaly_detector.py +672 -0
  207. oscura/discovery/auto_decoder.py +415 -0
  208. oscura/discovery/comparison.py +497 -0
  209. oscura/discovery/quality_validator.py +528 -0
  210. oscura/discovery/signal_detector.py +769 -0
  211. oscura/dsl/__init__.py +73 -0
  212. oscura/dsl/commands.py +246 -0
  213. oscura/dsl/interpreter.py +455 -0
  214. oscura/dsl/parser.py +689 -0
  215. oscura/dsl/repl.py +172 -0
  216. oscura/exceptions.py +59 -0
  217. oscura/exploratory/__init__.py +111 -0
  218. oscura/exploratory/error_recovery.py +642 -0
  219. oscura/exploratory/fuzzy.py +513 -0
  220. oscura/exploratory/fuzzy_advanced.py +786 -0
  221. oscura/exploratory/legacy.py +831 -0
  222. oscura/exploratory/parse.py +358 -0
  223. oscura/exploratory/recovery.py +275 -0
  224. oscura/exploratory/sync.py +382 -0
  225. oscura/exploratory/unknown.py +707 -0
  226. oscura/export/__init__.py +25 -0
  227. oscura/export/wireshark/README.md +265 -0
  228. oscura/export/wireshark/__init__.py +47 -0
  229. oscura/export/wireshark/generator.py +312 -0
  230. oscura/export/wireshark/lua_builder.py +159 -0
  231. oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
  232. oscura/export/wireshark/type_mapping.py +165 -0
  233. oscura/export/wireshark/validator.py +105 -0
  234. oscura/exporters/__init__.py +94 -0
  235. oscura/exporters/csv.py +303 -0
  236. oscura/exporters/exporters.py +44 -0
  237. oscura/exporters/hdf5.py +219 -0
  238. oscura/exporters/html_export.py +701 -0
  239. oscura/exporters/json_export.py +291 -0
  240. oscura/exporters/markdown_export.py +367 -0
  241. oscura/exporters/matlab_export.py +354 -0
  242. oscura/exporters/npz_export.py +219 -0
  243. oscura/exporters/spice_export.py +210 -0
  244. oscura/extensibility/__init__.py +131 -0
  245. oscura/extensibility/docs.py +752 -0
  246. oscura/extensibility/extensions.py +1125 -0
  247. oscura/extensibility/logging.py +259 -0
  248. oscura/extensibility/measurements.py +485 -0
  249. oscura/extensibility/plugins.py +414 -0
  250. oscura/extensibility/registry.py +346 -0
  251. oscura/extensibility/templates.py +913 -0
  252. oscura/extensibility/validation.py +651 -0
  253. oscura/filtering/__init__.py +89 -0
  254. oscura/filtering/base.py +563 -0
  255. oscura/filtering/convenience.py +564 -0
  256. oscura/filtering/design.py +725 -0
  257. oscura/filtering/filters.py +32 -0
  258. oscura/filtering/introspection.py +605 -0
  259. oscura/guidance/__init__.py +24 -0
  260. oscura/guidance/recommender.py +429 -0
  261. oscura/guidance/wizard.py +518 -0
  262. oscura/inference/__init__.py +251 -0
  263. oscura/inference/active_learning/README.md +153 -0
  264. oscura/inference/active_learning/__init__.py +38 -0
  265. oscura/inference/active_learning/lstar.py +257 -0
  266. oscura/inference/active_learning/observation_table.py +230 -0
  267. oscura/inference/active_learning/oracle.py +78 -0
  268. oscura/inference/active_learning/teachers/__init__.py +15 -0
  269. oscura/inference/active_learning/teachers/simulator.py +192 -0
  270. oscura/inference/adaptive_tuning.py +453 -0
  271. oscura/inference/alignment.py +653 -0
  272. oscura/inference/bayesian.py +943 -0
  273. oscura/inference/binary.py +1016 -0
  274. oscura/inference/crc_reverse.py +711 -0
  275. oscura/inference/logic.py +288 -0
  276. oscura/inference/message_format.py +1305 -0
  277. oscura/inference/protocol.py +417 -0
  278. oscura/inference/protocol_dsl.py +1084 -0
  279. oscura/inference/protocol_library.py +1230 -0
  280. oscura/inference/sequences.py +809 -0
  281. oscura/inference/signal_intelligence.py +1509 -0
  282. oscura/inference/spectral.py +215 -0
  283. oscura/inference/state_machine.py +634 -0
  284. oscura/inference/stream.py +918 -0
  285. oscura/integrations/__init__.py +59 -0
  286. oscura/integrations/llm.py +1827 -0
  287. oscura/jupyter/__init__.py +32 -0
  288. oscura/jupyter/display.py +268 -0
  289. oscura/jupyter/magic.py +334 -0
  290. oscura/loaders/__init__.py +526 -0
  291. oscura/loaders/binary.py +69 -0
  292. oscura/loaders/configurable.py +1255 -0
  293. oscura/loaders/csv.py +26 -0
  294. oscura/loaders/csv_loader.py +473 -0
  295. oscura/loaders/hdf5.py +9 -0
  296. oscura/loaders/hdf5_loader.py +510 -0
  297. oscura/loaders/lazy.py +370 -0
  298. oscura/loaders/mmap_loader.py +583 -0
  299. oscura/loaders/numpy_loader.py +436 -0
  300. oscura/loaders/pcap.py +432 -0
  301. oscura/loaders/preprocessing.py +368 -0
  302. oscura/loaders/rigol.py +287 -0
  303. oscura/loaders/sigrok.py +321 -0
  304. oscura/loaders/tdms.py +367 -0
  305. oscura/loaders/tektronix.py +711 -0
  306. oscura/loaders/validation.py +584 -0
  307. oscura/loaders/vcd.py +464 -0
  308. oscura/loaders/wav.py +233 -0
  309. oscura/math/__init__.py +45 -0
  310. oscura/math/arithmetic.py +824 -0
  311. oscura/math/interpolation.py +413 -0
  312. oscura/onboarding/__init__.py +39 -0
  313. oscura/onboarding/help.py +498 -0
  314. oscura/onboarding/tutorials.py +405 -0
  315. oscura/onboarding/wizard.py +466 -0
  316. oscura/optimization/__init__.py +19 -0
  317. oscura/optimization/parallel.py +440 -0
  318. oscura/optimization/search.py +532 -0
  319. oscura/pipeline/__init__.py +43 -0
  320. oscura/pipeline/base.py +338 -0
  321. oscura/pipeline/composition.py +242 -0
  322. oscura/pipeline/parallel.py +448 -0
  323. oscura/pipeline/pipeline.py +375 -0
  324. oscura/pipeline/reverse_engineering.py +1119 -0
  325. oscura/plugins/__init__.py +122 -0
  326. oscura/plugins/base.py +272 -0
  327. oscura/plugins/cli.py +497 -0
  328. oscura/plugins/discovery.py +411 -0
  329. oscura/plugins/isolation.py +418 -0
  330. oscura/plugins/lifecycle.py +959 -0
  331. oscura/plugins/manager.py +493 -0
  332. oscura/plugins/registry.py +421 -0
  333. oscura/plugins/versioning.py +372 -0
  334. oscura/py.typed +0 -0
  335. oscura/quality/__init__.py +65 -0
  336. oscura/quality/ensemble.py +740 -0
  337. oscura/quality/explainer.py +338 -0
  338. oscura/quality/scoring.py +616 -0
  339. oscura/quality/warnings.py +456 -0
  340. oscura/reporting/__init__.py +248 -0
  341. oscura/reporting/advanced.py +1234 -0
  342. oscura/reporting/analyze.py +448 -0
  343. oscura/reporting/argument_preparer.py +596 -0
  344. oscura/reporting/auto_report.py +507 -0
  345. oscura/reporting/batch.py +615 -0
  346. oscura/reporting/chart_selection.py +223 -0
  347. oscura/reporting/comparison.py +330 -0
  348. oscura/reporting/config.py +615 -0
  349. oscura/reporting/content/__init__.py +39 -0
  350. oscura/reporting/content/executive.py +127 -0
  351. oscura/reporting/content/filtering.py +191 -0
  352. oscura/reporting/content/minimal.py +257 -0
  353. oscura/reporting/content/verbosity.py +162 -0
  354. oscura/reporting/core.py +508 -0
  355. oscura/reporting/core_formats/__init__.py +17 -0
  356. oscura/reporting/core_formats/multi_format.py +210 -0
  357. oscura/reporting/engine.py +836 -0
  358. oscura/reporting/export.py +366 -0
  359. oscura/reporting/formatting/__init__.py +129 -0
  360. oscura/reporting/formatting/emphasis.py +81 -0
  361. oscura/reporting/formatting/numbers.py +403 -0
  362. oscura/reporting/formatting/standards.py +55 -0
  363. oscura/reporting/formatting.py +466 -0
  364. oscura/reporting/html.py +578 -0
  365. oscura/reporting/index.py +590 -0
  366. oscura/reporting/multichannel.py +296 -0
  367. oscura/reporting/output.py +379 -0
  368. oscura/reporting/pdf.py +373 -0
  369. oscura/reporting/plots.py +731 -0
  370. oscura/reporting/pptx_export.py +360 -0
  371. oscura/reporting/renderers/__init__.py +11 -0
  372. oscura/reporting/renderers/pdf.py +94 -0
  373. oscura/reporting/sections.py +471 -0
  374. oscura/reporting/standards.py +680 -0
  375. oscura/reporting/summary_generator.py +368 -0
  376. oscura/reporting/tables.py +397 -0
  377. oscura/reporting/template_system.py +724 -0
  378. oscura/reporting/templates/__init__.py +15 -0
  379. oscura/reporting/templates/definition.py +205 -0
  380. oscura/reporting/templates/index.html +649 -0
  381. oscura/reporting/templates/index.md +173 -0
  382. oscura/schemas/__init__.py +158 -0
  383. oscura/schemas/bus_configuration.json +322 -0
  384. oscura/schemas/device_mapping.json +182 -0
  385. oscura/schemas/packet_format.json +418 -0
  386. oscura/schemas/protocol_definition.json +363 -0
  387. oscura/search/__init__.py +16 -0
  388. oscura/search/anomaly.py +292 -0
  389. oscura/search/context.py +149 -0
  390. oscura/search/pattern.py +160 -0
  391. oscura/session/__init__.py +34 -0
  392. oscura/session/annotations.py +289 -0
  393. oscura/session/history.py +313 -0
  394. oscura/session/session.py +445 -0
  395. oscura/streaming/__init__.py +43 -0
  396. oscura/streaming/chunked.py +611 -0
  397. oscura/streaming/progressive.py +393 -0
  398. oscura/streaming/realtime.py +622 -0
  399. oscura/testing/__init__.py +54 -0
  400. oscura/testing/synthetic.py +808 -0
  401. oscura/triggering/__init__.py +68 -0
  402. oscura/triggering/base.py +229 -0
  403. oscura/triggering/edge.py +353 -0
  404. oscura/triggering/pattern.py +344 -0
  405. oscura/triggering/pulse.py +581 -0
  406. oscura/triggering/window.py +453 -0
  407. oscura/ui/__init__.py +48 -0
  408. oscura/ui/formatters.py +526 -0
  409. oscura/ui/progressive_display.py +340 -0
  410. oscura/utils/__init__.py +99 -0
  411. oscura/utils/autodetect.py +338 -0
  412. oscura/utils/buffer.py +389 -0
  413. oscura/utils/lazy.py +407 -0
  414. oscura/utils/lazy_imports.py +147 -0
  415. oscura/utils/memory.py +836 -0
  416. oscura/utils/memory_advanced.py +1326 -0
  417. oscura/utils/memory_extensions.py +465 -0
  418. oscura/utils/progressive.py +352 -0
  419. oscura/utils/windowing.py +362 -0
  420. oscura/visualization/__init__.py +321 -0
  421. oscura/visualization/accessibility.py +526 -0
  422. oscura/visualization/annotations.py +374 -0
  423. oscura/visualization/axis_scaling.py +305 -0
  424. oscura/visualization/colors.py +453 -0
  425. oscura/visualization/digital.py +337 -0
  426. oscura/visualization/eye.py +420 -0
  427. oscura/visualization/histogram.py +281 -0
  428. oscura/visualization/interactive.py +858 -0
  429. oscura/visualization/jitter.py +702 -0
  430. oscura/visualization/keyboard.py +394 -0
  431. oscura/visualization/layout.py +365 -0
  432. oscura/visualization/optimization.py +1028 -0
  433. oscura/visualization/palettes.py +446 -0
  434. oscura/visualization/plot.py +92 -0
  435. oscura/visualization/power.py +290 -0
  436. oscura/visualization/power_extended.py +626 -0
  437. oscura/visualization/presets.py +467 -0
  438. oscura/visualization/protocols.py +932 -0
  439. oscura/visualization/render.py +207 -0
  440. oscura/visualization/rendering.py +444 -0
  441. oscura/visualization/reverse_engineering.py +791 -0
  442. oscura/visualization/signal_integrity.py +808 -0
  443. oscura/visualization/specialized.py +553 -0
  444. oscura/visualization/spectral.py +811 -0
  445. oscura/visualization/styles.py +381 -0
  446. oscura/visualization/thumbnails.py +311 -0
  447. oscura/visualization/time_axis.py +351 -0
  448. oscura/visualization/waveform.py +367 -0
  449. oscura/workflow/__init__.py +13 -0
  450. oscura/workflow/dag.py +377 -0
  451. oscura/workflows/__init__.py +58 -0
  452. oscura/workflows/compliance.py +280 -0
  453. oscura/workflows/digital.py +272 -0
  454. oscura/workflows/multi_trace.py +502 -0
  455. oscura/workflows/power.py +178 -0
  456. oscura/workflows/protocol.py +492 -0
  457. oscura/workflows/reverse_engineering.py +639 -0
  458. oscura/workflows/signal_integrity.py +227 -0
  459. oscura-0.1.0.dist-info/METADATA +300 -0
  460. oscura-0.1.0.dist-info/RECORD +463 -0
  461. oscura-0.1.0.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/licenses/LICENSE +1 -1
  463. oscura-0.0.1.dist-info/METADATA +0 -63
  464. oscura-0.0.1.dist-info/RECORD +0 -5
  465. {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,492 @@
1
+ """Protocol debug workflow.
2
+
3
+ This module implements auto-detect protocol decoding with error context.
4
+
5
+
6
+ Example:
7
+ >>> import oscura as tk
8
+ >>> trace = tk.load('serial_capture.wfm')
9
+ >>> result = tk.debug_protocol(trace)
10
+ >>> print(f"Protocol: {result['protocol']}")
11
+ >>> print(f"Errors: {len(result['errors'])}")
12
+
13
+ References:
14
+ UART: TIA-232-F
15
+ I2C: NXP UM10204
16
+ SPI: Motorola SPI Block Guide
17
+ CAN: ISO 11898
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from typing import Any
23
+
24
+ import numpy as np
25
+
26
+ from oscura.core.exceptions import AnalysisError
27
+ from oscura.core.types import DigitalTrace, ProtocolPacket, WaveformTrace
28
+
29
+
30
+ def debug_protocol(
31
+ trace: WaveformTrace | DigitalTrace,
32
+ *,
33
+ protocol: str | None = None,
34
+ context_samples: int = 100,
35
+ error_types: list[str] | None = None,
36
+ decode_all: bool = False,
37
+ ) -> dict[str, Any]:
38
+ """Auto-detect and decode protocol with error context.
39
+
40
+ Automatically detects protocol type (UART, SPI, I2C, CAN) if not specified,
41
+ decodes packets, and highlights errors with surrounding context samples.
42
+
43
+ Args:
44
+ trace: Signal to decode.
45
+ protocol: Protocol type override ('UART', 'SPI', 'I2C', 'CAN', 'auto').
46
+ If None or 'auto', auto-detected.
47
+ context_samples: Number of samples to include before/after errors.
48
+ error_types: List of error types to detect. If None, detects all.
49
+ decode_all: If True, decode all packets. If False, focus on errors.
50
+
51
+ Returns:
52
+ Dictionary containing:
53
+ - protocol: Detected or specified protocol type
54
+ - baud_rate: Detected baud/clock rate (if applicable)
55
+ - packets: List of decoded ProtocolPacket objects
56
+ - errors: List of error dictionaries with context
57
+ - config: Protocol configuration used
58
+ - statistics: Decoding statistics (total packets, error count, etc.)
59
+
60
+ Raises:
61
+ AnalysisError: If protocol cannot be detected or decoded.
62
+
63
+ Example:
64
+ >>> trace = tk.load('uart_data.wfm')
65
+ >>> result = tk.debug_protocol(trace)
66
+ >>> print(f"Protocol: {result['protocol']}")
67
+ >>> print(f"Baud Rate: {result['baud_rate']}")
68
+ >>> for error in result['errors']:
69
+ ... print(f"Error at {error['timestamp']}: {error['type']}")
70
+
71
+ References:
72
+ sigrok Protocol Decoder API
73
+ UART: TIA-232-F (Serial communication)
74
+ I2C: NXP UM10204 (I2C-bus specification)
75
+ """
76
+ from oscura.inference.protocol import detect_protocol
77
+
78
+ # Convert to digital if needed
79
+ digital_trace = _to_digital(trace)
80
+
81
+ # Auto-detect protocol if not specified
82
+ if protocol is None or protocol.lower() == "auto":
83
+ detection = detect_protocol(trace, min_confidence=0.5, return_candidates=True) # type: ignore[arg-type]
84
+ protocol = detection["protocol"]
85
+ config = detection["config"]
86
+ confidence = detection["confidence"]
87
+ else:
88
+ confidence = 1.0
89
+ config = _get_default_protocol_config(protocol.upper())
90
+
91
+ protocol = protocol.upper()
92
+
93
+ # Decode based on protocol type
94
+ packets: list[ProtocolPacket] = []
95
+ errors: list[dict[str, Any]] = []
96
+
97
+ if protocol == "UART":
98
+ packets, errors = _decode_uart(digital_trace, config, context_samples, error_types, trace)
99
+ elif protocol == "SPI":
100
+ packets, errors = _decode_spi(digital_trace, config, context_samples, error_types, trace)
101
+ elif protocol == "I2C":
102
+ packets, errors = _decode_i2c(digital_trace, config, context_samples, error_types, trace)
103
+ elif protocol == "CAN":
104
+ packets, errors = _decode_can(digital_trace, config, context_samples, error_types, trace)
105
+ else:
106
+ raise AnalysisError(f"Unsupported protocol: {protocol}")
107
+
108
+ # Filter to error packets if not decoding all
109
+ if not decode_all:
110
+ packets = [p for p in packets if p.errors]
111
+
112
+ # Calculate statistics
113
+ total_packets = len(packets)
114
+ error_count = len(errors)
115
+ statistics = {
116
+ "total_packets": total_packets,
117
+ "error_count": error_count,
118
+ "error_rate": error_count / total_packets if total_packets > 0 else 0,
119
+ "confidence": confidence,
120
+ }
121
+
122
+ result = {
123
+ "protocol": protocol,
124
+ "baud_rate": config.get("baud_rate") or config.get("clock_rate"),
125
+ "packets": packets,
126
+ "errors": errors,
127
+ "config": config,
128
+ "statistics": statistics,
129
+ }
130
+
131
+ return result
132
+
133
+
134
+ def _to_digital(trace: WaveformTrace | DigitalTrace) -> DigitalTrace:
135
+ """Convert waveform trace to digital trace.
136
+
137
+ Args:
138
+ trace: Input trace.
139
+
140
+ Returns:
141
+ Digital trace.
142
+ """
143
+ if isinstance(trace, DigitalTrace):
144
+ return trace
145
+
146
+ data = trace.data
147
+ threshold = (np.max(data) + np.min(data)) / 2
148
+ digital_data = data > threshold
149
+
150
+ return DigitalTrace(
151
+ data=digital_data,
152
+ metadata=trace.metadata,
153
+ )
154
+
155
+
156
+ def _get_default_protocol_config(protocol: str) -> dict[str, Any]:
157
+ """Get default configuration for a protocol.
158
+
159
+ Args:
160
+ protocol: Protocol name.
161
+
162
+ Returns:
163
+ Default configuration dictionary.
164
+ """
165
+ configs = {
166
+ "UART": {
167
+ "baud_rate": 115200,
168
+ "data_bits": 8,
169
+ "parity": "none",
170
+ "stop_bits": 1,
171
+ },
172
+ "SPI": {
173
+ "clock_polarity": 0,
174
+ "clock_phase": 0,
175
+ "bit_order": "MSB",
176
+ },
177
+ "I2C": {
178
+ "clock_rate": 100000, # Standard mode
179
+ "address_bits": 7,
180
+ },
181
+ "CAN": {
182
+ "baud_rate": 500000,
183
+ "sample_point": 0.75,
184
+ },
185
+ }
186
+ return configs.get(protocol, {}) # type: ignore[return-value]
187
+
188
+
189
+ def _extract_context(
190
+ trace: WaveformTrace | DigitalTrace,
191
+ sample_idx: int,
192
+ context_samples: int,
193
+ ) -> WaveformTrace | DigitalTrace | None:
194
+ """Extract context samples around a point.
195
+
196
+ Args:
197
+ trace: Original trace.
198
+ sample_idx: Center sample index.
199
+ context_samples: Number of samples before and after.
200
+
201
+ Returns:
202
+ Sub-trace with context, or None if invalid.
203
+ """
204
+ data = trace.data
205
+ start = max(0, sample_idx - context_samples)
206
+ end = min(len(data), sample_idx + context_samples)
207
+
208
+ if end <= start:
209
+ return None
210
+
211
+ context_data = data[start:end]
212
+
213
+ if isinstance(trace, WaveformTrace):
214
+ return WaveformTrace(
215
+ data=context_data, # type: ignore[arg-type]
216
+ metadata=trace.metadata,
217
+ )
218
+ else:
219
+ return DigitalTrace(
220
+ data=context_data, # type: ignore[arg-type]
221
+ metadata=trace.metadata,
222
+ )
223
+
224
+
225
+ def _decode_uart(
226
+ trace: DigitalTrace,
227
+ config: dict[str, Any],
228
+ context_samples: int,
229
+ error_types: list[str] | None,
230
+ original_trace: WaveformTrace | DigitalTrace,
231
+ ) -> tuple[list[ProtocolPacket], list[dict[str, Any]]]:
232
+ """Decode UART protocol with error context.
233
+
234
+ Args:
235
+ trace: Digital trace to decode.
236
+ config: UART configuration.
237
+ context_samples: Context window size.
238
+ error_types: Error types to detect.
239
+ original_trace: Original trace for context extraction.
240
+
241
+ Returns:
242
+ Tuple of (packets, errors).
243
+ """
244
+ from oscura.analyzers.protocols.uart import UARTDecoder
245
+
246
+ baud_rate = config.get("baud_rate", 0)
247
+ data_bits = config.get("data_bits", 8)
248
+ parity = config.get("parity", "none")
249
+ stop_bits = config.get("stop_bits", 1)
250
+
251
+ decoder = UARTDecoder(
252
+ baudrate=baud_rate,
253
+ data_bits=data_bits,
254
+ parity=parity,
255
+ stop_bits=stop_bits,
256
+ )
257
+
258
+ packets = list(decoder.decode(trace))
259
+ errors: list[dict[str, Any]] = []
260
+
261
+ sample_rate = trace.metadata.sample_rate
262
+
263
+ for i, pkt in enumerate(packets):
264
+ if pkt.errors:
265
+ # Filter by error types if specified
266
+ relevant_errors = pkt.errors
267
+ if error_types:
268
+ relevant_errors = [
269
+ e for e in pkt.errors if any(t.lower() in e.lower() for t in error_types)
270
+ ]
271
+
272
+ for err in relevant_errors:
273
+ sample_idx = int(pkt.timestamp * sample_rate)
274
+ context_trace = _extract_context(original_trace, sample_idx, context_samples)
275
+
276
+ error = {
277
+ "type": err,
278
+ "timestamp": pkt.timestamp,
279
+ "packet_index": i,
280
+ "address": None,
281
+ "data": pkt.data,
282
+ "context": f"Samples {sample_idx - context_samples} to {sample_idx + context_samples}",
283
+ "context_trace": context_trace,
284
+ }
285
+ errors.append(error)
286
+
287
+ return packets, errors
288
+
289
+
290
+ def _decode_spi(
291
+ trace: DigitalTrace,
292
+ config: dict[str, Any],
293
+ context_samples: int,
294
+ error_types: list[str] | None,
295
+ original_trace: WaveformTrace | DigitalTrace,
296
+ ) -> tuple[list[ProtocolPacket], list[dict[str, Any]]]:
297
+ """Decode SPI protocol with error context.
298
+
299
+ Args:
300
+ trace: Digital trace to decode.
301
+ config: SPI configuration.
302
+ context_samples: Context window size.
303
+ error_types: Error types to detect.
304
+ original_trace: Original trace for context extraction.
305
+
306
+ Returns:
307
+ Tuple of (packets, errors).
308
+ """
309
+ from oscura.analyzers.protocols.spi import SPIDecoder
310
+
311
+ cpol = config.get("clock_polarity", 0)
312
+ cpha = config.get("clock_phase", 0)
313
+ word_size = config.get("word_size", 8)
314
+ bit_order = config.get("bit_order", "msb").lower()
315
+
316
+ decoder = SPIDecoder(
317
+ cpol=cpol,
318
+ cpha=cpha,
319
+ word_size=word_size,
320
+ bit_order=bit_order,
321
+ )
322
+
323
+ # For single-channel decode, use trace data as both clock and data
324
+ clk = trace.data
325
+ mosi = trace.data
326
+
327
+ packets = list(
328
+ decoder.decode(
329
+ clk=clk,
330
+ mosi=mosi,
331
+ sample_rate=trace.metadata.sample_rate,
332
+ )
333
+ )
334
+
335
+ errors: list[dict[str, Any]] = []
336
+ sample_rate = trace.metadata.sample_rate
337
+
338
+ for i, pkt in enumerate(packets):
339
+ if pkt.errors:
340
+ relevant_errors = pkt.errors
341
+ if error_types:
342
+ relevant_errors = [
343
+ e for e in pkt.errors if any(t.lower() in e.lower() for t in error_types)
344
+ ]
345
+
346
+ for err in relevant_errors:
347
+ sample_idx = int(pkt.timestamp * sample_rate)
348
+ context_trace = _extract_context(original_trace, sample_idx, context_samples)
349
+
350
+ error = {
351
+ "type": err,
352
+ "timestamp": pkt.timestamp,
353
+ "packet_index": i,
354
+ "mosi_data": pkt.data,
355
+ "context": f"Samples {sample_idx - context_samples} to {sample_idx + context_samples}",
356
+ "context_trace": context_trace,
357
+ }
358
+ errors.append(error)
359
+
360
+ return packets, errors
361
+
362
+
363
+ def _decode_i2c(
364
+ trace: DigitalTrace,
365
+ config: dict[str, Any],
366
+ context_samples: int,
367
+ error_types: list[str] | None,
368
+ original_trace: WaveformTrace | DigitalTrace,
369
+ ) -> tuple[list[ProtocolPacket], list[dict[str, Any]]]:
370
+ """Decode I2C protocol with error context.
371
+
372
+ Args:
373
+ trace: Digital trace to decode.
374
+ config: I2C configuration.
375
+ context_samples: Context window size.
376
+ error_types: Error types to detect.
377
+ original_trace: Original trace for context extraction.
378
+
379
+ Returns:
380
+ Tuple of (packets, errors).
381
+ """
382
+ from oscura.analyzers.protocols.i2c import I2CDecoder
383
+
384
+ address_format = config.get("address_format", "auto")
385
+
386
+ # For single-channel, assume SDA and create synthetic SCL
387
+ sda = trace.data
388
+ sample_rate = trace.metadata.sample_rate
389
+
390
+ edges = np.where(np.diff(sda.astype(int)) != 0)[0]
391
+
392
+ if len(edges) < 20:
393
+ return [], []
394
+
395
+ # Create synthetic SCL
396
+ scl = np.ones_like(sda, dtype=bool)
397
+ for i, edge in enumerate(edges):
398
+ if i % 2 == 0 and edge + 10 < len(scl):
399
+ scl[edge : edge + 10] = False
400
+
401
+ decoder = I2CDecoder(address_format=address_format)
402
+ packets = list(decoder.decode(scl=scl, sda=sda, sample_rate=sample_rate))
403
+
404
+ errors: list[dict[str, Any]] = []
405
+
406
+ for i, pkt in enumerate(packets):
407
+ if pkt.errors:
408
+ relevant_errors = pkt.errors
409
+ if error_types:
410
+ relevant_errors = [
411
+ e for e in pkt.errors if any(t.lower() in e.lower() for t in error_types)
412
+ ]
413
+
414
+ for err in relevant_errors:
415
+ sample_idx = int(pkt.timestamp * sample_rate)
416
+ context_trace = _extract_context(original_trace, sample_idx, context_samples)
417
+
418
+ addr = pkt.annotations.get("address", 0) if pkt.annotations else 0
419
+
420
+ error = {
421
+ "type": err,
422
+ "timestamp": pkt.timestamp,
423
+ "packet_index": i,
424
+ "address": addr,
425
+ "data": pkt.data,
426
+ "context": f"Samples {sample_idx - context_samples} to {sample_idx + context_samples}",
427
+ "context_trace": context_trace,
428
+ }
429
+ errors.append(error)
430
+
431
+ return packets, errors
432
+
433
+
434
+ def _decode_can(
435
+ trace: DigitalTrace,
436
+ config: dict[str, Any],
437
+ context_samples: int,
438
+ error_types: list[str] | None,
439
+ original_trace: WaveformTrace | DigitalTrace,
440
+ ) -> tuple[list[ProtocolPacket], list[dict[str, Any]]]:
441
+ """Decode CAN protocol with error context.
442
+
443
+ Args:
444
+ trace: Digital trace to decode.
445
+ config: CAN configuration.
446
+ context_samples: Context window size.
447
+ error_types: Error types to detect.
448
+ original_trace: Original trace for context extraction.
449
+
450
+ Returns:
451
+ Tuple of (packets, errors).
452
+ """
453
+ from oscura.analyzers.protocols.can import CANDecoder
454
+
455
+ bitrate = config.get("baud_rate", 500000)
456
+ sample_point = config.get("sample_point", 0.75)
457
+
458
+ decoder = CANDecoder(bitrate=bitrate, sample_point=sample_point)
459
+ packets = list(decoder.decode(trace))
460
+
461
+ errors: list[dict[str, Any]] = []
462
+ sample_rate = trace.metadata.sample_rate
463
+
464
+ for i, pkt in enumerate(packets):
465
+ if pkt.errors:
466
+ relevant_errors = pkt.errors
467
+ if error_types:
468
+ relevant_errors = [
469
+ e for e in pkt.errors if any(t.lower() in e.lower() for t in error_types)
470
+ ]
471
+
472
+ for err in relevant_errors:
473
+ sample_idx = int(pkt.timestamp * sample_rate)
474
+ context_trace = _extract_context(original_trace, sample_idx, context_samples)
475
+
476
+ arb_id = pkt.annotations.get("arbitration_id", 0) if pkt.annotations else 0
477
+
478
+ error = {
479
+ "type": err,
480
+ "timestamp": pkt.timestamp,
481
+ "packet_index": i,
482
+ "arbitration_id": arb_id,
483
+ "data": pkt.data,
484
+ "context": f"Samples {sample_idx - context_samples} to {sample_idx + context_samples}",
485
+ "context_trace": context_trace,
486
+ }
487
+ errors.append(error)
488
+
489
+ return packets, errors
490
+
491
+
492
+ __all__ = ["debug_protocol"]