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,385 @@
1
+ """Core data models for CAN bus analysis.
2
+
3
+ This module defines the fundamental data structures used throughout the
4
+ automotive CAN analysis subsystem.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections.abc import Iterator
10
+ from dataclasses import dataclass, field
11
+ from typing import Any, Literal
12
+
13
+ import numpy as np
14
+
15
+ __all__ = [
16
+ "ByteAnalysis",
17
+ "CANMessage",
18
+ "CANMessageList",
19
+ "ChecksumInfo",
20
+ "CounterPattern",
21
+ "DecodedSignal",
22
+ "MessageAnalysis",
23
+ "SignalDefinition",
24
+ ]
25
+
26
+
27
+ @dataclass
28
+ class CANMessage:
29
+ """A single CAN message.
30
+
31
+ Attributes:
32
+ arbitration_id: CAN arbitration ID (11-bit or 29-bit).
33
+ timestamp: Message timestamp in seconds.
34
+ data: Message data bytes (0-8 bytes for CAN 2.0, up to 64 for CAN-FD).
35
+ is_extended: True for 29-bit extended ID.
36
+ is_fd: True for CAN-FD frame.
37
+ channel: CAN bus channel number (if available).
38
+ """
39
+
40
+ arbitration_id: int
41
+ timestamp: float
42
+ data: bytes
43
+ is_extended: bool = False
44
+ is_fd: bool = False
45
+ channel: int = 0
46
+
47
+ def __post_init__(self) -> None:
48
+ """Validate message data."""
49
+ if not isinstance(self.data, bytes):
50
+ object.__setattr__(self, "data", bytes(self.data)) # type: ignore[unreachable]
51
+
52
+ @property
53
+ def dlc(self) -> int:
54
+ """Data length code."""
55
+ return len(self.data)
56
+
57
+ def __repr__(self) -> str:
58
+ """Human-readable representation."""
59
+ id_str = (
60
+ f"0x{self.arbitration_id:03X}"
61
+ if not self.is_extended
62
+ else f"0x{self.arbitration_id:08X}"
63
+ )
64
+ data_str = self.data.hex().upper()
65
+ return f"CANMessage({id_str}, t={self.timestamp:.6f}s, data={data_str})"
66
+
67
+
68
+ @dataclass
69
+ class CANMessageList:
70
+ """A collection of CAN messages.
71
+
72
+ This class provides convenient operations on collections of CAN messages.
73
+
74
+ Attributes:
75
+ messages: List of CAN messages.
76
+ """
77
+
78
+ messages: list[CANMessage] = field(default_factory=list)
79
+
80
+ def __len__(self) -> int:
81
+ """Return number of messages."""
82
+ return len(self.messages)
83
+
84
+ def __iter__(self) -> Iterator[CANMessage]:
85
+ """Iterate over messages."""
86
+ return iter(self.messages)
87
+
88
+ def __getitem__(self, index: int | slice) -> CANMessage | list[CANMessage]:
89
+ """Get message by index."""
90
+ return self.messages[index]
91
+
92
+ def append(self, message: CANMessage) -> None:
93
+ """Add a message to the list."""
94
+ self.messages.append(message)
95
+
96
+ def filter_by_id(self, arbitration_id: int) -> CANMessageList:
97
+ """Filter messages by arbitration ID.
98
+
99
+ Args:
100
+ arbitration_id: CAN ID to filter for.
101
+
102
+ Returns:
103
+ New CANMessageList containing only messages with the specified ID.
104
+ """
105
+ filtered = [msg for msg in self.messages if msg.arbitration_id == arbitration_id]
106
+ return CANMessageList(messages=filtered)
107
+
108
+ def unique_ids(self) -> set[int]:
109
+ """Get set of unique arbitration IDs in this collection.
110
+
111
+ Returns:
112
+ Set of unique CAN IDs.
113
+ """
114
+ return {msg.arbitration_id for msg in self.messages}
115
+
116
+ def time_range(self) -> tuple[float, float]:
117
+ """Get time range of messages.
118
+
119
+ Returns:
120
+ Tuple of (first_timestamp, last_timestamp).
121
+ """
122
+ if not self.messages:
123
+ return (0.0, 0.0)
124
+ timestamps = [msg.timestamp for msg in self.messages]
125
+ return (min(timestamps), max(timestamps))
126
+
127
+
128
+ @dataclass
129
+ class SignalDefinition:
130
+ """Definition of a signal within a CAN message.
131
+
132
+ Attributes:
133
+ name: Signal name.
134
+ start_bit: Starting bit position (0-63).
135
+ length: Signal length in bits.
136
+ byte_order: Byte order ('big_endian' or 'little_endian').
137
+ value_type: Value type ('unsigned', 'signed', 'float').
138
+ scale: Scaling factor (raw_value * scale).
139
+ offset: Offset (scaled_value + offset).
140
+ unit: Physical unit (e.g., 'rpm', 'km/h', '°C').
141
+ min_value: Minimum valid value.
142
+ max_value: Maximum valid value.
143
+ comment: Description or notes.
144
+ """
145
+
146
+ name: str
147
+ start_bit: int
148
+ length: int
149
+ byte_order: Literal["big_endian", "little_endian"] = "big_endian"
150
+ value_type: Literal["unsigned", "signed", "float"] = "unsigned"
151
+ scale: float = 1.0
152
+ offset: float = 0.0
153
+ unit: str = ""
154
+ min_value: float | None = None
155
+ max_value: float | None = None
156
+ comment: str = ""
157
+
158
+ @property
159
+ def start_byte(self) -> int:
160
+ """Get starting byte position."""
161
+ return self.start_bit // 8
162
+
163
+ def extract_raw(self, data: bytes) -> int:
164
+ """Extract raw value from message data.
165
+
166
+ Args:
167
+ data: Message data bytes.
168
+
169
+ Returns:
170
+ Raw integer value.
171
+ """
172
+ # Convert bytes to bit array
173
+ bits = np.unpackbits(np.frombuffer(data, dtype=np.uint8))
174
+
175
+ # Extract signal bits
176
+ if self.byte_order == "big_endian":
177
+ signal_bits = bits[self.start_bit : self.start_bit + self.length]
178
+ else:
179
+ # Little endian: reverse byte order
180
+ byte_start = self.start_bit // 8
181
+ bit_offset = self.start_bit % 8
182
+ num_bytes = (self.length + bit_offset + 7) // 8
183
+ bytes_range = data[byte_start : byte_start + num_bytes]
184
+ reversed_bytes = bytes(reversed(bytes_range))
185
+ bits = np.unpackbits(np.frombuffer(reversed_bytes, dtype=np.uint8))
186
+ signal_bits = bits[bit_offset : bit_offset + self.length]
187
+
188
+ # Convert bits to integer
189
+ raw_value = int("".join(str(b) for b in signal_bits), 2)
190
+
191
+ # Handle signed values
192
+ if self.value_type == "signed" and raw_value >= (1 << (self.length - 1)):
193
+ raw_value -= 1 << self.length
194
+
195
+ return raw_value
196
+
197
+ def decode(self, data: bytes) -> float:
198
+ """Decode signal value from message data.
199
+
200
+ Args:
201
+ data: Message data bytes.
202
+
203
+ Returns:
204
+ Decoded physical value.
205
+ """
206
+ raw = self.extract_raw(data)
207
+ return raw * self.scale + self.offset
208
+
209
+
210
+ @dataclass
211
+ class DecodedSignal:
212
+ """A decoded signal value.
213
+
214
+ Attributes:
215
+ name: Signal name.
216
+ value: Decoded physical value.
217
+ unit: Physical unit.
218
+ timestamp: Message timestamp.
219
+ raw_value: Raw integer value before scaling.
220
+ definition: Signal definition used for decoding.
221
+ """
222
+
223
+ name: str
224
+ value: float
225
+ unit: str
226
+ timestamp: float
227
+ raw_value: int | None = None
228
+ definition: SignalDefinition | None = None
229
+
230
+ def __repr__(self) -> str:
231
+ """Human-readable representation."""
232
+ if self.unit:
233
+ return f"{self.name}: {self.value:.2f} {self.unit} @ {self.timestamp:.6f}s"
234
+ return f"{self.name}: {self.value:.2f} @ {self.timestamp:.6f}s"
235
+
236
+
237
+ @dataclass
238
+ class ByteAnalysis:
239
+ """Analysis results for a single byte position.
240
+
241
+ Attributes:
242
+ position: Byte position (0-7 for CAN 2.0).
243
+ entropy: Shannon entropy (0.0 = constant, higher = more variable).
244
+ min_value: Minimum observed value.
245
+ max_value: Maximum observed value.
246
+ mean: Mean value.
247
+ std: Standard deviation.
248
+ is_constant: True if byte never changes.
249
+ unique_values: Number of unique values observed.
250
+ most_common_value: Most frequently occurring value.
251
+ change_rate: Fraction of messages where value changes from previous.
252
+ """
253
+
254
+ position: int
255
+ entropy: float
256
+ min_value: int
257
+ max_value: int
258
+ mean: float
259
+ std: float
260
+ is_constant: bool
261
+ unique_values: int
262
+ most_common_value: int
263
+ change_rate: float
264
+
265
+
266
+ @dataclass
267
+ class CounterPattern:
268
+ """Detected counter or sequence pattern.
269
+
270
+ Attributes:
271
+ byte_position: Byte position of counter.
272
+ bit_range: Tuple of (start_bit, length) if sub-byte counter.
273
+ increment: Typical increment value (usually 1).
274
+ wraps_at: Value where counter wraps to 0.
275
+ confidence: Confidence score (0.0-1.0).
276
+ pattern_type: Type of pattern ('counter', 'sequence', 'toggle').
277
+ """
278
+
279
+ byte_position: int
280
+ bit_range: tuple[int, int] | None = None
281
+ increment: int = 1
282
+ wraps_at: int = 255
283
+ confidence: float = 0.0
284
+ pattern_type: Literal["counter", "sequence", "toggle"] = "counter"
285
+
286
+
287
+ @dataclass
288
+ class ChecksumInfo:
289
+ """Detected checksum or CRC information.
290
+
291
+ Attributes:
292
+ byte_position: Byte position of checksum.
293
+ algorithm: Detected algorithm (e.g., 'CRC-8-SAE-J1850', 'XOR', 'SUM').
294
+ polynomial: CRC polynomial (if CRC).
295
+ covered_bytes: Byte positions covered by checksum.
296
+ confidence: Confidence score (0.0-1.0).
297
+ validation_rate: Fraction of messages with valid checksum.
298
+ """
299
+
300
+ byte_position: int
301
+ algorithm: str
302
+ polynomial: int | None = None
303
+ covered_bytes: list[int] = field(default_factory=list)
304
+ confidence: float = 0.0
305
+ validation_rate: float = 0.0
306
+
307
+
308
+ @dataclass
309
+ class MessageAnalysis:
310
+ """Complete analysis of a CAN message ID.
311
+
312
+ Attributes:
313
+ arbitration_id: CAN arbitration ID.
314
+ message_count: Number of messages analyzed.
315
+ frequency_hz: Average message frequency in Hz.
316
+ period_ms: Average period in milliseconds.
317
+ period_jitter_ms: Period jitter (std dev) in milliseconds.
318
+ byte_analyses: Per-byte analysis results.
319
+ detected_counters: Detected counter patterns.
320
+ detected_checksum: Detected checksum information.
321
+ suggested_signals: Suggested signal boundaries.
322
+ correlations: Correlations with other message IDs.
323
+ """
324
+
325
+ arbitration_id: int
326
+ message_count: int
327
+ frequency_hz: float
328
+ period_ms: float
329
+ period_jitter_ms: float
330
+ byte_analyses: list[ByteAnalysis]
331
+ detected_counters: list[CounterPattern] = field(default_factory=list)
332
+ detected_checksum: ChecksumInfo | None = None
333
+ suggested_signals: list[dict[str, Any]] = field(default_factory=list)
334
+ correlations: dict[int, float] = field(default_factory=dict)
335
+
336
+ def summary(self) -> str:
337
+ """Generate human-readable summary.
338
+
339
+ Returns:
340
+ Multi-line summary string.
341
+ """
342
+ lines = [
343
+ f"=== Message 0x{self.arbitration_id:03X} Analysis ===",
344
+ f"Count: {self.message_count} messages",
345
+ f"Frequency: {self.frequency_hz:.1f} Hz ({self.period_ms:.1f} ms period, jitter: {self.period_jitter_ms:.2f} ms)",
346
+ "",
347
+ "Byte Analysis:",
348
+ ]
349
+
350
+ for ba in self.byte_analyses:
351
+ if ba.is_constant:
352
+ lines.append(f" Byte {ba.position}: CONSTANT (0x{ba.most_common_value:02X})")
353
+ else:
354
+ lines.append(
355
+ f" Byte {ba.position}: entropy={ba.entropy:.2f}, "
356
+ f"range=[0x{ba.min_value:02X}-0x{ba.max_value:02X}], "
357
+ f"change_rate={ba.change_rate:.2f}"
358
+ )
359
+
360
+ if self.detected_counters:
361
+ lines.append("")
362
+ lines.append("Detected Counters:")
363
+ for counter in self.detected_counters:
364
+ lines.append(
365
+ f" Byte {counter.byte_position}: {counter.pattern_type} "
366
+ f"(increment={counter.increment}, wraps at {counter.wraps_at}, "
367
+ f"confidence={counter.confidence:.2f})"
368
+ )
369
+
370
+ if self.detected_checksum:
371
+ lines.append("")
372
+ lines.append("Detected Checksum:")
373
+ cs = self.detected_checksum
374
+ lines.append(
375
+ f" Byte {cs.byte_position}: {cs.algorithm} "
376
+ f"(validation_rate={cs.validation_rate:.2f}, confidence={cs.confidence:.2f})"
377
+ )
378
+
379
+ if self.suggested_signals:
380
+ lines.append("")
381
+ lines.append("Suggested Signal Boundaries:")
382
+ for sig in self.suggested_signals:
383
+ lines.append(f" {sig}")
384
+
385
+ return "\n".join(lines)