oscura 0.0.1__py3-none-any.whl → 0.1.1__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.1.dist-info/METADATA +300 -0
  460. oscura-0.1.1.dist-info/RECORD +463 -0
  461. oscura-0.1.1.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.1.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.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,417 @@
1
+ """Protocol type auto-detection from signal characteristics.
2
+
3
+ This module analyzes edge timing, symbol rate, and idle levels to
4
+ automatically detect serial protocol types.
5
+
6
+
7
+ Example:
8
+ >>> import oscura as osc
9
+ >>> trace = osc.load('serial_data.wfm')
10
+ >>> result = osc.detect_protocol(trace)
11
+ >>> print(f"Protocol: {result['protocol']}")
12
+ >>> print(f"Confidence: {result['confidence']:.1%}")
13
+
14
+ References:
15
+ UART: TIA-232-F
16
+ I2C: NXP UM10204
17
+ SPI: Motorola SPI Block Guide
18
+ CAN: ISO 11898
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from collections.abc import Callable
24
+ from concurrent.futures import ThreadPoolExecutor, as_completed
25
+ from typing import TYPE_CHECKING, Any
26
+
27
+ import numpy as np
28
+
29
+ from oscura.core.exceptions import AnalysisError
30
+
31
+ if TYPE_CHECKING:
32
+ from oscura.core.types import WaveformTrace
33
+
34
+
35
+ def detect_protocol(
36
+ trace: WaveformTrace,
37
+ *,
38
+ min_confidence: float = 0.6,
39
+ return_candidates: bool = False,
40
+ parallel: bool = True,
41
+ ) -> dict[str, Any]:
42
+ """Auto-detect serial protocol type.
43
+
44
+ Analyzes signal characteristics to identify protocol:
45
+ - Edge timing and regularity
46
+ - Symbol rate detection
47
+ - Idle level analysis
48
+ - Transition patterns
49
+
50
+ Detects: UART, SPI, I2C, CAN, 1-Wire, Manchester
51
+
52
+ Args:
53
+ trace: Signal to analyze.
54
+ min_confidence: Minimum confidence threshold (0-1).
55
+ return_candidates: If True, return all candidate protocols.
56
+ parallel: If True, run protocol scoring in parallel (default True).
57
+
58
+ Returns:
59
+ Dictionary containing:
60
+ - protocol: Detected protocol name
61
+ - confidence: Detection confidence (0-1)
62
+ - config: Suggested decoder configuration dict
63
+ - characteristics: Dict with detected signal characteristics
64
+ - candidates: List of all candidates (if return_candidates=True)
65
+
66
+ Raises:
67
+ AnalysisError: If no protocol can be detected with sufficient confidence.
68
+
69
+ Example:
70
+ >>> trace = osc.load('unknown_serial.wfm')
71
+ >>> result = osc.detect_protocol(trace, return_candidates=True)
72
+ >>> print(f"Detected: {result['protocol']}")
73
+ >>> print(f"Baud rate: {result['config'].get('baud_rate', 'N/A')}")
74
+ >>> for candidate in result['candidates']:
75
+ ... print(f" {candidate['protocol']}: {candidate['confidence']:.1%}")
76
+
77
+ References:
78
+ sigrok Protocol Decoder heuristics
79
+ UART: Asynchronous, idle high, start bit low
80
+ I2C: Clock + data, open-drain, pull-up
81
+ """
82
+ # Analyze signal characteristics
83
+ characteristics = _analyze_signal_characteristics(trace)
84
+
85
+ # Define protocol detectors
86
+ protocol_detectors: list[tuple[str, Callable[[dict[str, Any]], float], dict[str, Any]]] = [
87
+ (
88
+ "UART",
89
+ _score_uart,
90
+ {
91
+ "baud_rate": characteristics.get("symbol_rate", 115200),
92
+ "data_bits": 8,
93
+ "parity": "none",
94
+ "stop_bits": 1,
95
+ },
96
+ ),
97
+ (
98
+ "SPI",
99
+ _score_spi,
100
+ {
101
+ "clock_polarity": 0,
102
+ "clock_phase": 0,
103
+ "bit_order": "MSB",
104
+ },
105
+ ),
106
+ (
107
+ "I2C",
108
+ _score_i2c,
109
+ {
110
+ "clock_rate": characteristics.get("symbol_rate", 100000),
111
+ "address_bits": 7,
112
+ },
113
+ ),
114
+ (
115
+ "CAN",
116
+ _score_can,
117
+ {
118
+ "baud_rate": characteristics.get("symbol_rate", 500000),
119
+ "sample_point": 0.75,
120
+ },
121
+ ),
122
+ ]
123
+
124
+ # Score protocols (optionally in parallel)
125
+ candidates = []
126
+
127
+ if parallel:
128
+ # Run scoring in parallel using ThreadPoolExecutor
129
+ with ThreadPoolExecutor(max_workers=len(protocol_detectors)) as executor:
130
+ # Submit all scoring tasks
131
+ future_to_protocol = {
132
+ executor.submit(scorer, characteristics): (name, config)
133
+ for name, scorer, config in protocol_detectors
134
+ }
135
+
136
+ # Collect results
137
+ for future in as_completed(future_to_protocol):
138
+ name, config = future_to_protocol[future]
139
+ try:
140
+ score = future.result()
141
+ if score > 0:
142
+ candidates.append(
143
+ {
144
+ "protocol": name,
145
+ "confidence": score,
146
+ "config": config,
147
+ }
148
+ )
149
+ except Exception:
150
+ # If a scorer fails, skip that protocol
151
+ pass
152
+ else:
153
+ # Sequential scoring (original behavior)
154
+ for name, scorer, config in protocol_detectors:
155
+ score = scorer(characteristics)
156
+ if score > 0:
157
+ candidates.append(
158
+ {
159
+ "protocol": name,
160
+ "confidence": score,
161
+ "config": config,
162
+ }
163
+ )
164
+
165
+ # Sort by confidence
166
+ candidates.sort(key=lambda x: x["confidence"], reverse=True) # type: ignore[arg-type, return-value]
167
+
168
+ if not candidates:
169
+ raise AnalysisError(
170
+ "Could not detect protocol type. Signal may be analog or unsupported protocol."
171
+ )
172
+
173
+ # Primary detection
174
+ primary = candidates[0]
175
+
176
+ if primary["confidence"] < min_confidence: # type: ignore[operator]
177
+ raise AnalysisError(
178
+ f"Protocol detection confidence too low: {primary['confidence']:.1%} "
179
+ f"(minimum: {min_confidence:.1%}). Try specifying protocol manually."
180
+ )
181
+
182
+ # Build result
183
+ result = {
184
+ "protocol": primary["protocol"],
185
+ "confidence": primary["confidence"],
186
+ "config": primary["config"],
187
+ "characteristics": characteristics,
188
+ }
189
+
190
+ if return_candidates:
191
+ result["candidates"] = candidates
192
+
193
+ return result
194
+
195
+
196
+ def _analyze_signal_characteristics(trace: WaveformTrace) -> dict[str, Any]:
197
+ """Analyze signal to extract protocol-relevant characteristics.
198
+
199
+ Args:
200
+ trace: Signal to analyze.
201
+
202
+ Returns:
203
+ Dictionary with characteristics.
204
+ """
205
+ data = trace.data
206
+ sample_rate = trace.metadata.sample_rate
207
+
208
+ # Handle empty data
209
+ if len(data) == 0:
210
+ return {
211
+ "regularity": 0,
212
+ "symbol_rate": 0,
213
+ "idle_level": "low",
214
+ "duty_cycle": 0,
215
+ "transition_density": 0,
216
+ "edge_count": 0,
217
+ }
218
+
219
+ # Detect edges
220
+ threshold = (np.max(data) + np.min(data)) / 2
221
+ digital = data > threshold
222
+ edges = np.diff(digital.astype(int))
223
+ edge_indices = np.where(edges != 0)[0]
224
+
225
+ # Edge statistics
226
+ if len(edge_indices) > 1:
227
+ edge_times = edge_indices / sample_rate
228
+ edge_intervals = np.diff(edge_times)
229
+
230
+ # Detect if edges are regular (clock-like) or irregular
231
+ if len(edge_intervals) > 10:
232
+ interval_std = np.std(edge_intervals)
233
+ interval_mean = np.mean(edge_intervals)
234
+ regularity = 1.0 - min(1.0, interval_std / (interval_mean + 1e-12))
235
+ else:
236
+ regularity = 0.5
237
+
238
+ # Estimate symbol rate from edge intervals
239
+ # For clock-based: symbol_rate = 1 / (2 * edge_interval)
240
+ # For async: symbol_rate = 1 / min_interval
241
+ median_interval = np.median(edge_intervals)
242
+ symbol_rate = 1.0 / median_interval if median_interval > 0 else 0
243
+ elif len(edge_indices) == 1:
244
+ # With exactly 1 edge, regularity is indeterminate
245
+ regularity = 0.5
246
+ symbol_rate = 0
247
+ else:
248
+ # No edges: completely DC signal, no regularity
249
+ regularity = 0
250
+ symbol_rate = 0
251
+
252
+ # Idle level (high or low)
253
+ idle_level = "high" if np.mean(data) > threshold else "low"
254
+
255
+ # Duty cycle
256
+ duty_cycle = np.sum(digital) / len(digital)
257
+
258
+ # Transition density (edges per second)
259
+ duration = len(data) / sample_rate
260
+ transition_density = len(edge_indices) / duration if duration > 0 else 0
261
+
262
+ return {
263
+ "regularity": regularity,
264
+ "symbol_rate": symbol_rate,
265
+ "idle_level": idle_level,
266
+ "duty_cycle": duty_cycle,
267
+ "transition_density": transition_density,
268
+ "edge_count": len(edge_indices),
269
+ }
270
+
271
+
272
+ def _score_uart(characteristics: dict[str, Any]) -> float:
273
+ """Score likelihood of UART protocol.
274
+
275
+ UART characteristics:
276
+ - Irregular edges (async)
277
+ - Idle high
278
+ - Low transition density
279
+
280
+ Args:
281
+ characteristics: Signal characteristics.
282
+
283
+ Returns:
284
+ Score from 0 to 1.
285
+ """
286
+ score = 0.0
287
+
288
+ # UART is asynchronous - low regularity
289
+ regularity = characteristics["regularity"]
290
+ if regularity < 0.3:
291
+ score += 0.4
292
+ elif regularity < 0.5:
293
+ score += 0.2
294
+
295
+ # UART idles high
296
+ if characteristics["idle_level"] == "high":
297
+ score += 0.3
298
+
299
+ # UART has moderate transition density
300
+ density = characteristics["transition_density"]
301
+ if 1000 < density < 1e6: # Typical UART range
302
+ score += 0.3
303
+
304
+ # Cap at 0.99 to reflect inherent uncertainty
305
+ return min(0.99, score)
306
+
307
+
308
+ def _score_spi(characteristics: dict[str, Any]) -> float:
309
+ """Score likelihood of SPI protocol.
310
+
311
+ SPI characteristics:
312
+ - Regular clock edges
313
+ - ~50% duty cycle
314
+ - High transition density
315
+
316
+ Args:
317
+ characteristics: Signal characteristics.
318
+
319
+ Returns:
320
+ Score from 0 to 1.
321
+ """
322
+ score = 0.0
323
+
324
+ # SPI has regular clock - high regularity
325
+ regularity = characteristics["regularity"]
326
+ if regularity > 0.8:
327
+ score += 0.5
328
+ elif regularity > 0.6:
329
+ score += 0.3
330
+
331
+ # SPI clock typically ~50% duty cycle
332
+ duty_cycle = characteristics["duty_cycle"]
333
+ duty_error = abs(duty_cycle - 0.5)
334
+ if duty_error < 0.1:
335
+ score += 0.3
336
+
337
+ # SPI has high transition density
338
+ density = characteristics["transition_density"]
339
+ if density > 1e5: # High speed
340
+ score += 0.2
341
+
342
+ # Cap at 0.99 to reflect inherent uncertainty
343
+ return min(0.99, score)
344
+
345
+
346
+ def _score_i2c(characteristics: dict[str, Any]) -> float:
347
+ """Score likelihood of I2C protocol.
348
+
349
+ I2C characteristics:
350
+ - Clock-like regularity
351
+ - Idle high (pull-up)
352
+ - Moderate transition density
353
+
354
+ Args:
355
+ characteristics: Signal characteristics.
356
+
357
+ Returns:
358
+ Score from 0 to 1.
359
+ """
360
+ score = 0.0
361
+
362
+ # I2C clock has regularity
363
+ regularity = characteristics["regularity"]
364
+ if regularity > 0.6:
365
+ score += 0.4
366
+
367
+ # I2C idles high
368
+ if characteristics["idle_level"] == "high":
369
+ score += 0.3
370
+
371
+ # I2C has lower transition density than SPI
372
+ density = characteristics["transition_density"]
373
+ if 1e3 < density < 1e6:
374
+ score += 0.3
375
+
376
+ # Cap at 0.99 to reflect inherent uncertainty
377
+ return min(0.99, score)
378
+
379
+
380
+ def _score_can(characteristics: dict[str, Any]) -> float:
381
+ """Score likelihood of CAN protocol.
382
+
383
+ CAN characteristics:
384
+ - Irregular edges (NRZ encoding with bit stuffing)
385
+ - Idle high (recessive)
386
+ - Moderate to high transition density
387
+
388
+ Args:
389
+ characteristics: Signal characteristics.
390
+
391
+ Returns:
392
+ Score from 0 to 1.
393
+ """
394
+ score = 0.0
395
+
396
+ # CAN has some irregularity due to bit stuffing
397
+ regularity = characteristics["regularity"]
398
+ if 0.3 < regularity < 0.7:
399
+ score += 0.4
400
+
401
+ # CAN idles high (recessive state)
402
+ if characteristics["idle_level"] == "high":
403
+ score += 0.3
404
+
405
+ # CAN has specific baud rates (typically 125k, 250k, 500k, 1M)
406
+ symbol_rate = characteristics["symbol_rate"]
407
+ common_rates = [125000, 250000, 500000, 1000000]
408
+ for rate in common_rates:
409
+ if abs(symbol_rate - rate) / rate < 0.1: # Within 10%
410
+ score += 0.3
411
+ break
412
+
413
+ # Cap at 0.99 to reflect inherent uncertainty
414
+ return min(0.99, score)
415
+
416
+
417
+ __all__ = ["detect_protocol"]