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,448 @@
1
+ """CAN-FD protocol decoder.
2
+
3
+ This module implements CAN with Flexible Data-rate (CAN-FD) decoder
4
+ supporting variable data rate and extended payloads up to 64 bytes.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.analyzers.protocols.can_fd import CANFDDecoder
9
+ >>> decoder = CANFDDecoder(nominal_bitrate=500000, data_bitrate=2000000)
10
+ >>> for packet in decoder.decode(trace):
11
+ ... print(f"ID: 0x{packet.annotations['arbitration_id']:03X}")
12
+
13
+ References:
14
+ ISO 11898-1:2015 CAN-FD Specification
15
+ Bosch CAN-FD Specification v1.0
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from dataclasses import dataclass
21
+ from enum import IntEnum
22
+ from typing import TYPE_CHECKING
23
+
24
+ from oscura.analyzers.protocols.base import (
25
+ AnnotationLevel,
26
+ AsyncDecoder,
27
+ ChannelDef,
28
+ OptionDef,
29
+ )
30
+ from oscura.core.types import (
31
+ DigitalTrace,
32
+ ProtocolPacket,
33
+ TraceMetadata,
34
+ WaveformTrace,
35
+ )
36
+
37
+ if TYPE_CHECKING:
38
+ from collections.abc import Iterator
39
+
40
+ import numpy as np
41
+ from numpy.typing import NDArray
42
+
43
+
44
+ class CANFDFrameType(IntEnum):
45
+ """CAN-FD frame types."""
46
+
47
+ DATA = 0
48
+ REMOTE = 1
49
+
50
+
51
+ @dataclass
52
+ class CANFDFrame:
53
+ """Decoded CAN-FD frame.
54
+
55
+ Attributes:
56
+ arbitration_id: CAN ID (11-bit or 29-bit).
57
+ is_extended: True for 29-bit extended ID.
58
+ is_fd: True for CAN-FD frame.
59
+ brs: Bit Rate Switch flag.
60
+ esi: Error State Indicator.
61
+ dlc: Data length code (0-15).
62
+ data: Data bytes (0-64).
63
+ crc: Received CRC value.
64
+ timestamp: Frame start time in seconds.
65
+ errors: List of detected errors.
66
+ """
67
+
68
+ arbitration_id: int
69
+ is_extended: bool
70
+ is_fd: bool
71
+ brs: bool
72
+ esi: bool
73
+ dlc: int
74
+ data: bytes
75
+ crc: int
76
+ timestamp: float
77
+ errors: list[str]
78
+
79
+
80
+ # CAN-FD DLC to data length mapping
81
+ CANFD_DLC_TO_LENGTH = {
82
+ 0: 0,
83
+ 1: 1,
84
+ 2: 2,
85
+ 3: 3,
86
+ 4: 4,
87
+ 5: 5,
88
+ 6: 6,
89
+ 7: 7,
90
+ 8: 8,
91
+ 9: 12,
92
+ 10: 16,
93
+ 11: 20,
94
+ 12: 24,
95
+ 13: 32,
96
+ 14: 48,
97
+ 15: 64,
98
+ }
99
+
100
+
101
+ class CANFDDecoder(AsyncDecoder):
102
+ """CAN-FD protocol decoder.
103
+
104
+ Decodes CAN-FD frames with dual bit rate support, extended payloads,
105
+ and CRC-17/CRC-21 validation.
106
+
107
+ Attributes:
108
+ id: "can_fd"
109
+ name: "CAN-FD"
110
+ channels: [can_h, can_l] (optional differential) or [can] (single-ended)
111
+
112
+ Example:
113
+ >>> decoder = CANFDDecoder(nominal_bitrate=500000, data_bitrate=2000000)
114
+ >>> for packet in decoder.decode(trace):
115
+ ... print(f"Data ({len(packet.data)} bytes): {packet.data.hex()}")
116
+ """
117
+
118
+ id = "can_fd"
119
+ name = "CAN-FD"
120
+ longname = "CAN with Flexible Data-rate"
121
+ desc = "CAN-FD protocol decoder"
122
+
123
+ channels = [ # noqa: RUF012
124
+ ChannelDef("can", "CAN", "CAN bus signal", required=True),
125
+ ]
126
+
127
+ optional_channels = [ # noqa: RUF012
128
+ ChannelDef("can_h", "CAN_H", "CAN High differential signal", required=False),
129
+ ChannelDef("can_l", "CAN_L", "CAN Low differential signal", required=False),
130
+ ]
131
+
132
+ options = [ # noqa: RUF012
133
+ OptionDef(
134
+ "nominal_bitrate",
135
+ "Nominal bitrate",
136
+ "Arbitration phase bitrate",
137
+ default=500000,
138
+ values=None,
139
+ ),
140
+ OptionDef(
141
+ "data_bitrate",
142
+ "Data bitrate",
143
+ "Data phase bitrate",
144
+ default=2000000,
145
+ values=None,
146
+ ),
147
+ ]
148
+
149
+ annotations = [ # noqa: RUF012
150
+ ("sof", "Start of Frame"),
151
+ ("arbitration", "Arbitration field"),
152
+ ("control", "Control field"),
153
+ ("data", "Data field"),
154
+ ("crc", "CRC field"),
155
+ ("ack", "Acknowledge"),
156
+ ("eof", "End of Frame"),
157
+ ("error", "Error"),
158
+ ]
159
+
160
+ def __init__(
161
+ self,
162
+ nominal_bitrate: int = 500000,
163
+ data_bitrate: int = 2000000,
164
+ ) -> None:
165
+ """Initialize CAN-FD decoder.
166
+
167
+ Args:
168
+ nominal_bitrate: Nominal bitrate for arbitration phase (bps).
169
+ data_bitrate: Data phase bitrate for BRS frames (bps).
170
+ """
171
+ super().__init__(
172
+ baudrate=nominal_bitrate,
173
+ nominal_bitrate=nominal_bitrate,
174
+ data_bitrate=data_bitrate,
175
+ )
176
+ self._nominal_bitrate = nominal_bitrate
177
+ self._data_bitrate = data_bitrate
178
+
179
+ def decode(
180
+ self,
181
+ trace: DigitalTrace | WaveformTrace,
182
+ **channels: NDArray[np.bool_],
183
+ ) -> Iterator[ProtocolPacket]:
184
+ """Decode CAN-FD frames from trace.
185
+
186
+ Args:
187
+ trace: Input digital trace.
188
+ **channels: Additional channel data.
189
+
190
+ Yields:
191
+ Decoded CAN-FD frames as ProtocolPacket objects.
192
+
193
+ Example:
194
+ >>> decoder = CANFDDecoder(nominal_bitrate=500000)
195
+ >>> for packet in decoder.decode(trace):
196
+ ... print(f"ID: 0x{packet.annotations['arbitration_id']:X}")
197
+ """
198
+ # Convert to digital if needed
199
+ if isinstance(trace, WaveformTrace):
200
+ from oscura.analyzers.digital.extraction import to_digital
201
+
202
+ digital_trace = to_digital(trace, threshold="auto")
203
+ else:
204
+ digital_trace = trace
205
+
206
+ data = digital_trace.data
207
+ sample_rate = digital_trace.metadata.sample_rate
208
+
209
+ nominal_bit_period = sample_rate / self._nominal_bitrate
210
+ data_bit_period = sample_rate / self._data_bitrate
211
+
212
+ frame_num = 0
213
+ idx = 0
214
+
215
+ while idx < len(data):
216
+ # Look for SOF (dominant bit during idle)
217
+ sof_idx = self._find_sof(data, idx)
218
+ if sof_idx is None:
219
+ break
220
+
221
+ # Decode frame starting from SOF
222
+ frame, end_idx = self._decode_frame(
223
+ data, sof_idx, sample_rate, nominal_bit_period, data_bit_period
224
+ )
225
+
226
+ if frame is not None:
227
+ # Calculate timing
228
+ start_time = sof_idx / sample_rate
229
+
230
+ # Add annotation
231
+ self.put_annotation(
232
+ start_time,
233
+ frame.timestamp + 0.001, # Approximate end
234
+ AnnotationLevel.PACKETS,
235
+ f"ID: 0x{frame.arbitration_id:X}, {len(frame.data)} bytes",
236
+ )
237
+
238
+ # Create packet
239
+ annotations = {
240
+ "frame_num": frame_num,
241
+ "arbitration_id": frame.arbitration_id,
242
+ "is_extended": frame.is_extended,
243
+ "is_fd": frame.is_fd,
244
+ "brs": frame.brs,
245
+ "esi": frame.esi,
246
+ "dlc": frame.dlc,
247
+ "data_length": len(frame.data),
248
+ "crc": frame.crc,
249
+ }
250
+
251
+ packet = ProtocolPacket(
252
+ timestamp=start_time,
253
+ protocol="can_fd",
254
+ data=frame.data,
255
+ annotations=annotations,
256
+ errors=frame.errors,
257
+ )
258
+
259
+ yield packet
260
+ frame_num += 1
261
+
262
+ idx = end_idx if end_idx > idx else idx + int(nominal_bit_period)
263
+
264
+ def _find_sof(self, data: NDArray[np.bool_], start_idx: int) -> int | None:
265
+ """Find Start of Frame (dominant bit during recessive idle).
266
+
267
+ Args:
268
+ data: Digital data array.
269
+ start_idx: Start search index.
270
+
271
+ Returns:
272
+ Index of SOF, or None if not found.
273
+ """
274
+ # Look for recessive-to-dominant transition (1 to 0)
275
+ idx = start_idx
276
+ while idx < len(data) - 1:
277
+ if data[idx] and not data[idx + 1]:
278
+ return idx + 1
279
+ idx += 1
280
+ return None
281
+
282
+ def _decode_frame(
283
+ self,
284
+ data: NDArray[np.bool_],
285
+ sof_idx: int,
286
+ sample_rate: float,
287
+ nominal_bit_period: float,
288
+ data_bit_period: float,
289
+ ) -> tuple[CANFDFrame | None, int]:
290
+ """Decode CAN-FD frame starting from SOF.
291
+
292
+ Args:
293
+ data: Digital data array.
294
+ sof_idx: SOF index.
295
+ sample_rate: Sample rate in Hz.
296
+ nominal_bit_period: Nominal bit period in samples.
297
+ data_bit_period: Data bit period in samples.
298
+
299
+ Returns:
300
+ (frame, end_index) tuple.
301
+ """
302
+ errors = [] # type: ignore[var-annotated]
303
+ bit_idx = sof_idx
304
+ current_bit_period = nominal_bit_period
305
+
306
+ # Sample bits (simplified - ignores bit stuffing for brevity)
307
+ def sample_bits(count: int) -> list[int]:
308
+ nonlocal bit_idx
309
+ bits = []
310
+ for _ in range(count):
311
+ sample_idx = int(bit_idx + current_bit_period / 2)
312
+ if sample_idx < len(data):
313
+ bits.append(0 if data[sample_idx] else 1) # Dominant=1, Recessive=0
314
+ bit_idx += current_bit_period # type: ignore[assignment]
315
+ else:
316
+ return bits
317
+ return bits
318
+
319
+ # Arbitration field (11 bits for standard, 29 for extended)
320
+ arb_bits = sample_bits(11)
321
+ if len(arb_bits) < 11:
322
+ return None, int(bit_idx)
323
+
324
+ arbitration_id = 0
325
+ for bit in arb_bits:
326
+ arbitration_id = (arbitration_id << 1) | bit
327
+
328
+ # Check for extended frame (IDE bit)
329
+ ide_bits = sample_bits(1)
330
+ is_extended = ide_bits[0] == 1 if ide_bits else False
331
+
332
+ if is_extended:
333
+ # Extended ID: read additional 18 bits
334
+ ext_bits = sample_bits(18)
335
+ for bit in ext_bits:
336
+ arbitration_id = (arbitration_id << 1) | bit
337
+
338
+ # Control field
339
+ # FDF (EDL), res, BRS, ESI, DLC (4 bits)
340
+ ctrl_bits = sample_bits(7 if not is_extended else 6)
341
+
342
+ if len(ctrl_bits) < (7 if not is_extended else 6):
343
+ return None, int(bit_idx)
344
+
345
+ # FDF/EDL bit - first bit of control field regardless of frame type
346
+ fdf = ctrl_bits[0]
347
+ is_fd = fdf == 1
348
+ brs = ctrl_bits[2] == 1 if len(ctrl_bits) > 2 else False
349
+ esi = ctrl_bits[3] == 1 if len(ctrl_bits) > 3 else False
350
+
351
+ # DLC (4 bits)
352
+ dlc_start = 3 if not is_extended else 2
353
+ dlc_bits = (
354
+ ctrl_bits[dlc_start : dlc_start + 4]
355
+ if len(ctrl_bits) >= dlc_start + 4
356
+ else [0, 0, 0, 0]
357
+ )
358
+ dlc = 0
359
+ for bit in dlc_bits:
360
+ dlc = (dlc << 1) | bit
361
+
362
+ # Get data length from DLC
363
+ data_length = CANFD_DLC_TO_LENGTH.get(dlc, 0)
364
+
365
+ # Switch to data bitrate if BRS is set
366
+ if is_fd and brs:
367
+ current_bit_period = data_bit_period
368
+
369
+ # Data field
370
+ data_bytes = []
371
+ for _ in range(data_length):
372
+ byte_bits = sample_bits(8)
373
+ if len(byte_bits) == 8:
374
+ byte_val = 0
375
+ for bit in byte_bits:
376
+ byte_val = (byte_val << 1) | bit
377
+ data_bytes.append(byte_val)
378
+
379
+ # CRC field (CRC-17 for <=16 bytes, CRC-21 for >16 bytes)
380
+ crc_length = 17 if data_length <= 16 else 21
381
+ crc_bits = sample_bits(crc_length)
382
+ crc = 0
383
+ for bit in crc_bits:
384
+ crc = (crc << 1) | bit
385
+
386
+ # Switch back to nominal bitrate for CRC delimiter, ACK, EOF
387
+ current_bit_period = nominal_bit_period
388
+
389
+ # CRC delimiter, ACK slot, ACK delimiter, EOF (7 bits)
390
+ sample_bits(10)
391
+
392
+ # Create frame
393
+ frame = CANFDFrame(
394
+ arbitration_id=arbitration_id,
395
+ is_extended=is_extended,
396
+ is_fd=is_fd,
397
+ brs=brs,
398
+ esi=esi,
399
+ dlc=dlc,
400
+ data=bytes(data_bytes),
401
+ crc=crc,
402
+ timestamp=sof_idx / sample_rate,
403
+ errors=errors,
404
+ )
405
+
406
+ return frame, int(bit_idx)
407
+
408
+
409
+ def decode_can_fd(
410
+ data: NDArray[np.bool_] | WaveformTrace | DigitalTrace,
411
+ sample_rate: float = 1.0,
412
+ nominal_bitrate: int = 500000,
413
+ data_bitrate: int = 2000000,
414
+ ) -> list[ProtocolPacket]:
415
+ """Convenience function to decode CAN-FD frames.
416
+
417
+ Args:
418
+ data: CAN bus signal (digital array or trace).
419
+ sample_rate: Sample rate in Hz.
420
+ nominal_bitrate: Nominal bitrate in bps.
421
+ data_bitrate: Data phase bitrate in bps.
422
+
423
+ Returns:
424
+ List of decoded CAN-FD frames.
425
+
426
+ Example:
427
+ >>> packets = decode_can_fd(signal, sample_rate=100e6, nominal_bitrate=500000)
428
+ >>> for pkt in packets:
429
+ ... print(f"ID: 0x{pkt.annotations['arbitration_id']:X}")
430
+ """
431
+ decoder = CANFDDecoder(nominal_bitrate=nominal_bitrate, data_bitrate=data_bitrate)
432
+ if isinstance(data, WaveformTrace | DigitalTrace):
433
+ return list(decoder.decode(data))
434
+ else:
435
+ trace = DigitalTrace(
436
+ data=data,
437
+ metadata=TraceMetadata(sample_rate=sample_rate),
438
+ )
439
+ return list(decoder.decode(trace))
440
+
441
+
442
+ __all__ = [
443
+ "CANFD_DLC_TO_LENGTH",
444
+ "CANFDDecoder",
445
+ "CANFDFrame",
446
+ "CANFDFrameType",
447
+ "decode_can_fd",
448
+ ]