oscura 0.0.1__py3-none-any.whl → 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. oscura/__init__.py +813 -8
  2. oscura/__main__.py +392 -0
  3. oscura/analyzers/__init__.py +37 -0
  4. oscura/analyzers/digital/__init__.py +177 -0
  5. oscura/analyzers/digital/bus.py +691 -0
  6. oscura/analyzers/digital/clock.py +805 -0
  7. oscura/analyzers/digital/correlation.py +720 -0
  8. oscura/analyzers/digital/edges.py +632 -0
  9. oscura/analyzers/digital/extraction.py +413 -0
  10. oscura/analyzers/digital/quality.py +878 -0
  11. oscura/analyzers/digital/signal_quality.py +877 -0
  12. oscura/analyzers/digital/thresholds.py +708 -0
  13. oscura/analyzers/digital/timing.py +1104 -0
  14. oscura/analyzers/eye/__init__.py +46 -0
  15. oscura/analyzers/eye/diagram.py +434 -0
  16. oscura/analyzers/eye/metrics.py +555 -0
  17. oscura/analyzers/jitter/__init__.py +83 -0
  18. oscura/analyzers/jitter/ber.py +333 -0
  19. oscura/analyzers/jitter/decomposition.py +759 -0
  20. oscura/analyzers/jitter/measurements.py +413 -0
  21. oscura/analyzers/jitter/spectrum.py +220 -0
  22. oscura/analyzers/measurements.py +40 -0
  23. oscura/analyzers/packet/__init__.py +171 -0
  24. oscura/analyzers/packet/daq.py +1077 -0
  25. oscura/analyzers/packet/metrics.py +437 -0
  26. oscura/analyzers/packet/parser.py +327 -0
  27. oscura/analyzers/packet/payload.py +2156 -0
  28. oscura/analyzers/packet/payload_analysis.py +1312 -0
  29. oscura/analyzers/packet/payload_extraction.py +236 -0
  30. oscura/analyzers/packet/payload_patterns.py +670 -0
  31. oscura/analyzers/packet/stream.py +359 -0
  32. oscura/analyzers/patterns/__init__.py +266 -0
  33. oscura/analyzers/patterns/clustering.py +1036 -0
  34. oscura/analyzers/patterns/discovery.py +539 -0
  35. oscura/analyzers/patterns/learning.py +797 -0
  36. oscura/analyzers/patterns/matching.py +1091 -0
  37. oscura/analyzers/patterns/periodic.py +650 -0
  38. oscura/analyzers/patterns/sequences.py +767 -0
  39. oscura/analyzers/power/__init__.py +116 -0
  40. oscura/analyzers/power/ac_power.py +391 -0
  41. oscura/analyzers/power/basic.py +383 -0
  42. oscura/analyzers/power/conduction.py +314 -0
  43. oscura/analyzers/power/efficiency.py +297 -0
  44. oscura/analyzers/power/ripple.py +356 -0
  45. oscura/analyzers/power/soa.py +372 -0
  46. oscura/analyzers/power/switching.py +479 -0
  47. oscura/analyzers/protocol/__init__.py +150 -0
  48. oscura/analyzers/protocols/__init__.py +150 -0
  49. oscura/analyzers/protocols/base.py +500 -0
  50. oscura/analyzers/protocols/can.py +620 -0
  51. oscura/analyzers/protocols/can_fd.py +448 -0
  52. oscura/analyzers/protocols/flexray.py +405 -0
  53. oscura/analyzers/protocols/hdlc.py +399 -0
  54. oscura/analyzers/protocols/i2c.py +368 -0
  55. oscura/analyzers/protocols/i2s.py +296 -0
  56. oscura/analyzers/protocols/jtag.py +393 -0
  57. oscura/analyzers/protocols/lin.py +445 -0
  58. oscura/analyzers/protocols/manchester.py +333 -0
  59. oscura/analyzers/protocols/onewire.py +501 -0
  60. oscura/analyzers/protocols/spi.py +334 -0
  61. oscura/analyzers/protocols/swd.py +325 -0
  62. oscura/analyzers/protocols/uart.py +393 -0
  63. oscura/analyzers/protocols/usb.py +495 -0
  64. oscura/analyzers/signal_integrity/__init__.py +63 -0
  65. oscura/analyzers/signal_integrity/embedding.py +294 -0
  66. oscura/analyzers/signal_integrity/equalization.py +370 -0
  67. oscura/analyzers/signal_integrity/sparams.py +484 -0
  68. oscura/analyzers/spectral/__init__.py +53 -0
  69. oscura/analyzers/spectral/chunked.py +273 -0
  70. oscura/analyzers/spectral/chunked_fft.py +571 -0
  71. oscura/analyzers/spectral/chunked_wavelet.py +391 -0
  72. oscura/analyzers/spectral/fft.py +92 -0
  73. oscura/analyzers/statistical/__init__.py +250 -0
  74. oscura/analyzers/statistical/checksum.py +923 -0
  75. oscura/analyzers/statistical/chunked_corr.py +228 -0
  76. oscura/analyzers/statistical/classification.py +778 -0
  77. oscura/analyzers/statistical/entropy.py +1113 -0
  78. oscura/analyzers/statistical/ngrams.py +614 -0
  79. oscura/analyzers/statistics/__init__.py +119 -0
  80. oscura/analyzers/statistics/advanced.py +885 -0
  81. oscura/analyzers/statistics/basic.py +263 -0
  82. oscura/analyzers/statistics/correlation.py +630 -0
  83. oscura/analyzers/statistics/distribution.py +298 -0
  84. oscura/analyzers/statistics/outliers.py +463 -0
  85. oscura/analyzers/statistics/streaming.py +93 -0
  86. oscura/analyzers/statistics/trend.py +520 -0
  87. oscura/analyzers/validation.py +598 -0
  88. oscura/analyzers/waveform/__init__.py +36 -0
  89. oscura/analyzers/waveform/measurements.py +943 -0
  90. oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
  91. oscura/analyzers/waveform/spectral.py +1689 -0
  92. oscura/analyzers/waveform/wavelets.py +298 -0
  93. oscura/api/__init__.py +62 -0
  94. oscura/api/dsl.py +538 -0
  95. oscura/api/fluent.py +571 -0
  96. oscura/api/operators.py +498 -0
  97. oscura/api/optimization.py +392 -0
  98. oscura/api/profiling.py +396 -0
  99. oscura/automotive/__init__.py +73 -0
  100. oscura/automotive/can/__init__.py +52 -0
  101. oscura/automotive/can/analysis.py +356 -0
  102. oscura/automotive/can/checksum.py +250 -0
  103. oscura/automotive/can/correlation.py +212 -0
  104. oscura/automotive/can/discovery.py +355 -0
  105. oscura/automotive/can/message_wrapper.py +375 -0
  106. oscura/automotive/can/models.py +385 -0
  107. oscura/automotive/can/patterns.py +381 -0
  108. oscura/automotive/can/session.py +452 -0
  109. oscura/automotive/can/state_machine.py +300 -0
  110. oscura/automotive/can/stimulus_response.py +461 -0
  111. oscura/automotive/dbc/__init__.py +15 -0
  112. oscura/automotive/dbc/generator.py +156 -0
  113. oscura/automotive/dbc/parser.py +146 -0
  114. oscura/automotive/dtc/__init__.py +30 -0
  115. oscura/automotive/dtc/database.py +3036 -0
  116. oscura/automotive/j1939/__init__.py +14 -0
  117. oscura/automotive/j1939/decoder.py +745 -0
  118. oscura/automotive/loaders/__init__.py +35 -0
  119. oscura/automotive/loaders/asc.py +98 -0
  120. oscura/automotive/loaders/blf.py +77 -0
  121. oscura/automotive/loaders/csv_can.py +136 -0
  122. oscura/automotive/loaders/dispatcher.py +136 -0
  123. oscura/automotive/loaders/mdf.py +331 -0
  124. oscura/automotive/loaders/pcap.py +132 -0
  125. oscura/automotive/obd/__init__.py +14 -0
  126. oscura/automotive/obd/decoder.py +707 -0
  127. oscura/automotive/uds/__init__.py +48 -0
  128. oscura/automotive/uds/decoder.py +265 -0
  129. oscura/automotive/uds/models.py +64 -0
  130. oscura/automotive/visualization.py +369 -0
  131. oscura/batch/__init__.py +55 -0
  132. oscura/batch/advanced.py +627 -0
  133. oscura/batch/aggregate.py +300 -0
  134. oscura/batch/analyze.py +139 -0
  135. oscura/batch/logging.py +487 -0
  136. oscura/batch/metrics.py +556 -0
  137. oscura/builders/__init__.py +41 -0
  138. oscura/builders/signal_builder.py +1131 -0
  139. oscura/cli/__init__.py +14 -0
  140. oscura/cli/batch.py +339 -0
  141. oscura/cli/characterize.py +273 -0
  142. oscura/cli/compare.py +775 -0
  143. oscura/cli/decode.py +551 -0
  144. oscura/cli/main.py +247 -0
  145. oscura/cli/shell.py +350 -0
  146. oscura/comparison/__init__.py +66 -0
  147. oscura/comparison/compare.py +397 -0
  148. oscura/comparison/golden.py +487 -0
  149. oscura/comparison/limits.py +391 -0
  150. oscura/comparison/mask.py +434 -0
  151. oscura/comparison/trace_diff.py +30 -0
  152. oscura/comparison/visualization.py +481 -0
  153. oscura/compliance/__init__.py +70 -0
  154. oscura/compliance/advanced.py +756 -0
  155. oscura/compliance/masks.py +363 -0
  156. oscura/compliance/reporting.py +483 -0
  157. oscura/compliance/testing.py +298 -0
  158. oscura/component/__init__.py +38 -0
  159. oscura/component/impedance.py +365 -0
  160. oscura/component/reactive.py +598 -0
  161. oscura/component/transmission_line.py +312 -0
  162. oscura/config/__init__.py +191 -0
  163. oscura/config/defaults.py +254 -0
  164. oscura/config/loader.py +348 -0
  165. oscura/config/memory.py +271 -0
  166. oscura/config/migration.py +458 -0
  167. oscura/config/pipeline.py +1077 -0
  168. oscura/config/preferences.py +530 -0
  169. oscura/config/protocol.py +875 -0
  170. oscura/config/schema.py +713 -0
  171. oscura/config/settings.py +420 -0
  172. oscura/config/thresholds.py +599 -0
  173. oscura/convenience.py +457 -0
  174. oscura/core/__init__.py +299 -0
  175. oscura/core/audit.py +457 -0
  176. oscura/core/backend_selector.py +405 -0
  177. oscura/core/cache.py +590 -0
  178. oscura/core/cancellation.py +439 -0
  179. oscura/core/confidence.py +225 -0
  180. oscura/core/config.py +506 -0
  181. oscura/core/correlation.py +216 -0
  182. oscura/core/cross_domain.py +422 -0
  183. oscura/core/debug.py +301 -0
  184. oscura/core/edge_cases.py +541 -0
  185. oscura/core/exceptions.py +535 -0
  186. oscura/core/gpu_backend.py +523 -0
  187. oscura/core/lazy.py +832 -0
  188. oscura/core/log_query.py +540 -0
  189. oscura/core/logging.py +931 -0
  190. oscura/core/logging_advanced.py +952 -0
  191. oscura/core/memoize.py +171 -0
  192. oscura/core/memory_check.py +274 -0
  193. oscura/core/memory_guard.py +290 -0
  194. oscura/core/memory_limits.py +336 -0
  195. oscura/core/memory_monitor.py +453 -0
  196. oscura/core/memory_progress.py +465 -0
  197. oscura/core/memory_warnings.py +315 -0
  198. oscura/core/numba_backend.py +362 -0
  199. oscura/core/performance.py +352 -0
  200. oscura/core/progress.py +524 -0
  201. oscura/core/provenance.py +358 -0
  202. oscura/core/results.py +331 -0
  203. oscura/core/types.py +504 -0
  204. oscura/core/uncertainty.py +383 -0
  205. oscura/discovery/__init__.py +52 -0
  206. oscura/discovery/anomaly_detector.py +672 -0
  207. oscura/discovery/auto_decoder.py +415 -0
  208. oscura/discovery/comparison.py +497 -0
  209. oscura/discovery/quality_validator.py +528 -0
  210. oscura/discovery/signal_detector.py +769 -0
  211. oscura/dsl/__init__.py +73 -0
  212. oscura/dsl/commands.py +246 -0
  213. oscura/dsl/interpreter.py +455 -0
  214. oscura/dsl/parser.py +689 -0
  215. oscura/dsl/repl.py +172 -0
  216. oscura/exceptions.py +59 -0
  217. oscura/exploratory/__init__.py +111 -0
  218. oscura/exploratory/error_recovery.py +642 -0
  219. oscura/exploratory/fuzzy.py +513 -0
  220. oscura/exploratory/fuzzy_advanced.py +786 -0
  221. oscura/exploratory/legacy.py +831 -0
  222. oscura/exploratory/parse.py +358 -0
  223. oscura/exploratory/recovery.py +275 -0
  224. oscura/exploratory/sync.py +382 -0
  225. oscura/exploratory/unknown.py +707 -0
  226. oscura/export/__init__.py +25 -0
  227. oscura/export/wireshark/README.md +265 -0
  228. oscura/export/wireshark/__init__.py +47 -0
  229. oscura/export/wireshark/generator.py +312 -0
  230. oscura/export/wireshark/lua_builder.py +159 -0
  231. oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
  232. oscura/export/wireshark/type_mapping.py +165 -0
  233. oscura/export/wireshark/validator.py +105 -0
  234. oscura/exporters/__init__.py +94 -0
  235. oscura/exporters/csv.py +303 -0
  236. oscura/exporters/exporters.py +44 -0
  237. oscura/exporters/hdf5.py +219 -0
  238. oscura/exporters/html_export.py +701 -0
  239. oscura/exporters/json_export.py +291 -0
  240. oscura/exporters/markdown_export.py +367 -0
  241. oscura/exporters/matlab_export.py +354 -0
  242. oscura/exporters/npz_export.py +219 -0
  243. oscura/exporters/spice_export.py +210 -0
  244. oscura/extensibility/__init__.py +131 -0
  245. oscura/extensibility/docs.py +752 -0
  246. oscura/extensibility/extensions.py +1125 -0
  247. oscura/extensibility/logging.py +259 -0
  248. oscura/extensibility/measurements.py +485 -0
  249. oscura/extensibility/plugins.py +414 -0
  250. oscura/extensibility/registry.py +346 -0
  251. oscura/extensibility/templates.py +913 -0
  252. oscura/extensibility/validation.py +651 -0
  253. oscura/filtering/__init__.py +89 -0
  254. oscura/filtering/base.py +563 -0
  255. oscura/filtering/convenience.py +564 -0
  256. oscura/filtering/design.py +725 -0
  257. oscura/filtering/filters.py +32 -0
  258. oscura/filtering/introspection.py +605 -0
  259. oscura/guidance/__init__.py +24 -0
  260. oscura/guidance/recommender.py +429 -0
  261. oscura/guidance/wizard.py +518 -0
  262. oscura/inference/__init__.py +251 -0
  263. oscura/inference/active_learning/README.md +153 -0
  264. oscura/inference/active_learning/__init__.py +38 -0
  265. oscura/inference/active_learning/lstar.py +257 -0
  266. oscura/inference/active_learning/observation_table.py +230 -0
  267. oscura/inference/active_learning/oracle.py +78 -0
  268. oscura/inference/active_learning/teachers/__init__.py +15 -0
  269. oscura/inference/active_learning/teachers/simulator.py +192 -0
  270. oscura/inference/adaptive_tuning.py +453 -0
  271. oscura/inference/alignment.py +653 -0
  272. oscura/inference/bayesian.py +943 -0
  273. oscura/inference/binary.py +1016 -0
  274. oscura/inference/crc_reverse.py +711 -0
  275. oscura/inference/logic.py +288 -0
  276. oscura/inference/message_format.py +1305 -0
  277. oscura/inference/protocol.py +417 -0
  278. oscura/inference/protocol_dsl.py +1084 -0
  279. oscura/inference/protocol_library.py +1230 -0
  280. oscura/inference/sequences.py +809 -0
  281. oscura/inference/signal_intelligence.py +1509 -0
  282. oscura/inference/spectral.py +215 -0
  283. oscura/inference/state_machine.py +634 -0
  284. oscura/inference/stream.py +918 -0
  285. oscura/integrations/__init__.py +59 -0
  286. oscura/integrations/llm.py +1827 -0
  287. oscura/jupyter/__init__.py +32 -0
  288. oscura/jupyter/display.py +268 -0
  289. oscura/jupyter/magic.py +334 -0
  290. oscura/loaders/__init__.py +526 -0
  291. oscura/loaders/binary.py +69 -0
  292. oscura/loaders/configurable.py +1255 -0
  293. oscura/loaders/csv.py +26 -0
  294. oscura/loaders/csv_loader.py +473 -0
  295. oscura/loaders/hdf5.py +9 -0
  296. oscura/loaders/hdf5_loader.py +510 -0
  297. oscura/loaders/lazy.py +370 -0
  298. oscura/loaders/mmap_loader.py +583 -0
  299. oscura/loaders/numpy_loader.py +436 -0
  300. oscura/loaders/pcap.py +432 -0
  301. oscura/loaders/preprocessing.py +368 -0
  302. oscura/loaders/rigol.py +287 -0
  303. oscura/loaders/sigrok.py +321 -0
  304. oscura/loaders/tdms.py +367 -0
  305. oscura/loaders/tektronix.py +711 -0
  306. oscura/loaders/validation.py +584 -0
  307. oscura/loaders/vcd.py +464 -0
  308. oscura/loaders/wav.py +233 -0
  309. oscura/math/__init__.py +45 -0
  310. oscura/math/arithmetic.py +824 -0
  311. oscura/math/interpolation.py +413 -0
  312. oscura/onboarding/__init__.py +39 -0
  313. oscura/onboarding/help.py +498 -0
  314. oscura/onboarding/tutorials.py +405 -0
  315. oscura/onboarding/wizard.py +466 -0
  316. oscura/optimization/__init__.py +19 -0
  317. oscura/optimization/parallel.py +440 -0
  318. oscura/optimization/search.py +532 -0
  319. oscura/pipeline/__init__.py +43 -0
  320. oscura/pipeline/base.py +338 -0
  321. oscura/pipeline/composition.py +242 -0
  322. oscura/pipeline/parallel.py +448 -0
  323. oscura/pipeline/pipeline.py +375 -0
  324. oscura/pipeline/reverse_engineering.py +1119 -0
  325. oscura/plugins/__init__.py +122 -0
  326. oscura/plugins/base.py +272 -0
  327. oscura/plugins/cli.py +497 -0
  328. oscura/plugins/discovery.py +411 -0
  329. oscura/plugins/isolation.py +418 -0
  330. oscura/plugins/lifecycle.py +959 -0
  331. oscura/plugins/manager.py +493 -0
  332. oscura/plugins/registry.py +421 -0
  333. oscura/plugins/versioning.py +372 -0
  334. oscura/py.typed +0 -0
  335. oscura/quality/__init__.py +65 -0
  336. oscura/quality/ensemble.py +740 -0
  337. oscura/quality/explainer.py +338 -0
  338. oscura/quality/scoring.py +616 -0
  339. oscura/quality/warnings.py +456 -0
  340. oscura/reporting/__init__.py +248 -0
  341. oscura/reporting/advanced.py +1234 -0
  342. oscura/reporting/analyze.py +448 -0
  343. oscura/reporting/argument_preparer.py +596 -0
  344. oscura/reporting/auto_report.py +507 -0
  345. oscura/reporting/batch.py +615 -0
  346. oscura/reporting/chart_selection.py +223 -0
  347. oscura/reporting/comparison.py +330 -0
  348. oscura/reporting/config.py +615 -0
  349. oscura/reporting/content/__init__.py +39 -0
  350. oscura/reporting/content/executive.py +127 -0
  351. oscura/reporting/content/filtering.py +191 -0
  352. oscura/reporting/content/minimal.py +257 -0
  353. oscura/reporting/content/verbosity.py +162 -0
  354. oscura/reporting/core.py +508 -0
  355. oscura/reporting/core_formats/__init__.py +17 -0
  356. oscura/reporting/core_formats/multi_format.py +210 -0
  357. oscura/reporting/engine.py +836 -0
  358. oscura/reporting/export.py +366 -0
  359. oscura/reporting/formatting/__init__.py +129 -0
  360. oscura/reporting/formatting/emphasis.py +81 -0
  361. oscura/reporting/formatting/numbers.py +403 -0
  362. oscura/reporting/formatting/standards.py +55 -0
  363. oscura/reporting/formatting.py +466 -0
  364. oscura/reporting/html.py +578 -0
  365. oscura/reporting/index.py +590 -0
  366. oscura/reporting/multichannel.py +296 -0
  367. oscura/reporting/output.py +379 -0
  368. oscura/reporting/pdf.py +373 -0
  369. oscura/reporting/plots.py +731 -0
  370. oscura/reporting/pptx_export.py +360 -0
  371. oscura/reporting/renderers/__init__.py +11 -0
  372. oscura/reporting/renderers/pdf.py +94 -0
  373. oscura/reporting/sections.py +471 -0
  374. oscura/reporting/standards.py +680 -0
  375. oscura/reporting/summary_generator.py +368 -0
  376. oscura/reporting/tables.py +397 -0
  377. oscura/reporting/template_system.py +724 -0
  378. oscura/reporting/templates/__init__.py +15 -0
  379. oscura/reporting/templates/definition.py +205 -0
  380. oscura/reporting/templates/index.html +649 -0
  381. oscura/reporting/templates/index.md +173 -0
  382. oscura/schemas/__init__.py +158 -0
  383. oscura/schemas/bus_configuration.json +322 -0
  384. oscura/schemas/device_mapping.json +182 -0
  385. oscura/schemas/packet_format.json +418 -0
  386. oscura/schemas/protocol_definition.json +363 -0
  387. oscura/search/__init__.py +16 -0
  388. oscura/search/anomaly.py +292 -0
  389. oscura/search/context.py +149 -0
  390. oscura/search/pattern.py +160 -0
  391. oscura/session/__init__.py +34 -0
  392. oscura/session/annotations.py +289 -0
  393. oscura/session/history.py +313 -0
  394. oscura/session/session.py +445 -0
  395. oscura/streaming/__init__.py +43 -0
  396. oscura/streaming/chunked.py +611 -0
  397. oscura/streaming/progressive.py +393 -0
  398. oscura/streaming/realtime.py +622 -0
  399. oscura/testing/__init__.py +54 -0
  400. oscura/testing/synthetic.py +808 -0
  401. oscura/triggering/__init__.py +68 -0
  402. oscura/triggering/base.py +229 -0
  403. oscura/triggering/edge.py +353 -0
  404. oscura/triggering/pattern.py +344 -0
  405. oscura/triggering/pulse.py +581 -0
  406. oscura/triggering/window.py +453 -0
  407. oscura/ui/__init__.py +48 -0
  408. oscura/ui/formatters.py +526 -0
  409. oscura/ui/progressive_display.py +340 -0
  410. oscura/utils/__init__.py +99 -0
  411. oscura/utils/autodetect.py +338 -0
  412. oscura/utils/buffer.py +389 -0
  413. oscura/utils/lazy.py +407 -0
  414. oscura/utils/lazy_imports.py +147 -0
  415. oscura/utils/memory.py +836 -0
  416. oscura/utils/memory_advanced.py +1326 -0
  417. oscura/utils/memory_extensions.py +465 -0
  418. oscura/utils/progressive.py +352 -0
  419. oscura/utils/windowing.py +362 -0
  420. oscura/visualization/__init__.py +321 -0
  421. oscura/visualization/accessibility.py +526 -0
  422. oscura/visualization/annotations.py +374 -0
  423. oscura/visualization/axis_scaling.py +305 -0
  424. oscura/visualization/colors.py +453 -0
  425. oscura/visualization/digital.py +337 -0
  426. oscura/visualization/eye.py +420 -0
  427. oscura/visualization/histogram.py +281 -0
  428. oscura/visualization/interactive.py +858 -0
  429. oscura/visualization/jitter.py +702 -0
  430. oscura/visualization/keyboard.py +394 -0
  431. oscura/visualization/layout.py +365 -0
  432. oscura/visualization/optimization.py +1028 -0
  433. oscura/visualization/palettes.py +446 -0
  434. oscura/visualization/plot.py +92 -0
  435. oscura/visualization/power.py +290 -0
  436. oscura/visualization/power_extended.py +626 -0
  437. oscura/visualization/presets.py +467 -0
  438. oscura/visualization/protocols.py +932 -0
  439. oscura/visualization/render.py +207 -0
  440. oscura/visualization/rendering.py +444 -0
  441. oscura/visualization/reverse_engineering.py +791 -0
  442. oscura/visualization/signal_integrity.py +808 -0
  443. oscura/visualization/specialized.py +553 -0
  444. oscura/visualization/spectral.py +811 -0
  445. oscura/visualization/styles.py +381 -0
  446. oscura/visualization/thumbnails.py +311 -0
  447. oscura/visualization/time_axis.py +351 -0
  448. oscura/visualization/waveform.py +367 -0
  449. oscura/workflow/__init__.py +13 -0
  450. oscura/workflow/dag.py +377 -0
  451. oscura/workflows/__init__.py +58 -0
  452. oscura/workflows/compliance.py +280 -0
  453. oscura/workflows/digital.py +272 -0
  454. oscura/workflows/multi_trace.py +502 -0
  455. oscura/workflows/power.py +178 -0
  456. oscura/workflows/protocol.py +492 -0
  457. oscura/workflows/reverse_engineering.py +639 -0
  458. oscura/workflows/signal_integrity.py +227 -0
  459. oscura-0.1.1.dist-info/METADATA +300 -0
  460. oscura-0.1.1.dist-info/RECORD +463 -0
  461. oscura-0.1.1.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/licenses/LICENSE +1 -1
  463. oscura-0.0.1.dist-info/METADATA +0 -63
  464. oscura-0.0.1.dist-info/RECORD +0 -5
  465. {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,375 @@
1
+ """CAN message wrapper for analysis and hypothesis testing.
2
+
3
+ This module provides the CANMessageWrapper class which wraps messages
4
+ with a specific CAN ID and provides analysis and hypothesis testing methods.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING, Literal
10
+
11
+ import numpy as np
12
+
13
+ from oscura.automotive.can.models import DecodedSignal, SignalDefinition
14
+
15
+ if TYPE_CHECKING:
16
+ from oscura.automotive.can.models import MessageAnalysis
17
+ from oscura.automotive.can.session import CANSession
18
+
19
+ __all__ = ["CANMessageWrapper", "HypothesisResult"]
20
+
21
+
22
+ class HypothesisResult:
23
+ """Result of testing a signal hypothesis.
24
+
25
+ Attributes:
26
+ signal_name: Name of the tested signal.
27
+ definition: Signal definition tested.
28
+ values: Decoded values from all messages.
29
+ min_value: Minimum decoded value.
30
+ max_value: Maximum decoded value.
31
+ mean: Mean decoded value.
32
+ std: Standard deviation.
33
+ is_valid: Whether hypothesis appears valid.
34
+ confidence: Confidence score (0.0-1.0).
35
+ feedback: Human-readable feedback.
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ signal_name: str,
41
+ definition: SignalDefinition,
42
+ values: list[float],
43
+ min_value: float,
44
+ max_value: float,
45
+ mean: float,
46
+ std: float,
47
+ is_valid: bool,
48
+ confidence: float,
49
+ feedback: str,
50
+ ):
51
+ """Initialize hypothesis result."""
52
+ self.signal_name = signal_name
53
+ self.definition = definition
54
+ self.values = values
55
+ self.min_value = min_value
56
+ self.max_value = max_value
57
+ self.mean = mean
58
+ self.std = std
59
+ self.is_valid = is_valid
60
+ self.confidence = confidence
61
+ self.feedback = feedback
62
+
63
+ def __repr__(self) -> str:
64
+ """Human-readable representation."""
65
+ status = "VALID" if self.is_valid else "INVALID"
66
+ return (
67
+ f"HypothesisResult({self.signal_name}: {status}, "
68
+ f"confidence={self.confidence:.2f}, "
69
+ f"range=[{self.min_value:.2f}, {self.max_value:.2f}])"
70
+ )
71
+
72
+ def summary(self) -> str:
73
+ """Generate detailed summary."""
74
+ lines = [
75
+ f"=== Hypothesis Test: {self.signal_name} ===",
76
+ f"Status: {'VALID' if self.is_valid else 'INVALID'}",
77
+ f"Confidence: {self.confidence:.2f}",
78
+ "",
79
+ "Signal Definition:",
80
+ f" Start Byte: {self.definition.start_byte}",
81
+ f" Start Bit: {self.definition.start_bit}",
82
+ f" Length: {self.definition.length} bits",
83
+ f" Byte Order: {self.definition.byte_order}",
84
+ f" Value Type: {self.definition.value_type}",
85
+ f" Scale: {self.definition.scale}",
86
+ f" Offset: {self.definition.offset}",
87
+ "",
88
+ "Decoded Values:",
89
+ f" Min: {self.min_value:.2f} {self.definition.unit}",
90
+ f" Max: {self.max_value:.2f} {self.definition.unit}",
91
+ f" Mean: {self.mean:.2f} {self.definition.unit}",
92
+ f" Std Dev: {self.std:.2f} {self.definition.unit}",
93
+ f" Sample Count: {len(self.values)}",
94
+ "",
95
+ f"Feedback: {self.feedback}",
96
+ ]
97
+ return "\n".join(lines)
98
+
99
+
100
+ class CANMessageWrapper:
101
+ """Wrapper for analyzing messages with a specific CAN ID.
102
+
103
+ This class provides methods for analyzing and reverse engineering
104
+ a specific CAN message ID.
105
+ """
106
+
107
+ def __init__(self, session: CANSession, arbitration_id: int):
108
+ """Initialize message wrapper.
109
+
110
+ Args:
111
+ session: Parent CAN session.
112
+ arbitration_id: CAN ID to wrap.
113
+ """
114
+ self._session = session
115
+ self._arbitration_id = arbitration_id
116
+ self._documented_signals: dict[str, SignalDefinition] = {}
117
+
118
+ @property
119
+ def arbitration_id(self) -> int:
120
+ """Get CAN arbitration ID."""
121
+ return self._arbitration_id
122
+
123
+ def analyze(self, force_refresh: bool = False) -> MessageAnalysis:
124
+ """Perform complete statistical analysis of this message.
125
+
126
+ Args:
127
+ force_refresh: Force re-analysis even if cached.
128
+
129
+ Returns:
130
+ MessageAnalysis with complete analysis results.
131
+
132
+ Example:
133
+ >>> msg = session.message(0x280)
134
+ >>> analysis = msg.analyze()
135
+ >>> print(analysis.summary())
136
+ """
137
+ return self._session.analyze_message(self._arbitration_id, force_refresh=force_refresh)
138
+
139
+ def test_hypothesis(
140
+ self,
141
+ signal_name: str,
142
+ start_byte: int,
143
+ bit_length: int,
144
+ byte_order: Literal["big_endian", "little_endian"] = "big_endian",
145
+ value_type: Literal["unsigned", "signed", "float"] = "unsigned",
146
+ scale: float = 1.0,
147
+ offset: float = 0.0,
148
+ unit: str = "",
149
+ expected_min: float | None = None,
150
+ expected_max: float | None = None,
151
+ ) -> HypothesisResult:
152
+ """Test a hypothesis about signal encoding.
153
+
154
+ Args:
155
+ signal_name: Name for the signal.
156
+ start_byte: Starting byte position (0-7).
157
+ bit_length: Signal length in bits.
158
+ byte_order: Byte order ('big_endian' or 'little_endian').
159
+ value_type: Value type ('unsigned', 'signed', 'float').
160
+ scale: Scaling factor.
161
+ offset: Offset value.
162
+ unit: Physical unit.
163
+ expected_min: Expected minimum value (for validation).
164
+ expected_max: Expected maximum value (for validation).
165
+
166
+ Returns:
167
+ HypothesisResult with test results and feedback.
168
+
169
+ Example:
170
+ >>> msg = session.message(0x280)
171
+ >>> result = msg.test_hypothesis(
172
+ ... signal_name="rpm",
173
+ ... start_byte=2,
174
+ ... bit_length=16,
175
+ ... scale=0.25,
176
+ ... unit="rpm",
177
+ ... expected_min=0,
178
+ ... expected_max=8000
179
+ ... )
180
+ >>> print(result.summary())
181
+ """
182
+ # Create signal definition
183
+ definition = SignalDefinition(
184
+ name=signal_name,
185
+ start_bit=start_byte * 8,
186
+ length=bit_length,
187
+ byte_order=byte_order,
188
+ value_type=value_type,
189
+ scale=scale,
190
+ offset=offset,
191
+ unit=unit,
192
+ )
193
+
194
+ # Get all messages with this ID
195
+ filtered = self._session._messages.filter_by_id(self._arbitration_id)
196
+
197
+ # Decode all values
198
+ decoded_values = []
199
+ for msg in filtered.messages:
200
+ try:
201
+ value = definition.decode(msg.data)
202
+ decoded_values.append(value)
203
+ except Exception:
204
+ # Skip messages that can't be decoded
205
+ pass
206
+
207
+ if not decoded_values:
208
+ return HypothesisResult(
209
+ signal_name=signal_name,
210
+ definition=definition,
211
+ values=[],
212
+ min_value=0.0,
213
+ max_value=0.0,
214
+ mean=0.0,
215
+ std=0.0,
216
+ is_valid=False,
217
+ confidence=0.0,
218
+ feedback="Failed to decode any messages with this definition",
219
+ )
220
+
221
+ # Calculate statistics
222
+ arr = np.array(decoded_values)
223
+ min_val = float(np.min(arr))
224
+ max_val = float(np.max(arr))
225
+ mean_val = float(np.mean(arr))
226
+ std_val = float(np.std(arr))
227
+
228
+ # Validate hypothesis
229
+ is_valid = True
230
+ confidence = 1.0
231
+ feedback_parts = []
232
+
233
+ # Check expected range if provided
234
+ if expected_min is not None and min_val < expected_min:
235
+ is_valid = False
236
+ confidence *= 0.5
237
+ feedback_parts.append(f"Min value {min_val:.2f} below expected {expected_min:.2f}")
238
+
239
+ if expected_max is not None and max_val > expected_max:
240
+ is_valid = False
241
+ confidence *= 0.5
242
+ feedback_parts.append(f"Max value {max_val:.2f} above expected {expected_max:.2f}")
243
+
244
+ # Check for reasonable value distribution
245
+ if std_val == 0:
246
+ confidence *= 0.7
247
+ feedback_parts.append("Warning: All values are identical - might be a constant field")
248
+
249
+ # Check for extremely large range (might indicate wrong scaling)
250
+ value_range = max_val - min_val
251
+ if value_range > 1e6:
252
+ confidence *= 0.6
253
+ feedback_parts.append("Warning: Very large value range - check scaling factor")
254
+
255
+ # Positive feedback
256
+ if is_valid and not feedback_parts:
257
+ feedback_parts.append(f"Values in expected range [{min_val:.2f}, {max_val:.2f}]")
258
+ if std_val > 0:
259
+ feedback_parts.append("Signal shows variation - likely represents real data")
260
+
261
+ feedback = "; ".join(feedback_parts) if feedback_parts else "Hypothesis test passed"
262
+
263
+ return HypothesisResult(
264
+ signal_name=signal_name,
265
+ definition=definition,
266
+ values=decoded_values,
267
+ min_value=min_val,
268
+ max_value=max_val,
269
+ mean=mean_val,
270
+ std=std_val,
271
+ is_valid=is_valid,
272
+ confidence=confidence,
273
+ feedback=feedback,
274
+ )
275
+
276
+ def document_signal(
277
+ self,
278
+ name: str,
279
+ start_bit: int,
280
+ length: int,
281
+ byte_order: Literal["big_endian", "little_endian"] = "big_endian",
282
+ value_type: Literal["unsigned", "signed", "float"] = "unsigned",
283
+ scale: float = 1.0,
284
+ offset: float = 0.0,
285
+ unit: str = "",
286
+ comment: str = "",
287
+ ) -> None:
288
+ """Document a confirmed signal definition.
289
+
290
+ Args:
291
+ name: Signal name.
292
+ start_bit: Starting bit position.
293
+ length: Signal length in bits.
294
+ byte_order: Byte order.
295
+ value_type: Value type.
296
+ scale: Scaling factor.
297
+ offset: Offset value.
298
+ unit: Physical unit.
299
+ comment: Description or notes.
300
+
301
+ Example:
302
+ >>> msg = session.message(0x280)
303
+ >>> msg.document_signal(
304
+ ... name="rpm",
305
+ ... start_bit=16,
306
+ ... length=16,
307
+ ... scale=0.25,
308
+ ... unit="rpm",
309
+ ... comment="Confirmed via OBD-II correlation"
310
+ ... )
311
+ """
312
+ definition = SignalDefinition(
313
+ name=name,
314
+ start_bit=start_bit,
315
+ length=length,
316
+ byte_order=byte_order,
317
+ value_type=value_type,
318
+ scale=scale,
319
+ offset=offset,
320
+ unit=unit,
321
+ comment=comment,
322
+ )
323
+
324
+ self._documented_signals[name] = definition
325
+
326
+ def get_documented_signals(self) -> dict[str, SignalDefinition]:
327
+ """Get all documented signal definitions.
328
+
329
+ Returns:
330
+ Dictionary mapping signal names to definitions.
331
+ """
332
+ return self._documented_signals.copy()
333
+
334
+ def decode_signals(self) -> list[DecodedSignal]:
335
+ """Decode all documented signals from all messages.
336
+
337
+ Returns:
338
+ List of DecodedSignal objects, one per message per signal.
339
+
340
+ Example:
341
+ >>> msg = session.message(0x280)
342
+ >>> msg.document_signal("rpm", start_bit=16, length=16, scale=0.25, unit="rpm")
343
+ >>> decoded = msg.decode_signals()
344
+ >>> for sig in decoded[:5]: # First 5
345
+ ... print(sig)
346
+ """
347
+ decoded_signals = []
348
+
349
+ filtered = self._session._messages.filter_by_id(self._arbitration_id)
350
+
351
+ for msg in filtered.messages:
352
+ for sig_name, sig_def in self._documented_signals.items():
353
+ try:
354
+ value = sig_def.decode(msg.data)
355
+ raw_value = sig_def.extract_raw(msg.data)
356
+
357
+ decoded_sig = DecodedSignal(
358
+ name=sig_name,
359
+ value=value,
360
+ unit=sig_def.unit,
361
+ timestamp=msg.timestamp,
362
+ raw_value=raw_value,
363
+ definition=sig_def,
364
+ )
365
+ decoded_signals.append(decoded_sig)
366
+
367
+ except Exception:
368
+ # Skip messages that can't be decoded
369
+ pass
370
+
371
+ return decoded_signals
372
+
373
+ def __repr__(self) -> str:
374
+ """Human-readable representation."""
375
+ return f"CANMessageWrapper(id=0x{self._arbitration_id:03X}, documented_signals={len(self._documented_signals)})"