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,382 @@
1
+ """Fuzzy synchronization pattern search for corrupted data.
2
+
3
+
4
+ This module provides fuzzy pattern matching for finding sync words and markers
5
+ in noisy or corrupted logic analyzer captures, with configurable bit error
6
+ tolerance using Hamming distance.
7
+ """
8
+
9
+ from dataclasses import dataclass
10
+ from enum import Enum
11
+ from typing import Literal
12
+
13
+ import numpy as np
14
+ from numpy.typing import NDArray
15
+
16
+
17
+ class RecoveryStrategy(Enum):
18
+ """Error recovery strategies for corrupted packets.
19
+
20
+ Attributes:
21
+ NEXT_SYNC: Skip to next sync word when corruption detected
22
+ SKIP_BYTES: Skip fixed byte count and retry parsing
23
+ HEURISTIC: Use statistical packet length model for recovery
24
+ """
25
+
26
+ NEXT_SYNC = "next_sync"
27
+ SKIP_BYTES = "skip_bytes"
28
+ HEURISTIC = "heuristic"
29
+
30
+
31
+ @dataclass
32
+ class SyncMatch:
33
+ """Result from fuzzy sync pattern search.
34
+
35
+ Attributes:
36
+ index: Starting position of match in bits or bytes
37
+ matched_value: The actual value that matched (may differ from pattern)
38
+ hamming_distance: Number of bit errors in the match
39
+ confidence: Match confidence (1.0 - bit_errors/pattern_length)
40
+ pattern_length: Length of pattern in bits
41
+ """
42
+
43
+ index: int
44
+ matched_value: int
45
+ hamming_distance: int
46
+ confidence: float
47
+ pattern_length: int
48
+
49
+
50
+ @dataclass
51
+ class PacketParseResult:
52
+ """Result from robust packet parsing.
53
+
54
+ Attributes:
55
+ packets: List of successfully parsed packet data
56
+ valid: List of validity flags for each packet
57
+ errors: List of error types ('length_corruption', 'sync_lost', None)
58
+ error_positions: Byte positions where errors occurred
59
+ recovery_count: Number of times recovery was triggered
60
+ """
61
+
62
+ packets: list[bytes]
63
+ valid: list[bool]
64
+ errors: list[str | None]
65
+ error_positions: list[int]
66
+ recovery_count: int
67
+
68
+
69
+ def hamming_distance(a: int, b: int, pattern_bits: int) -> int:
70
+ """Calculate Hamming distance between two integers.
71
+
72
+ Args:
73
+ a: First integer
74
+ b: Second integer
75
+ pattern_bits: Number of bits to compare (8, 16, 32, or 64)
76
+
77
+ Returns:
78
+ Number of differing bits
79
+
80
+ Examples:
81
+ >>> hamming_distance(0b10101010, 0b10101011, 8)
82
+ 1
83
+ >>> hamming_distance(0xAA55, 0xAA54, 16)
84
+ 1
85
+ """
86
+ # XOR gives 1s where bits differ
87
+ diff = a ^ b
88
+ # Mask to pattern length
89
+ mask = (1 << pattern_bits) - 1
90
+ diff &= mask
91
+ # Count set bits (population count)
92
+ return (diff).bit_count()
93
+
94
+
95
+ def fuzzy_sync_search(
96
+ data: NDArray[np.uint8],
97
+ pattern: int,
98
+ *,
99
+ pattern_bits: Literal[8, 16, 32, 64] = 8,
100
+ max_errors: int = 2,
101
+ min_confidence: float = 0.85,
102
+ ) -> list[SyncMatch]:
103
+ """Find sync patterns with bit error tolerance using Hamming distance.
104
+
105
+ : Searches for sync words even with bit errors,
106
+ essential for recovering corrupted logic analyzer captures.
107
+
108
+ Performance targets (DAQ-001):
109
+ - ≥10 MB/s for max_errors=2
110
+ - ≥5 MB/s for max_errors=4
111
+ - ≥1 MB/s for max_errors=8
112
+
113
+ Confidence scoring (DAQ-001):
114
+ - ≥0.95 (0-1 bit errors): Highly reliable
115
+ - 0.85-0.95 (2-4 bit errors): Reliable
116
+ - <0.85 (>4 bit errors): Verify manually
117
+
118
+ Args:
119
+ data: Input byte array to search
120
+ pattern: Sync pattern to find (e.g., 0xAA55F0F0 for 32-bit)
121
+ pattern_bits: Pattern length in bits (8, 16, 32, or 64)
122
+ max_errors: Maximum tolerable bit errors (0-8)
123
+ min_confidence: Minimum confidence threshold (0.0-1.0)
124
+
125
+ Returns:
126
+ List of SyncMatch objects with position, matched value, distance,
127
+ and confidence score
128
+
129
+ Raises:
130
+ ValueError: If pattern_bits not in [8, 16, 32, 64]
131
+ ValueError: If max_errors < 0 or > 8
132
+ ValueError: If min_confidence not in [0.0, 1.0]
133
+
134
+ Examples:
135
+ >>> data = np.array([0xAA, 0x55, 0xF0, 0xF0, 0xFF], dtype=np.uint8)
136
+ >>> # Find exact match
137
+ >>> matches = fuzzy_sync_search(data, 0xAA55, pattern_bits=16)
138
+ >>> print(matches[0].confidence)
139
+ 1.0
140
+
141
+ >>> # Find with 1 bit error (0xAA54 instead of 0xAA55)
142
+ >>> data = np.array([0xAA, 0x54, 0x00], dtype=np.uint8)
143
+ >>> matches = fuzzy_sync_search(data, 0xAA55, pattern_bits=16, max_errors=2)
144
+ >>> print(matches[0].hamming_distance)
145
+ 1
146
+
147
+ References:
148
+ DAQ-001: Fuzzy Bit Pattern Search with Hamming Distance Tolerance
149
+ """
150
+ if pattern_bits not in (8, 16, 32, 64):
151
+ raise ValueError("pattern_bits must be 8, 16, 32, or 64")
152
+
153
+ if max_errors < 0 or max_errors > 8:
154
+ raise ValueError("max_errors must be in range [0, 8]")
155
+
156
+ if not 0.0 <= min_confidence <= 1.0:
157
+ raise ValueError("min_confidence must be in range [0.0, 1.0]")
158
+
159
+ pattern_bytes = pattern_bits // 8
160
+ if len(data) < pattern_bytes:
161
+ return []
162
+
163
+ matches: list[SyncMatch] = []
164
+
165
+ # Sliding window search
166
+ for i in range(len(data) - pattern_bytes + 1):
167
+ # Extract window and convert to integer
168
+ window = data[i : i + pattern_bytes]
169
+
170
+ # Convert bytes to integer (big-endian)
171
+ if pattern_bytes == 1:
172
+ value = int(window[0])
173
+ elif pattern_bytes == 2:
174
+ value = (int(window[0]) << 8) | int(window[1])
175
+ elif pattern_bytes == 4:
176
+ value = (
177
+ (int(window[0]) << 24)
178
+ | (int(window[1]) << 16)
179
+ | (int(window[2]) << 8)
180
+ | int(window[3])
181
+ )
182
+ else: # 8 bytes
183
+ value = 0
184
+ for j in range(8):
185
+ value = (value << 8) | int(window[j])
186
+
187
+ # Calculate Hamming distance
188
+ dist = hamming_distance(value, pattern, pattern_bits)
189
+
190
+ # Check if within error tolerance
191
+ if dist <= max_errors:
192
+ confidence = 1.0 - (dist / pattern_bits)
193
+
194
+ if confidence >= min_confidence:
195
+ matches.append(
196
+ SyncMatch(
197
+ index=i,
198
+ matched_value=value,
199
+ hamming_distance=dist,
200
+ confidence=confidence,
201
+ pattern_length=pattern_bits,
202
+ )
203
+ )
204
+
205
+ return matches
206
+
207
+
208
+ def parse_variable_length_packets(
209
+ data: NDArray[np.uint8],
210
+ *,
211
+ sync_pattern: int | None = None,
212
+ sync_bits: Literal[8, 16, 32, 64] = 16,
213
+ length_offset: int = 2,
214
+ length_size: int = 2,
215
+ min_packet_size: int = 4,
216
+ max_packet_size: int = 1024,
217
+ recovery_strategy: RecoveryStrategy = RecoveryStrategy.NEXT_SYNC,
218
+ skip_bytes: int = 1,
219
+ ) -> PacketParseResult:
220
+ """Parse variable-length packets with error recovery.
221
+
222
+ : Robust parsing that continues after corruption,
223
+ falling back to sync word search when length fields are corrupted.
224
+
225
+ Error detection (DAQ-002):
226
+ - Invalid if: length=0, length>max_packet_size, or length&0xFF00=0xFF00
227
+ - Suspicious if: length < min_expected or length > 90th_percentile×2 # noqa: RUF002
228
+
229
+ Recovery strategies (DAQ-002):
230
+ - next_sync: Skip to next sync word (requires sync_pattern)
231
+ - skip_bytes: Skip fixed byte count and retry
232
+ - heuristic: Use statistical packet length model
233
+
234
+ Args:
235
+ data: Input byte array containing packets
236
+ sync_pattern: Optional sync word to search for on errors
237
+ sync_bits: Sync pattern length in bits
238
+ length_offset: Byte offset to length field from start
239
+ length_size: Length field size in bytes (1 or 2)
240
+ min_packet_size: Minimum valid packet size in bytes
241
+ max_packet_size: Maximum valid packet size in bytes
242
+ recovery_strategy: Strategy to use when corruption detected
243
+ skip_bytes: Number of bytes to skip for SKIP_BYTES strategy
244
+
245
+ Returns:
246
+ PacketParseResult with parsed packets and error information
247
+
248
+ Raises:
249
+ ValueError: If length_size not 1 or 2
250
+ ValueError: If recovery_strategy is NEXT_SYNC without sync_pattern
251
+
252
+ Examples:
253
+ >>> # Simple TLV parsing with sync word
254
+ >>> data = np.array([0xAA, 0x55, 0x00, 0x04, 0x01, 0x02], dtype=np.uint8)
255
+ >>> result = parse_variable_length_packets(
256
+ ... data, sync_pattern=0xAA55, length_offset=2
257
+ ... )
258
+ >>> len(result.packets)
259
+ 1
260
+
261
+ References:
262
+ DAQ-002: Robust Variable-Length Packet Parsing with Error Recovery
263
+ """
264
+ if length_size not in (1, 2):
265
+ raise ValueError("length_size must be 1 or 2")
266
+
267
+ if recovery_strategy == RecoveryStrategy.NEXT_SYNC and sync_pattern is None:
268
+ raise ValueError("NEXT_SYNC strategy requires sync_pattern")
269
+
270
+ packets: list[bytes] = []
271
+ valid: list[bool] = []
272
+ errors: list[str | None] = []
273
+ error_positions: list[int] = []
274
+ recovery_count = 0
275
+
276
+ # Track packet lengths for heuristic recovery
277
+ packet_lengths: list[int] = []
278
+
279
+ pos = 0
280
+ while pos < len(data):
281
+ # Try to parse packet at current position
282
+
283
+ # Check if we have enough data for header
284
+ if pos + length_offset + length_size > len(data):
285
+ break
286
+
287
+ # Extract length field
288
+ length_pos = pos + length_offset
289
+ if length_size == 1:
290
+ pkt_length = int(data[length_pos])
291
+ else: # 2 bytes
292
+ pkt_length = (int(data[length_pos]) << 8) | int(data[length_pos + 1])
293
+
294
+ # Validate length field
295
+ is_valid_length = True
296
+ error_type = None
297
+
298
+ # Check for obviously corrupted lengths
299
+ if (
300
+ pkt_length == 0
301
+ or pkt_length > max_packet_size
302
+ or (length_size == 2 and (pkt_length & 0xFF00) == 0xFF00)
303
+ or pkt_length < min_packet_size
304
+ ):
305
+ is_valid_length = False
306
+ error_type = "length_corruption"
307
+
308
+ # Check suspiciously large length (heuristic)
309
+ if is_valid_length and len(packet_lengths) >= 10:
310
+ p90 = np.percentile(packet_lengths, 90)
311
+ if pkt_length > p90 * 2:
312
+ is_valid_length = False
313
+ error_type = "length_corruption"
314
+
315
+ if is_valid_length:
316
+ # Length looks good, try to extract packet
317
+ packet_end = pos + pkt_length
318
+
319
+ if packet_end <= len(data):
320
+ # Successfully extract packet
321
+ packet_data = bytes(data[pos:packet_end])
322
+ packets.append(packet_data)
323
+ valid.append(True)
324
+ errors.append(None)
325
+ packet_lengths.append(pkt_length)
326
+ pos = packet_end
327
+ else:
328
+ # Packet extends beyond data
329
+ errors.append("truncated")
330
+ error_positions.append(pos)
331
+ break
332
+ else:
333
+ # Length field corrupted - apply recovery
334
+ recovery_count += 1
335
+ error_positions.append(pos)
336
+
337
+ if recovery_strategy == RecoveryStrategy.NEXT_SYNC:
338
+ # Search for next sync word
339
+ assert sync_pattern is not None # Validated at function start
340
+ search_start = pos + 1
341
+ search_data = data[search_start:]
342
+
343
+ if len(search_data) >= sync_bits // 8:
344
+ matches = fuzzy_sync_search(
345
+ search_data,
346
+ sync_pattern,
347
+ pattern_bits=sync_bits,
348
+ max_errors=0, # type: ignore[arg-type]
349
+ )
350
+
351
+ if matches:
352
+ # Found sync, jump to it
353
+ pos = search_start + matches[0].index
354
+ errors.append("sync_lost")
355
+ else:
356
+ # No more syncs found
357
+ break
358
+ else:
359
+ break
360
+
361
+ elif recovery_strategy == RecoveryStrategy.SKIP_BYTES:
362
+ # Skip fixed bytes and retry
363
+ pos += skip_bytes
364
+ errors.append(error_type)
365
+
366
+ elif recovery_strategy == RecoveryStrategy.HEURISTIC:
367
+ # Use median packet length as guess
368
+ if packet_lengths:
369
+ guess_length = int(np.median(packet_lengths))
370
+ pos += guess_length
371
+ else:
372
+ # No history, skip minimal amount
373
+ pos += min_packet_size
374
+ errors.append(error_type)
375
+
376
+ return PacketParseResult(
377
+ packets=packets,
378
+ valid=valid,
379
+ errors=errors,
380
+ error_positions=error_positions,
381
+ recovery_count=recovery_count,
382
+ )