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,452 @@
1
+ """CAN reverse engineering session.
2
+
3
+ This module provides the main user-facing API for CAN bus reverse engineering,
4
+ centered around the CANSession class which manages message collections and
5
+ provides discovery-oriented analysis workflows.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from pathlib import Path
11
+ from typing import TYPE_CHECKING
12
+
13
+ import pandas as pd
14
+
15
+ from oscura.automotive.can.analysis import MessageAnalyzer
16
+ from oscura.automotive.can.models import (
17
+ CANMessage,
18
+ CANMessageList,
19
+ MessageAnalysis,
20
+ )
21
+ from oscura.automotive.can.patterns import (
22
+ MessagePair,
23
+ MessageSequence,
24
+ PatternAnalyzer,
25
+ TemporalCorrelation,
26
+ )
27
+
28
+ if TYPE_CHECKING:
29
+ from oscura.automotive.can.message_wrapper import CANMessageWrapper
30
+ from oscura.automotive.can.stimulus_response import StimulusResponseReport
31
+ from oscura.inference.state_machine import FiniteAutomaton
32
+
33
+ __all__ = ["CANSession"]
34
+
35
+
36
+ class CANSession:
37
+ """CAN bus reverse engineering session.
38
+
39
+ This is the primary API for discovering and analyzing unknown CAN bus
40
+ protocols. It provides:
41
+ - Message inventory and filtering
42
+ - Per-message statistical analysis
43
+ - Discovery-oriented workflows
44
+ - Hypothesis testing
45
+ - Documentation generation
46
+
47
+ Example - Discovery workflow:
48
+ >>> session = CANSession.from_log("capture.blf")
49
+ >>> inventory = session.inventory()
50
+ >>> print(inventory)
51
+ >>>
52
+ >>> # Focus on a specific message
53
+ >>> msg = session.message(0x280)
54
+ >>> analysis = msg.analyze()
55
+ >>> print(analysis.summary())
56
+ >>>
57
+ >>> # Test hypothesis
58
+ >>> hypothesis = msg.test_hypothesis(
59
+ ... signal_name="rpm",
60
+ ... start_byte=2,
61
+ ... bit_length=16,
62
+ ... scale=0.25
63
+ ... )
64
+
65
+ Example - Known protocol decoding:
66
+ >>> session = CANSession.from_log("capture.blf")
67
+ >>> from oscura.automotive.dbc import load_dbc
68
+ >>> dbc = load_dbc("vehicle.dbc")
69
+ >>> decoded = session.decode(dbc)
70
+ """
71
+
72
+ def __init__(self, messages: CANMessageList | None = None):
73
+ """Initialize CAN session.
74
+
75
+ Args:
76
+ messages: Initial message collection (optional).
77
+ """
78
+ self._messages = messages or CANMessageList()
79
+ self._analyses_cache: dict[int, MessageAnalysis] = {}
80
+
81
+ @classmethod
82
+ def from_log(cls, file_path: Path | str) -> CANSession:
83
+ """Create session from automotive log file.
84
+
85
+ Automatically detects file format (BLF, ASC, MDF, CSV) and loads.
86
+
87
+ Args:
88
+ file_path: Path to log file.
89
+
90
+ Returns:
91
+ New CANSession with loaded messages.
92
+ """
93
+ from oscura.automotive.loaders import load_automotive_log
94
+
95
+ messages = load_automotive_log(file_path)
96
+ return cls(messages=messages)
97
+
98
+ @classmethod
99
+ def from_messages(cls, messages: list[CANMessage]) -> CANSession:
100
+ """Create session from list of CAN messages.
101
+
102
+ Args:
103
+ messages: List of CAN messages.
104
+
105
+ Returns:
106
+ New CANSession.
107
+ """
108
+ msg_list = CANMessageList(messages=messages)
109
+ return cls(messages=msg_list)
110
+
111
+ def inventory(self) -> pd.DataFrame:
112
+ """Generate message inventory.
113
+
114
+ Returns a pandas DataFrame with one row per unique CAN ID, showing:
115
+ - arbitration_id: CAN ID
116
+ - count: Number of messages
117
+ - frequency_hz: Average frequency in Hz
118
+ - period_ms: Average period in milliseconds
119
+ - first_seen: Timestamp of first message
120
+ - last_seen: Timestamp of last message
121
+ - dlc: Data length (bytes)
122
+
123
+ Returns:
124
+ DataFrame with message inventory.
125
+ """
126
+ unique_ids = sorted(self._messages.unique_ids())
127
+
128
+ inventory_data = []
129
+ for arb_id in unique_ids:
130
+ filtered = self._messages.filter_by_id(arb_id)
131
+ timestamps = [msg.timestamp for msg in filtered.messages]
132
+
133
+ count = len(filtered)
134
+ first_seen = min(timestamps)
135
+ last_seen = max(timestamps)
136
+ duration = last_seen - first_seen
137
+
138
+ if duration > 0 and count > 1:
139
+ frequency_hz = (count - 1) / duration
140
+ period_ms = (duration / (count - 1)) * 1000
141
+ else:
142
+ frequency_hz = 0.0
143
+ period_ms = 0.0
144
+
145
+ # Get DLC from first message
146
+ dlc = filtered.messages[0].dlc
147
+
148
+ inventory_data.append(
149
+ {
150
+ "arbitration_id": f"0x{arb_id:03X}",
151
+ "count": count,
152
+ "frequency_hz": f"{frequency_hz:.1f}",
153
+ "period_ms": f"{period_ms:.1f}",
154
+ "first_seen": f"{first_seen:.6f}",
155
+ "last_seen": f"{last_seen:.6f}",
156
+ "dlc": dlc,
157
+ }
158
+ )
159
+
160
+ return pd.DataFrame(inventory_data)
161
+
162
+ def message(self, arbitration_id: int) -> CANMessageWrapper:
163
+ """Get message wrapper for analysis of a specific CAN ID.
164
+
165
+ Args:
166
+ arbitration_id: CAN ID to analyze.
167
+
168
+ Returns:
169
+ CANMessageWrapper for this message ID.
170
+
171
+ Raises:
172
+ ValueError: If no messages with this ID exist.
173
+ """
174
+ from oscura.automotive.can.message_wrapper import CANMessageWrapper
175
+
176
+ filtered = self._messages.filter_by_id(arbitration_id)
177
+ if not filtered.messages:
178
+ raise ValueError(f"No messages found for ID 0x{arbitration_id:03X}")
179
+
180
+ return CANMessageWrapper(self, arbitration_id)
181
+
182
+ def analyze_message(self, arbitration_id: int, force_refresh: bool = False) -> MessageAnalysis:
183
+ """Analyze a specific message ID.
184
+
185
+ Args:
186
+ arbitration_id: CAN ID to analyze.
187
+ force_refresh: Force re-analysis even if cached.
188
+
189
+ Returns:
190
+ MessageAnalysis with complete analysis.
191
+ """
192
+ # Check cache
193
+ if not force_refresh and arbitration_id in self._analyses_cache:
194
+ return self._analyses_cache[arbitration_id]
195
+
196
+ # Perform analysis
197
+ analysis = MessageAnalyzer.analyze_message_id(self._messages, arbitration_id)
198
+
199
+ # Cache result
200
+ self._analyses_cache[arbitration_id] = analysis
201
+
202
+ return analysis
203
+
204
+ def filter(
205
+ self,
206
+ min_frequency: float | None = None,
207
+ max_frequency: float | None = None,
208
+ arbitration_ids: list[int] | None = None,
209
+ time_range: tuple[float, float] | None = None,
210
+ ) -> CANSession:
211
+ """Filter messages and return new session.
212
+
213
+ Args:
214
+ min_frequency: Minimum message frequency in Hz.
215
+ max_frequency: Maximum message frequency in Hz.
216
+ arbitration_ids: List of CAN IDs to include.
217
+ time_range: Tuple of (start_time, end_time) in seconds.
218
+
219
+ Returns:
220
+ New CANSession with filtered messages.
221
+ """
222
+ filtered_messages = []
223
+
224
+ # First, filter by time range if specified
225
+ if time_range:
226
+ start_time, end_time = time_range
227
+ for msg in self._messages:
228
+ if start_time <= msg.timestamp <= end_time:
229
+ filtered_messages.append(msg)
230
+ else:
231
+ filtered_messages = list(self._messages)
232
+
233
+ # Filter by CAN IDs if specified
234
+ if arbitration_ids:
235
+ filtered_messages = [
236
+ msg for msg in filtered_messages if msg.arbitration_id in arbitration_ids
237
+ ]
238
+
239
+ # Filter by frequency if specified
240
+ if min_frequency or max_frequency:
241
+ # Group by ID and calculate frequencies
242
+ from collections import defaultdict
243
+
244
+ id_messages: dict[int, list[CANMessage]] = defaultdict(list)
245
+ for msg in filtered_messages:
246
+ id_messages[msg.arbitration_id].append(msg)
247
+
248
+ # Filter IDs by frequency
249
+ valid_ids = set()
250
+ for arb_id, msgs in id_messages.items():
251
+ if len(msgs) > 1:
252
+ timestamps = [m.timestamp for m in msgs]
253
+ duration = max(timestamps) - min(timestamps)
254
+ if duration > 0:
255
+ freq = (len(msgs) - 1) / duration
256
+
257
+ if min_frequency and freq < min_frequency:
258
+ continue
259
+ if max_frequency and freq > max_frequency:
260
+ continue
261
+
262
+ valid_ids.add(arb_id)
263
+
264
+ filtered_messages = [
265
+ msg for msg in filtered_messages if msg.arbitration_id in valid_ids
266
+ ]
267
+
268
+ return CANSession.from_messages(filtered_messages)
269
+
270
+ def unique_ids(self) -> set[int]:
271
+ """Get set of unique CAN IDs in this session.
272
+
273
+ Returns:
274
+ Set of unique arbitration IDs.
275
+ """
276
+ return self._messages.unique_ids()
277
+
278
+ def time_range(self) -> tuple[float, float]:
279
+ """Get time range of all messages.
280
+
281
+ Returns:
282
+ Tuple of (first_timestamp, last_timestamp).
283
+ """
284
+ return self._messages.time_range()
285
+
286
+ def __len__(self) -> int:
287
+ """Return total number of messages."""
288
+ return len(self._messages)
289
+
290
+ def compare_to(self, other_session: CANSession) -> StimulusResponseReport:
291
+ """Compare this session to another to detect changes.
292
+
293
+ This method is useful for stimulus-response analysis where you compare
294
+ a baseline capture (no user action) against a stimulus capture (with
295
+ user action) to identify which messages and signals respond.
296
+
297
+ Args:
298
+ other_session: Session to compare against (treated as stimulus).
299
+
300
+ Returns:
301
+ StimulusResponseReport with detected changes.
302
+
303
+ Example - Brake pedal analysis:
304
+ >>> baseline = CANSession.from_log("no_brake.blf")
305
+ >>> stimulus = CANSession.from_log("brake_pressed.blf")
306
+ >>> report = baseline.compare_to(stimulus)
307
+ >>> print(report.summary())
308
+ >>> # Show which messages changed
309
+ >>> for msg_id in report.changed_messages:
310
+ ... print(f"0x{msg_id:03X} responded to brake press")
311
+
312
+ Example - Throttle position analysis:
313
+ >>> idle = CANSession.from_log("idle.blf")
314
+ >>> throttle = CANSession.from_log("throttle_50pct.blf")
315
+ >>> report = idle.compare_to(throttle)
316
+ >>> # Examine byte-level changes
317
+ >>> for msg_id, changes in report.byte_changes.items():
318
+ ... print(f"Message 0x{msg_id:03X}:")
319
+ ... for change in changes:
320
+ ... print(f" Byte {change.byte_position}: {change.change_magnitude:.2f}")
321
+ """
322
+ from oscura.automotive.can.stimulus_response import (
323
+ StimulusResponseAnalyzer,
324
+ )
325
+
326
+ analyzer = StimulusResponseAnalyzer()
327
+ return analyzer.detect_responses(self, other_session)
328
+
329
+ def find_message_pairs(
330
+ self,
331
+ time_window_ms: float = 100,
332
+ min_occurrence: int = 3,
333
+ ) -> list[MessagePair]:
334
+ """Find message pairs that frequently occur together.
335
+
336
+ Discovers request-response patterns and coordinated message transmissions
337
+ by detecting messages that consistently appear within a short time window.
338
+
339
+ Args:
340
+ time_window_ms: Maximum time window in milliseconds.
341
+ min_occurrence: Minimum number of occurrences to report.
342
+
343
+ Returns:
344
+ List of MessagePair objects, sorted by occurrence count.
345
+
346
+ Example:
347
+ >>> session = CANSession.from_log("capture.blf")
348
+ >>> pairs = session.find_message_pairs(time_window_ms=50)
349
+ >>> for pair in pairs[:5]:
350
+ ... print(pair)
351
+ """
352
+ return PatternAnalyzer.find_message_pairs(
353
+ self, time_window_ms=time_window_ms, min_occurrence=min_occurrence
354
+ )
355
+
356
+ def find_message_sequences(
357
+ self,
358
+ max_sequence_length: int = 5,
359
+ time_window_ms: float = 500,
360
+ min_support: float = 0.7,
361
+ ) -> list[MessageSequence]:
362
+ """Find message sequences (A → B → C patterns).
363
+
364
+ Discovers multi-step control sequences or protocol handshakes by
365
+ mining sequential patterns in the message stream.
366
+
367
+ Args:
368
+ max_sequence_length: Maximum length of sequences (2-10).
369
+ time_window_ms: Maximum time window for entire sequence.
370
+ min_support: Minimum support score (0.0-1.0).
371
+
372
+ Returns:
373
+ List of MessageSequence objects, sorted by support.
374
+
375
+ Example:
376
+ >>> session = CANSession.from_log("startup.blf")
377
+ >>> sequences = session.find_message_sequences(
378
+ ... max_sequence_length=3,
379
+ ... time_window_ms=1000
380
+ ... )
381
+ >>> for seq in sequences[:5]:
382
+ ... print(seq)
383
+ """
384
+ return PatternAnalyzer.find_message_sequences(
385
+ self,
386
+ max_sequence_length=max_sequence_length,
387
+ time_window_ms=time_window_ms,
388
+ min_support=min_support,
389
+ )
390
+
391
+ def find_temporal_correlations(
392
+ self,
393
+ max_delay_ms: float = 100,
394
+ ) -> dict[tuple[int, int], TemporalCorrelation]:
395
+ """Find temporal correlations between messages.
396
+
397
+ Analyzes timing relationships to determine which messages consistently
398
+ follow others with predictable delays.
399
+
400
+ Args:
401
+ max_delay_ms: Maximum delay to consider for correlations.
402
+
403
+ Returns:
404
+ Dictionary mapping (leader_id, follower_id) to correlation info.
405
+
406
+ Example:
407
+ >>> session = CANSession.from_log("capture.blf")
408
+ >>> correlations = session.find_temporal_correlations(max_delay_ms=50)
409
+ >>> for (leader, follower), corr in correlations.items():
410
+ ... print(f"0x{leader:03X} → 0x{follower:03X}: {corr.avg_delay_ms:.2f}ms")
411
+ """
412
+ return PatternAnalyzer.find_temporal_correlations(self, max_delay_ms=max_delay_ms)
413
+
414
+ def learn_state_machine(
415
+ self, trigger_ids: list[int], context_window_ms: float = 500
416
+ ) -> FiniteAutomaton:
417
+ """Learn state machine from message sequences.
418
+
419
+ This method integrates TraceKit's state machine inference to learn
420
+ protocol state machines from CAN message sequences around trigger messages.
421
+
422
+ Args:
423
+ trigger_ids: CAN IDs that trigger sequence extraction.
424
+ context_window_ms: Time window (ms) before trigger to capture sequences.
425
+
426
+ Returns:
427
+ Learned finite automaton representing the state machine.
428
+
429
+ Example:
430
+ >>> session = CANSession.from_log("ignition_cycles.blf")
431
+ >>> automaton = session.learn_state_machine(
432
+ ... trigger_ids=[0x280],
433
+ ... context_window_ms=500
434
+ ... )
435
+ >>> print(automaton.to_dot())
436
+ """
437
+ from oscura.automotive.can.state_machine import learn_state_machine
438
+
439
+ return learn_state_machine(
440
+ session=self, trigger_ids=trigger_ids, context_window_ms=context_window_ms
441
+ )
442
+
443
+ def __repr__(self) -> str:
444
+ """Human-readable representation."""
445
+ num_messages = len(self._messages)
446
+ num_ids = len(self.unique_ids())
447
+ time_start, time_end = self.time_range()
448
+ duration = time_end - time_start
449
+
450
+ return (
451
+ f"CANSession({num_messages} messages, {num_ids} unique IDs, duration={duration:.2f}s)"
452
+ )