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,495 @@
1
+ """USB protocol decoder.
2
+
3
+ This module provides USB Low Speed (1.5 Mbps) and Full Speed (12 Mbps)
4
+ protocol decoding with NRZI encoding, bit stuffing, and CRC validation.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.analyzers.protocols.usb import USBDecoder
9
+ >>> decoder = USBDecoder(speed="full")
10
+ >>> for packet in decoder.decode(dp=dp, dm=dm):
11
+ ... print(f"PID: {packet.annotations['pid_name']}")
12
+
13
+ References:
14
+ USB 2.0 Specification (usb.org)
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from enum import Enum
20
+ from typing import TYPE_CHECKING, Literal
21
+
22
+ from oscura.analyzers.protocols.base import (
23
+ AnnotationLevel,
24
+ ChannelDef,
25
+ OptionDef,
26
+ SyncDecoder,
27
+ )
28
+ from oscura.core.types import DigitalTrace, ProtocolPacket
29
+
30
+ if TYPE_CHECKING:
31
+ from collections.abc import Iterator
32
+
33
+ import numpy as np
34
+ from numpy.typing import NDArray
35
+
36
+
37
+ class USBSpeed(Enum):
38
+ """USB speed modes."""
39
+
40
+ LOW_SPEED = 1_500_000 # 1.5 Mbps
41
+ FULL_SPEED = 12_000_000 # 12 Mbps
42
+
43
+
44
+ class USBPID(Enum):
45
+ """USB Packet Identifiers."""
46
+
47
+ # Token PIDs
48
+ OUT = 0b0001
49
+ IN = 0b1001
50
+ SOF = 0b0101
51
+ SETUP = 0b1101
52
+ # Data PIDs
53
+ DATA0 = 0b0011
54
+ DATA1 = 0b1011
55
+ DATA2 = 0b0111
56
+ MDATA = 0b1111
57
+ # Handshake PIDs
58
+ ACK = 0b0010
59
+ NAK = 0b1010
60
+ STALL = 0b1110
61
+ NYET = 0b0110
62
+ # Special PIDs
63
+ PRE = 0b1100
64
+ ERR = 0b1100
65
+ SPLIT = 0b1000
66
+ PING = 0b0100
67
+
68
+
69
+ # PID names for display
70
+ PID_NAMES = {
71
+ 0b0001: "OUT",
72
+ 0b1001: "IN",
73
+ 0b0101: "SOF",
74
+ 0b1101: "SETUP",
75
+ 0b0011: "DATA0",
76
+ 0b1011: "DATA1",
77
+ 0b0111: "DATA2",
78
+ 0b1111: "MDATA",
79
+ 0b0010: "ACK",
80
+ 0b1010: "NAK",
81
+ 0b1110: "STALL",
82
+ 0b0110: "NYET",
83
+ 0b1100: "PRE/ERR",
84
+ 0b1000: "SPLIT",
85
+ 0b0100: "PING",
86
+ }
87
+
88
+
89
+ class USBDecoder(SyncDecoder):
90
+ """USB protocol decoder.
91
+
92
+ Decodes USB Low Speed and Full Speed transactions including
93
+ NRZI decoding, bit unstuffing, and CRC validation.
94
+
95
+ Attributes:
96
+ id: "usb"
97
+ name: "USB"
98
+ channels: [dp, dm] (required)
99
+
100
+ Example:
101
+ >>> decoder = USBDecoder(speed="full")
102
+ >>> for packet in decoder.decode(dp=dp, dm=dm, sample_rate=100e6):
103
+ ... print(f"PID: {packet.annotations['pid_name']}")
104
+ """
105
+
106
+ id = "usb"
107
+ name = "USB"
108
+ longname = "Universal Serial Bus"
109
+ desc = "USB Low/Full Speed protocol decoder"
110
+
111
+ channels = [ # noqa: RUF012
112
+ ChannelDef("dp", "D+", "USB D+ signal", required=True),
113
+ ChannelDef("dm", "D-", "USB D- signal", required=True),
114
+ ]
115
+
116
+ optional_channels = [] # noqa: RUF012
117
+
118
+ options = [ # noqa: RUF012
119
+ OptionDef("speed", "Speed", "USB speed", default="full", values=["low", "full"]),
120
+ ]
121
+
122
+ annotations = [ # noqa: RUF012
123
+ ("sync", "SYNC field"),
124
+ ("pid", "Packet ID"),
125
+ ("data", "Data payload"),
126
+ ("crc", "CRC field"),
127
+ ("eop", "End of Packet"),
128
+ ("error", "Error"),
129
+ ]
130
+
131
+ def __init__(
132
+ self,
133
+ speed: Literal["low", "full"] = "full",
134
+ ) -> None:
135
+ """Initialize USB decoder.
136
+
137
+ Args:
138
+ speed: USB speed ("low" or "full").
139
+ """
140
+ super().__init__(speed=speed)
141
+ self._speed = USBSpeed.LOW_SPEED if speed == "low" else USBSpeed.FULL_SPEED
142
+
143
+ def decode( # type: ignore[override]
144
+ self,
145
+ trace: DigitalTrace | None = None,
146
+ *,
147
+ dp: NDArray[np.bool_] | None = None,
148
+ dm: NDArray[np.bool_] | None = None,
149
+ sample_rate: float = 1.0,
150
+ ) -> Iterator[ProtocolPacket]:
151
+ """Decode USB packets.
152
+
153
+ Args:
154
+ trace: Optional primary trace.
155
+ dp: D+ signal.
156
+ dm: D- signal.
157
+ sample_rate: Sample rate in Hz.
158
+
159
+ Yields:
160
+ Decoded USB packets as ProtocolPacket objects.
161
+
162
+ Example:
163
+ >>> decoder = USBDecoder(speed="full")
164
+ >>> for pkt in decoder.decode(dp=dp, dm=dm, sample_rate=100e6):
165
+ ... print(f"Address: {pkt.annotations.get('address', 'N/A')}")
166
+ """
167
+ if dp is None or dm is None:
168
+ return
169
+
170
+ n_samples = min(len(dp), len(dm))
171
+ dp = dp[:n_samples]
172
+ dm = dm[:n_samples]
173
+
174
+ # Decode differential signal to single-ended
175
+ # J state: LS: D-=1, D+=0; FS: D+=1, D-=0
176
+ # K state: LS: D+=1, D-=0; FS: D-=1, D+=0
177
+ # SE0: D+=0, D-=0 (idle/EOP)
178
+ # SE1: D+=1, D-=1 (illegal)
179
+
180
+ if self._speed == USBSpeed.LOW_SPEED:
181
+ # Low speed: J = D-, K = D+
182
+ diff_signal = ~dp & dm # J=1, K=0
183
+ else:
184
+ # Full speed: J = D+, K = D-
185
+ diff_signal = dp & ~dm # J=1, K=0
186
+
187
+ # Find packet boundaries (SYNC followed by data, ending with EOP)
188
+ # EOP is SE0 for at least 2 bit times
189
+
190
+ bit_period = sample_rate / self._speed.value
191
+ int(2 * bit_period)
192
+
193
+ # Find SE0 regions (both D+ and D- are 0)
194
+ se0 = ~dp & ~dm
195
+
196
+ trans_num = 0
197
+ idx = 0
198
+
199
+ while idx < len(diff_signal):
200
+ # Look for SYNC pattern in NRZI-decoded signal
201
+ # SYNC is 0x80 (10000000) after NRZI and bit unstuffing
202
+ # In NRZI: no transition = 1, transition = 0
203
+
204
+ # Decode NRZI starting from current position
205
+ nrzi_start = self._find_sync_pattern(diff_signal, idx, bit_period)
206
+ if nrzi_start is None:
207
+ break
208
+
209
+ # Extract packet bits
210
+ packet_bits, bit_errors = self._extract_packet_bits(
211
+ diff_signal, nrzi_start, bit_period, se0
212
+ )
213
+
214
+ if len(packet_bits) < 16: # Minimum: SYNC(8) + PID(8)
215
+ idx = nrzi_start + int(bit_period)
216
+ continue
217
+
218
+ # Skip SYNC field (first 8 bits)
219
+ data_bits = packet_bits[8:]
220
+
221
+ # Extract PID (8 bits)
222
+ if len(data_bits) < 8:
223
+ idx = nrzi_start + int(bit_period)
224
+ continue
225
+
226
+ pid_byte = self._bits_to_byte(data_bits[:8])
227
+ pid_value = pid_byte & 0x0F
228
+ pid_check = (pid_byte >> 4) & 0x0F
229
+
230
+ errors = list(bit_errors)
231
+
232
+ # Validate PID (upper 4 bits should be complement of lower 4 bits)
233
+ if pid_value ^ pid_check != 0x0F:
234
+ errors.append("PID check failed")
235
+
236
+ pid_name = PID_NAMES.get(pid_value, f"UNKNOWN(0x{pid_value:X})")
237
+
238
+ # Extract payload based on PID type
239
+ payload_bits = data_bits[8:]
240
+ payload_bytes = []
241
+ annotations = {
242
+ "transaction_num": trans_num,
243
+ "pid_value": pid_value,
244
+ "pid_name": pid_name,
245
+ }
246
+
247
+ # Token packets: OUT, IN, SOF, SETUP
248
+ if pid_value in [0b0001, 0b1001, 0b1101]: # OUT, IN, SETUP
249
+ if len(payload_bits) >= 16: # 11-bit (addr+endp) + 5-bit CRC
250
+ addr_endp = self._bits_to_value(payload_bits[:11])
251
+ address = addr_endp & 0x7F
252
+ endpoint = (addr_endp >> 7) & 0x0F
253
+ crc5 = self._bits_to_value(payload_bits[11:16])
254
+
255
+ # Validate CRC5
256
+ expected_crc5 = self._crc5(addr_endp)
257
+ if crc5 != expected_crc5:
258
+ errors.append("CRC5 error")
259
+
260
+ annotations["address"] = address
261
+ annotations["endpoint"] = endpoint
262
+
263
+ elif pid_value == 0b0101: # SOF
264
+ if len(payload_bits) >= 16: # 11-bit frame number + 5-bit CRC
265
+ frame_num = self._bits_to_value(payload_bits[:11])
266
+ crc5 = self._bits_to_value(payload_bits[11:16])
267
+ annotations["frame_number"] = frame_num
268
+
269
+ # Data packets: DATA0, DATA1, DATA2, MDATA
270
+ elif pid_value in [0b0011, 0b1011, 0b0111, 0b1111]:
271
+ if len(payload_bits) >= 16: # At least CRC16
272
+ # Data payload + CRC16
273
+ data_bit_count = len(payload_bits) - 16
274
+ if data_bit_count >= 0:
275
+ for i in range(0, data_bit_count, 8):
276
+ if i + 8 <= data_bit_count:
277
+ byte_val = self._bits_to_byte(payload_bits[i : i + 8])
278
+ payload_bytes.append(byte_val)
279
+
280
+ self._bits_to_value(payload_bits[-16:])
281
+ annotations["data_length"] = len(payload_bytes)
282
+
283
+ # Calculate timing
284
+ start_time = nrzi_start / sample_rate
285
+ end_time = (nrzi_start + len(packet_bits) * bit_period) / sample_rate
286
+
287
+ # Add annotation
288
+ self.put_annotation(
289
+ start_time,
290
+ end_time,
291
+ AnnotationLevel.PACKETS,
292
+ f"{pid_name}",
293
+ )
294
+
295
+ # Create packet
296
+ packet = ProtocolPacket(
297
+ timestamp=start_time,
298
+ protocol="usb",
299
+ data=bytes(payload_bytes),
300
+ annotations=annotations,
301
+ errors=errors,
302
+ )
303
+
304
+ yield packet
305
+
306
+ trans_num += 1
307
+ idx = int(nrzi_start + len(packet_bits) * bit_period)
308
+
309
+ def _find_sync_pattern(
310
+ self,
311
+ signal: NDArray[np.bool_],
312
+ start_idx: int,
313
+ bit_period: float,
314
+ ) -> int | None:
315
+ """Find USB SYNC pattern (KJKJKJKK in differential).
316
+
317
+ Args:
318
+ signal: Differential signal.
319
+ start_idx: Start search index.
320
+ bit_period: Bit period in samples.
321
+
322
+ Returns:
323
+ Index of bit center of first SYNC bit, or None if not found.
324
+ """
325
+ # SYNC pattern is 00000001 in data
326
+ # In NRZI: 0 = transition, 1 = no transition
327
+ # So SYNC has 6 transitions in first 7 bits, then 1 non-transition
328
+ # Look for alternating pattern
329
+
330
+ min_transitions = 5
331
+ idx = start_idx
332
+ int(bit_period)
333
+
334
+ while idx < len(signal) - int(9 * bit_period):
335
+ # Sample 8 consecutive bits at bit centers
336
+ # Bit centers are at: idx, idx+period, idx+2*period, ...
337
+ samples = []
338
+ for i in range(8):
339
+ sample_idx = int(idx + i * bit_period)
340
+ if sample_idx >= len(signal):
341
+ break
342
+ samples.append(signal[sample_idx])
343
+
344
+ if len(samples) < 8:
345
+ break
346
+
347
+ # Count transitions
348
+ trans_count = sum(1 for i in range(7) if samples[i] != samples[i + 1])
349
+
350
+ # SYNC should have at least 5-6 transitions
351
+ if trans_count >= min_transitions:
352
+ return idx # Return first bit center
353
+
354
+ idx += int(bit_period / 4) # Scan at quarter-bit resolution
355
+
356
+ return None
357
+
358
+ def _extract_packet_bits(
359
+ self,
360
+ signal: NDArray[np.bool_],
361
+ start_idx: int,
362
+ bit_period: float,
363
+ se0: NDArray[np.bool_],
364
+ ) -> tuple[list[int], list[str]]:
365
+ """Extract and decode packet bits with NRZI and unstuffing.
366
+
367
+ Args:
368
+ signal: NRZI-encoded differential signal.
369
+ start_idx: Packet start index (bit center of first bit).
370
+ bit_period: Bit period in samples.
371
+ se0: SE0 detection array.
372
+
373
+ Returns:
374
+ (bits, errors) tuple.
375
+ """
376
+ bits = []
377
+ errors = [] # type: ignore[var-annotated]
378
+ stuff_count = 0
379
+
380
+ max_bits = 1024 # Prevent infinite loops
381
+
382
+ # Track previous signal value for NRZI decoding
383
+ prev_sample_idx = max(0, int(start_idx - bit_period))
384
+ prev_val = signal[prev_sample_idx]
385
+
386
+ for bit_num in range(max_bits):
387
+ sample_idx = int(start_idx + bit_num * bit_period)
388
+ if sample_idx >= len(signal):
389
+ break
390
+
391
+ # Check for EOP (SE0)
392
+ if se0[sample_idx]:
393
+ break
394
+
395
+ curr_val = signal[sample_idx]
396
+
397
+ # NRZI decode: no transition = 1, transition = 0
398
+ if curr_val == prev_val:
399
+ bit = 1
400
+ else:
401
+ bit = 0
402
+
403
+ # Bit unstuffing: after six consecutive 1s, the next 0 is a stuff bit
404
+ if bit == 1:
405
+ stuff_count += 1
406
+ bits.append(bit)
407
+ elif stuff_count == 6:
408
+ # This is a stuff bit (should be 0), skip it
409
+ stuff_count = 0
410
+ # Don't append stuff bit
411
+ else:
412
+ # Normal 0 bit
413
+ stuff_count = 0
414
+ bits.append(bit)
415
+
416
+ # Update for next bit
417
+ prev_val = curr_val
418
+
419
+ return bits, errors
420
+
421
+ def _bits_to_byte(self, bits: list[int]) -> int:
422
+ """Convert 8 bits to byte (LSB first).
423
+
424
+ Args:
425
+ bits: List of 8 bits.
426
+
427
+ Returns:
428
+ Byte value.
429
+ """
430
+ value = 0
431
+ for i in range(min(8, len(bits))):
432
+ value |= bits[i] << i
433
+ return value
434
+
435
+ def _bits_to_value(self, bits: list[int]) -> int:
436
+ """Convert bits to integer (LSB first).
437
+
438
+ Args:
439
+ bits: List of bits.
440
+
441
+ Returns:
442
+ Integer value.
443
+ """
444
+ value = 0
445
+ for i, bit in enumerate(bits):
446
+ value |= bit << i
447
+ return value
448
+
449
+ def _crc5(self, data: int) -> int:
450
+ """Compute USB CRC5.
451
+
452
+ Args:
453
+ data: 11-bit data value.
454
+
455
+ Returns:
456
+ 5-bit CRC.
457
+ """
458
+ # CRC-5-USB polynomial: x^5 + x^2 + 1 (0x05)
459
+ crc = 0x1F
460
+ for i in range(11):
461
+ bit = (data >> i) & 1
462
+ if (crc & 1) ^ bit:
463
+ crc = ((crc >> 1) ^ 0x14) & 0x1F
464
+ else:
465
+ crc >>= 1
466
+ return crc ^ 0x1F
467
+
468
+
469
+ def decode_usb(
470
+ dp: NDArray[np.bool_],
471
+ dm: NDArray[np.bool_],
472
+ sample_rate: float = 1.0,
473
+ speed: Literal["low", "full"] = "full",
474
+ ) -> list[ProtocolPacket]:
475
+ """Convenience function to decode USB packets.
476
+
477
+ Args:
478
+ dp: D+ signal.
479
+ dm: D- signal.
480
+ sample_rate: Sample rate in Hz.
481
+ speed: USB speed ("low" or "full").
482
+
483
+ Returns:
484
+ List of decoded USB packets.
485
+
486
+ Example:
487
+ >>> packets = decode_usb(dp, dm, sample_rate=100e6, speed="full")
488
+ >>> for pkt in packets:
489
+ ... print(f"PID: {pkt.annotations['pid_name']}")
490
+ """
491
+ decoder = USBDecoder(speed=speed)
492
+ return list(decoder.decode(dp=dp, dm=dm, sample_rate=sample_rate))
493
+
494
+
495
+ __all__ = ["PID_NAMES", "USBPID", "USBDecoder", "USBSpeed", "decode_usb"]
@@ -0,0 +1,63 @@
1
+ """Signal integrity analysis module.
2
+
3
+ This module provides S-parameter handling, channel de-embedding,
4
+ and equalization functions for high-speed serial link analysis.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.analyzers.signal_integrity import (
9
+ ... load_touchstone, deembed, ffe_equalize, return_loss
10
+ ... )
11
+ >>> s_params = load_touchstone("cable.s2p")
12
+ >>> clean_trace = deembed(trace, s_params)
13
+ >>> rl = return_loss(s_params, frequency=1e9)
14
+
15
+ References:
16
+ Touchstone 2.0 File Format Specification
17
+ IEEE 370-2020: Standard for Electrical Characterization of PCBs
18
+ """
19
+
20
+ from oscura.analyzers.signal_integrity.embedding import (
21
+ cascade_deembed,
22
+ deembed,
23
+ embed,
24
+ )
25
+ from oscura.analyzers.signal_integrity.equalization import (
26
+ CTLEResult,
27
+ DFEResult,
28
+ FFEResult,
29
+ ctle_equalize,
30
+ dfe_equalize,
31
+ ffe_equalize,
32
+ optimize_ffe,
33
+ )
34
+ from oscura.analyzers.signal_integrity.sparams import (
35
+ SParameterData,
36
+ abcd_to_s,
37
+ insertion_loss,
38
+ load_touchstone,
39
+ return_loss,
40
+ s_to_abcd,
41
+ )
42
+
43
+ __all__ = [
44
+ "CTLEResult",
45
+ "DFEResult",
46
+ # Equalization
47
+ "FFEResult",
48
+ # S-parameters
49
+ "SParameterData",
50
+ "abcd_to_s",
51
+ "cascade_deembed",
52
+ "ctle_equalize",
53
+ # Embedding
54
+ "deembed",
55
+ "dfe_equalize",
56
+ "embed",
57
+ "ffe_equalize",
58
+ "insertion_loss",
59
+ "load_touchstone",
60
+ "optimize_ffe",
61
+ "return_loss",
62
+ "s_to_abcd",
63
+ ]