oscura 0.5.0__py3-none-any.whl → 0.6.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 (513) hide show
  1. oscura/__init__.py +169 -167
  2. oscura/analyzers/__init__.py +3 -0
  3. oscura/analyzers/classification.py +659 -0
  4. oscura/analyzers/digital/__init__.py +0 -48
  5. oscura/analyzers/digital/edges.py +325 -65
  6. oscura/analyzers/digital/extraction.py +0 -195
  7. oscura/analyzers/digital/quality.py +293 -166
  8. oscura/analyzers/digital/timing.py +260 -115
  9. oscura/analyzers/digital/timing_numba.py +334 -0
  10. oscura/analyzers/entropy.py +605 -0
  11. oscura/analyzers/eye/diagram.py +176 -109
  12. oscura/analyzers/eye/metrics.py +5 -5
  13. oscura/analyzers/jitter/__init__.py +6 -4
  14. oscura/analyzers/jitter/ber.py +52 -52
  15. oscura/analyzers/jitter/classification.py +156 -0
  16. oscura/analyzers/jitter/decomposition.py +163 -113
  17. oscura/analyzers/jitter/spectrum.py +80 -64
  18. oscura/analyzers/ml/__init__.py +39 -0
  19. oscura/analyzers/ml/features.py +600 -0
  20. oscura/analyzers/ml/signal_classifier.py +604 -0
  21. oscura/analyzers/packet/daq.py +246 -158
  22. oscura/analyzers/packet/parser.py +12 -1
  23. oscura/analyzers/packet/payload.py +50 -2110
  24. oscura/analyzers/packet/payload_analysis.py +361 -181
  25. oscura/analyzers/packet/payload_patterns.py +133 -70
  26. oscura/analyzers/packet/stream.py +84 -23
  27. oscura/analyzers/patterns/__init__.py +26 -5
  28. oscura/analyzers/patterns/anomaly_detection.py +908 -0
  29. oscura/analyzers/patterns/clustering.py +169 -108
  30. oscura/analyzers/patterns/clustering_optimized.py +227 -0
  31. oscura/analyzers/patterns/discovery.py +1 -1
  32. oscura/analyzers/patterns/matching.py +581 -197
  33. oscura/analyzers/patterns/pattern_mining.py +778 -0
  34. oscura/analyzers/patterns/periodic.py +121 -38
  35. oscura/analyzers/patterns/sequences.py +175 -78
  36. oscura/analyzers/power/conduction.py +1 -1
  37. oscura/analyzers/power/soa.py +6 -6
  38. oscura/analyzers/power/switching.py +250 -110
  39. oscura/analyzers/protocol/__init__.py +17 -1
  40. oscura/analyzers/protocols/__init__.py +1 -22
  41. oscura/analyzers/protocols/base.py +6 -6
  42. oscura/analyzers/protocols/ble/__init__.py +38 -0
  43. oscura/analyzers/protocols/ble/analyzer.py +809 -0
  44. oscura/analyzers/protocols/ble/uuids.py +288 -0
  45. oscura/analyzers/protocols/can.py +257 -127
  46. oscura/analyzers/protocols/can_fd.py +107 -80
  47. oscura/analyzers/protocols/flexray.py +139 -80
  48. oscura/analyzers/protocols/hdlc.py +93 -58
  49. oscura/analyzers/protocols/i2c.py +247 -106
  50. oscura/analyzers/protocols/i2s.py +138 -86
  51. oscura/analyzers/protocols/industrial/__init__.py +40 -0
  52. oscura/analyzers/protocols/industrial/bacnet/__init__.py +33 -0
  53. oscura/analyzers/protocols/industrial/bacnet/analyzer.py +708 -0
  54. oscura/analyzers/protocols/industrial/bacnet/encoding.py +412 -0
  55. oscura/analyzers/protocols/industrial/bacnet/services.py +622 -0
  56. oscura/analyzers/protocols/industrial/ethercat/__init__.py +30 -0
  57. oscura/analyzers/protocols/industrial/ethercat/analyzer.py +474 -0
  58. oscura/analyzers/protocols/industrial/ethercat/mailbox.py +339 -0
  59. oscura/analyzers/protocols/industrial/ethercat/topology.py +166 -0
  60. oscura/analyzers/protocols/industrial/modbus/__init__.py +31 -0
  61. oscura/analyzers/protocols/industrial/modbus/analyzer.py +525 -0
  62. oscura/analyzers/protocols/industrial/modbus/crc.py +79 -0
  63. oscura/analyzers/protocols/industrial/modbus/functions.py +436 -0
  64. oscura/analyzers/protocols/industrial/opcua/__init__.py +21 -0
  65. oscura/analyzers/protocols/industrial/opcua/analyzer.py +552 -0
  66. oscura/analyzers/protocols/industrial/opcua/datatypes.py +446 -0
  67. oscura/analyzers/protocols/industrial/opcua/services.py +264 -0
  68. oscura/analyzers/protocols/industrial/profinet/__init__.py +23 -0
  69. oscura/analyzers/protocols/industrial/profinet/analyzer.py +441 -0
  70. oscura/analyzers/protocols/industrial/profinet/dcp.py +263 -0
  71. oscura/analyzers/protocols/industrial/profinet/ptcp.py +200 -0
  72. oscura/analyzers/protocols/jtag.py +180 -98
  73. oscura/analyzers/protocols/lin.py +219 -114
  74. oscura/analyzers/protocols/manchester.py +4 -4
  75. oscura/analyzers/protocols/onewire.py +253 -149
  76. oscura/analyzers/protocols/parallel_bus/__init__.py +20 -0
  77. oscura/analyzers/protocols/parallel_bus/centronics.py +92 -0
  78. oscura/analyzers/protocols/parallel_bus/gpib.py +137 -0
  79. oscura/analyzers/protocols/spi.py +192 -95
  80. oscura/analyzers/protocols/swd.py +321 -167
  81. oscura/analyzers/protocols/uart.py +267 -125
  82. oscura/analyzers/protocols/usb.py +235 -131
  83. oscura/analyzers/side_channel/power.py +17 -12
  84. oscura/analyzers/signal/__init__.py +15 -0
  85. oscura/analyzers/signal/timing_analysis.py +1086 -0
  86. oscura/analyzers/signal_integrity/__init__.py +4 -1
  87. oscura/analyzers/signal_integrity/sparams.py +2 -19
  88. oscura/analyzers/spectral/chunked.py +129 -60
  89. oscura/analyzers/spectral/chunked_fft.py +300 -94
  90. oscura/analyzers/spectral/chunked_wavelet.py +100 -80
  91. oscura/analyzers/statistical/checksum.py +376 -217
  92. oscura/analyzers/statistical/classification.py +229 -107
  93. oscura/analyzers/statistical/entropy.py +78 -53
  94. oscura/analyzers/statistics/correlation.py +407 -211
  95. oscura/analyzers/statistics/outliers.py +2 -2
  96. oscura/analyzers/statistics/streaming.py +30 -5
  97. oscura/analyzers/validation.py +216 -101
  98. oscura/analyzers/waveform/measurements.py +9 -0
  99. oscura/analyzers/waveform/measurements_with_uncertainty.py +31 -15
  100. oscura/analyzers/waveform/spectral.py +500 -228
  101. oscura/api/__init__.py +31 -5
  102. oscura/api/dsl/__init__.py +582 -0
  103. oscura/{dsl → api/dsl}/commands.py +43 -76
  104. oscura/{dsl → api/dsl}/interpreter.py +26 -51
  105. oscura/{dsl → api/dsl}/parser.py +107 -77
  106. oscura/{dsl → api/dsl}/repl.py +2 -2
  107. oscura/api/dsl.py +1 -1
  108. oscura/{integrations → api/integrations}/__init__.py +1 -1
  109. oscura/{integrations → api/integrations}/llm.py +201 -102
  110. oscura/api/operators.py +3 -3
  111. oscura/api/optimization.py +144 -30
  112. oscura/api/rest_server.py +921 -0
  113. oscura/api/server/__init__.py +17 -0
  114. oscura/api/server/dashboard.py +850 -0
  115. oscura/api/server/static/README.md +34 -0
  116. oscura/api/server/templates/base.html +181 -0
  117. oscura/api/server/templates/export.html +120 -0
  118. oscura/api/server/templates/home.html +284 -0
  119. oscura/api/server/templates/protocols.html +58 -0
  120. oscura/api/server/templates/reports.html +43 -0
  121. oscura/api/server/templates/session_detail.html +89 -0
  122. oscura/api/server/templates/sessions.html +83 -0
  123. oscura/api/server/templates/waveforms.html +73 -0
  124. oscura/automotive/__init__.py +8 -1
  125. oscura/automotive/can/__init__.py +10 -0
  126. oscura/automotive/can/checksum.py +3 -1
  127. oscura/automotive/can/dbc_generator.py +590 -0
  128. oscura/automotive/can/message_wrapper.py +121 -74
  129. oscura/automotive/can/patterns.py +98 -21
  130. oscura/automotive/can/session.py +292 -56
  131. oscura/automotive/can/state_machine.py +6 -3
  132. oscura/automotive/can/stimulus_response.py +97 -75
  133. oscura/automotive/dbc/__init__.py +10 -2
  134. oscura/automotive/dbc/generator.py +84 -56
  135. oscura/automotive/dbc/parser.py +6 -6
  136. oscura/automotive/dtc/data.json +2763 -0
  137. oscura/automotive/dtc/database.py +2 -2
  138. oscura/automotive/flexray/__init__.py +31 -0
  139. oscura/automotive/flexray/analyzer.py +504 -0
  140. oscura/automotive/flexray/crc.py +185 -0
  141. oscura/automotive/flexray/fibex.py +449 -0
  142. oscura/automotive/j1939/__init__.py +45 -8
  143. oscura/automotive/j1939/analyzer.py +605 -0
  144. oscura/automotive/j1939/spns.py +326 -0
  145. oscura/automotive/j1939/transport.py +306 -0
  146. oscura/automotive/lin/__init__.py +47 -0
  147. oscura/automotive/lin/analyzer.py +612 -0
  148. oscura/automotive/loaders/blf.py +13 -2
  149. oscura/automotive/loaders/csv_can.py +143 -72
  150. oscura/automotive/loaders/dispatcher.py +50 -2
  151. oscura/automotive/loaders/mdf.py +86 -45
  152. oscura/automotive/loaders/pcap.py +111 -61
  153. oscura/automotive/uds/__init__.py +4 -0
  154. oscura/automotive/uds/analyzer.py +725 -0
  155. oscura/automotive/uds/decoder.py +140 -58
  156. oscura/automotive/uds/models.py +7 -1
  157. oscura/automotive/visualization.py +1 -1
  158. oscura/cli/analyze.py +348 -0
  159. oscura/cli/batch.py +142 -122
  160. oscura/cli/benchmark.py +275 -0
  161. oscura/cli/characterize.py +137 -82
  162. oscura/cli/compare.py +224 -131
  163. oscura/cli/completion.py +250 -0
  164. oscura/cli/config_cmd.py +361 -0
  165. oscura/cli/decode.py +164 -87
  166. oscura/cli/export.py +286 -0
  167. oscura/cli/main.py +115 -31
  168. oscura/{onboarding → cli/onboarding}/__init__.py +3 -3
  169. oscura/{onboarding → cli/onboarding}/help.py +80 -58
  170. oscura/{onboarding → cli/onboarding}/tutorials.py +97 -72
  171. oscura/{onboarding → cli/onboarding}/wizard.py +55 -36
  172. oscura/cli/progress.py +147 -0
  173. oscura/cli/shell.py +157 -135
  174. oscura/cli/validate_cmd.py +204 -0
  175. oscura/cli/visualize.py +158 -0
  176. oscura/convenience.py +125 -79
  177. oscura/core/__init__.py +4 -2
  178. oscura/core/backend_selector.py +3 -3
  179. oscura/core/cache.py +126 -15
  180. oscura/core/cancellation.py +1 -1
  181. oscura/{config → core/config}/__init__.py +20 -11
  182. oscura/{config → core/config}/defaults.py +1 -1
  183. oscura/{config → core/config}/loader.py +7 -5
  184. oscura/{config → core/config}/memory.py +5 -5
  185. oscura/{config → core/config}/migration.py +1 -1
  186. oscura/{config → core/config}/pipeline.py +99 -23
  187. oscura/{config → core/config}/preferences.py +1 -1
  188. oscura/{config → core/config}/protocol.py +3 -3
  189. oscura/{config → core/config}/schema.py +426 -272
  190. oscura/{config → core/config}/settings.py +1 -1
  191. oscura/{config → core/config}/thresholds.py +195 -153
  192. oscura/core/correlation.py +5 -6
  193. oscura/core/cross_domain.py +0 -2
  194. oscura/core/debug.py +9 -5
  195. oscura/{extensibility → core/extensibility}/docs.py +158 -70
  196. oscura/{extensibility → core/extensibility}/extensions.py +160 -76
  197. oscura/{extensibility → core/extensibility}/logging.py +1 -1
  198. oscura/{extensibility → core/extensibility}/measurements.py +1 -1
  199. oscura/{extensibility → core/extensibility}/plugins.py +1 -1
  200. oscura/{extensibility → core/extensibility}/templates.py +73 -3
  201. oscura/{extensibility → core/extensibility}/validation.py +1 -1
  202. oscura/core/gpu_backend.py +11 -7
  203. oscura/core/log_query.py +101 -11
  204. oscura/core/logging.py +126 -54
  205. oscura/core/logging_advanced.py +5 -5
  206. oscura/core/memory_limits.py +108 -70
  207. oscura/core/memory_monitor.py +2 -2
  208. oscura/core/memory_progress.py +7 -7
  209. oscura/core/memory_warnings.py +1 -1
  210. oscura/core/numba_backend.py +13 -13
  211. oscura/{plugins → core/plugins}/__init__.py +9 -9
  212. oscura/{plugins → core/plugins}/base.py +7 -7
  213. oscura/{plugins → core/plugins}/cli.py +3 -3
  214. oscura/{plugins → core/plugins}/discovery.py +186 -106
  215. oscura/{plugins → core/plugins}/lifecycle.py +1 -1
  216. oscura/{plugins → core/plugins}/manager.py +7 -7
  217. oscura/{plugins → core/plugins}/registry.py +3 -3
  218. oscura/{plugins → core/plugins}/versioning.py +1 -1
  219. oscura/core/progress.py +16 -1
  220. oscura/core/provenance.py +8 -2
  221. oscura/{schemas → core/schemas}/__init__.py +2 -2
  222. oscura/core/schemas/bus_configuration.json +322 -0
  223. oscura/core/schemas/device_mapping.json +182 -0
  224. oscura/core/schemas/packet_format.json +418 -0
  225. oscura/core/schemas/protocol_definition.json +363 -0
  226. oscura/core/types.py +4 -0
  227. oscura/core/uncertainty.py +3 -3
  228. oscura/correlation/__init__.py +52 -0
  229. oscura/correlation/multi_protocol.py +811 -0
  230. oscura/discovery/auto_decoder.py +117 -35
  231. oscura/discovery/comparison.py +191 -86
  232. oscura/discovery/quality_validator.py +155 -68
  233. oscura/discovery/signal_detector.py +196 -79
  234. oscura/export/__init__.py +18 -20
  235. oscura/export/kaitai_struct.py +513 -0
  236. oscura/export/scapy_layer.py +801 -0
  237. oscura/export/wireshark/README.md +15 -15
  238. oscura/export/wireshark/generator.py +1 -1
  239. oscura/export/wireshark/templates/dissector.lua.j2 +2 -2
  240. oscura/export/wireshark_dissector.py +746 -0
  241. oscura/guidance/wizard.py +207 -111
  242. oscura/hardware/__init__.py +19 -0
  243. oscura/{acquisition → hardware/acquisition}/__init__.py +4 -4
  244. oscura/{acquisition → hardware/acquisition}/file.py +2 -2
  245. oscura/{acquisition → hardware/acquisition}/hardware.py +7 -7
  246. oscura/{acquisition → hardware/acquisition}/saleae.py +15 -12
  247. oscura/{acquisition → hardware/acquisition}/socketcan.py +1 -1
  248. oscura/{acquisition → hardware/acquisition}/streaming.py +2 -2
  249. oscura/{acquisition → hardware/acquisition}/synthetic.py +3 -3
  250. oscura/{acquisition → hardware/acquisition}/visa.py +33 -11
  251. oscura/hardware/firmware/__init__.py +29 -0
  252. oscura/hardware/firmware/pattern_recognition.py +874 -0
  253. oscura/hardware/hal_detector.py +736 -0
  254. oscura/hardware/security/__init__.py +37 -0
  255. oscura/hardware/security/side_channel_detector.py +1126 -0
  256. oscura/inference/__init__.py +4 -0
  257. oscura/inference/active_learning/README.md +7 -7
  258. oscura/inference/active_learning/observation_table.py +4 -1
  259. oscura/inference/alignment.py +216 -123
  260. oscura/inference/bayesian.py +113 -33
  261. oscura/inference/crc_reverse.py +101 -55
  262. oscura/inference/logic.py +6 -2
  263. oscura/inference/message_format.py +342 -183
  264. oscura/inference/protocol.py +95 -44
  265. oscura/inference/protocol_dsl.py +180 -82
  266. oscura/inference/signal_intelligence.py +1439 -706
  267. oscura/inference/spectral.py +99 -57
  268. oscura/inference/state_machine.py +810 -158
  269. oscura/inference/stream.py +270 -110
  270. oscura/iot/__init__.py +34 -0
  271. oscura/iot/coap/__init__.py +32 -0
  272. oscura/iot/coap/analyzer.py +668 -0
  273. oscura/iot/coap/options.py +212 -0
  274. oscura/iot/lorawan/__init__.py +21 -0
  275. oscura/iot/lorawan/crypto.py +206 -0
  276. oscura/iot/lorawan/decoder.py +801 -0
  277. oscura/iot/lorawan/mac_commands.py +341 -0
  278. oscura/iot/mqtt/__init__.py +27 -0
  279. oscura/iot/mqtt/analyzer.py +999 -0
  280. oscura/iot/mqtt/properties.py +315 -0
  281. oscura/iot/zigbee/__init__.py +31 -0
  282. oscura/iot/zigbee/analyzer.py +615 -0
  283. oscura/iot/zigbee/security.py +153 -0
  284. oscura/iot/zigbee/zcl.py +349 -0
  285. oscura/jupyter/display.py +125 -45
  286. oscura/{exploratory → jupyter/exploratory}/__init__.py +8 -8
  287. oscura/{exploratory → jupyter/exploratory}/error_recovery.py +298 -141
  288. oscura/jupyter/exploratory/fuzzy.py +746 -0
  289. oscura/{exploratory → jupyter/exploratory}/fuzzy_advanced.py +258 -100
  290. oscura/{exploratory → jupyter/exploratory}/legacy.py +464 -242
  291. oscura/{exploratory → jupyter/exploratory}/parse.py +167 -145
  292. oscura/{exploratory → jupyter/exploratory}/recovery.py +119 -87
  293. oscura/jupyter/exploratory/sync.py +612 -0
  294. oscura/{exploratory → jupyter/exploratory}/unknown.py +299 -176
  295. oscura/jupyter/magic.py +4 -4
  296. oscura/{ui → jupyter/ui}/__init__.py +2 -2
  297. oscura/{ui → jupyter/ui}/formatters.py +3 -3
  298. oscura/{ui → jupyter/ui}/progressive_display.py +153 -82
  299. oscura/loaders/__init__.py +171 -63
  300. oscura/loaders/binary.py +88 -1
  301. oscura/loaders/chipwhisperer.py +153 -137
  302. oscura/loaders/configurable.py +208 -86
  303. oscura/loaders/csv_loader.py +458 -215
  304. oscura/loaders/hdf5_loader.py +278 -119
  305. oscura/loaders/lazy.py +87 -54
  306. oscura/loaders/mmap_loader.py +1 -1
  307. oscura/loaders/numpy_loader.py +253 -116
  308. oscura/loaders/pcap.py +226 -151
  309. oscura/loaders/rigol.py +110 -49
  310. oscura/loaders/sigrok.py +201 -78
  311. oscura/loaders/tdms.py +81 -58
  312. oscura/loaders/tektronix.py +291 -174
  313. oscura/loaders/touchstone.py +182 -87
  314. oscura/loaders/vcd.py +215 -117
  315. oscura/loaders/wav.py +155 -68
  316. oscura/reporting/__init__.py +9 -7
  317. oscura/reporting/analyze.py +352 -146
  318. oscura/reporting/argument_preparer.py +69 -14
  319. oscura/reporting/auto_report.py +97 -61
  320. oscura/reporting/batch.py +131 -58
  321. oscura/reporting/chart_selection.py +57 -45
  322. oscura/reporting/comparison.py +63 -17
  323. oscura/reporting/content/executive.py +76 -24
  324. oscura/reporting/core_formats/multi_format.py +11 -8
  325. oscura/reporting/engine.py +312 -158
  326. oscura/reporting/enhanced_reports.py +949 -0
  327. oscura/reporting/export.py +86 -43
  328. oscura/reporting/formatting/numbers.py +69 -42
  329. oscura/reporting/html.py +139 -58
  330. oscura/reporting/index.py +137 -65
  331. oscura/reporting/output.py +158 -67
  332. oscura/reporting/pdf.py +67 -102
  333. oscura/reporting/plots.py +191 -112
  334. oscura/reporting/sections.py +88 -47
  335. oscura/reporting/standards.py +104 -61
  336. oscura/reporting/summary_generator.py +75 -55
  337. oscura/reporting/tables.py +138 -54
  338. oscura/reporting/templates/enhanced/protocol_re.html +525 -0
  339. oscura/reporting/templates/index.md +13 -13
  340. oscura/sessions/__init__.py +14 -23
  341. oscura/sessions/base.py +3 -3
  342. oscura/sessions/blackbox.py +106 -10
  343. oscura/sessions/generic.py +2 -2
  344. oscura/sessions/legacy.py +783 -0
  345. oscura/side_channel/__init__.py +63 -0
  346. oscura/side_channel/dpa.py +1025 -0
  347. oscura/utils/__init__.py +15 -1
  348. oscura/utils/autodetect.py +1 -5
  349. oscura/utils/bitwise.py +118 -0
  350. oscura/{builders → utils/builders}/__init__.py +1 -1
  351. oscura/{comparison → utils/comparison}/__init__.py +6 -6
  352. oscura/{comparison → utils/comparison}/compare.py +202 -101
  353. oscura/{comparison → utils/comparison}/golden.py +83 -63
  354. oscura/{comparison → utils/comparison}/limits.py +313 -89
  355. oscura/{comparison → utils/comparison}/mask.py +151 -45
  356. oscura/{comparison → utils/comparison}/trace_diff.py +1 -1
  357. oscura/{comparison → utils/comparison}/visualization.py +147 -89
  358. oscura/{component → utils/component}/__init__.py +3 -3
  359. oscura/{component → utils/component}/impedance.py +122 -58
  360. oscura/{component → utils/component}/reactive.py +165 -168
  361. oscura/{component → utils/component}/transmission_line.py +3 -3
  362. oscura/{filtering → utils/filtering}/__init__.py +6 -6
  363. oscura/{filtering → utils/filtering}/base.py +1 -1
  364. oscura/{filtering → utils/filtering}/convenience.py +2 -2
  365. oscura/{filtering → utils/filtering}/design.py +169 -93
  366. oscura/{filtering → utils/filtering}/filters.py +2 -2
  367. oscura/{filtering → utils/filtering}/introspection.py +2 -2
  368. oscura/utils/geometry.py +31 -0
  369. oscura/utils/imports.py +184 -0
  370. oscura/utils/lazy.py +1 -1
  371. oscura/{math → utils/math}/__init__.py +2 -2
  372. oscura/{math → utils/math}/arithmetic.py +114 -48
  373. oscura/{math → utils/math}/interpolation.py +139 -106
  374. oscura/utils/memory.py +129 -66
  375. oscura/utils/memory_advanced.py +92 -9
  376. oscura/utils/memory_extensions.py +10 -8
  377. oscura/{optimization → utils/optimization}/__init__.py +1 -1
  378. oscura/{optimization → utils/optimization}/search.py +2 -2
  379. oscura/utils/performance/__init__.py +58 -0
  380. oscura/utils/performance/caching.py +889 -0
  381. oscura/utils/performance/lsh_clustering.py +333 -0
  382. oscura/utils/performance/memory_optimizer.py +699 -0
  383. oscura/utils/performance/optimizations.py +675 -0
  384. oscura/utils/performance/parallel.py +654 -0
  385. oscura/utils/performance/profiling.py +661 -0
  386. oscura/{pipeline → utils/pipeline}/base.py +1 -1
  387. oscura/{pipeline → utils/pipeline}/composition.py +11 -3
  388. oscura/{pipeline → utils/pipeline}/parallel.py +3 -2
  389. oscura/{pipeline → utils/pipeline}/pipeline.py +1 -1
  390. oscura/{pipeline → utils/pipeline}/reverse_engineering.py +412 -221
  391. oscura/{search → utils/search}/__init__.py +3 -3
  392. oscura/{search → utils/search}/anomaly.py +188 -58
  393. oscura/utils/search/context.py +294 -0
  394. oscura/{search → utils/search}/pattern.py +138 -10
  395. oscura/utils/serial.py +51 -0
  396. oscura/utils/storage/__init__.py +61 -0
  397. oscura/utils/storage/database.py +1166 -0
  398. oscura/{streaming → utils/streaming}/chunked.py +302 -143
  399. oscura/{streaming → utils/streaming}/progressive.py +1 -1
  400. oscura/{streaming → utils/streaming}/realtime.py +3 -2
  401. oscura/{triggering → utils/triggering}/__init__.py +6 -6
  402. oscura/{triggering → utils/triggering}/base.py +6 -6
  403. oscura/{triggering → utils/triggering}/edge.py +2 -2
  404. oscura/{triggering → utils/triggering}/pattern.py +2 -2
  405. oscura/{triggering → utils/triggering}/pulse.py +115 -74
  406. oscura/{triggering → utils/triggering}/window.py +2 -2
  407. oscura/utils/validation.py +32 -0
  408. oscura/validation/__init__.py +121 -0
  409. oscura/{compliance → validation/compliance}/__init__.py +5 -5
  410. oscura/{compliance → validation/compliance}/advanced.py +5 -5
  411. oscura/{compliance → validation/compliance}/masks.py +1 -1
  412. oscura/{compliance → validation/compliance}/reporting.py +127 -53
  413. oscura/{compliance → validation/compliance}/testing.py +114 -52
  414. oscura/validation/compliance_tests.py +915 -0
  415. oscura/validation/fuzzer.py +990 -0
  416. oscura/validation/grammar_tests.py +596 -0
  417. oscura/validation/grammar_validator.py +904 -0
  418. oscura/validation/hil_testing.py +977 -0
  419. oscura/{quality → validation/quality}/__init__.py +4 -4
  420. oscura/{quality → validation/quality}/ensemble.py +251 -171
  421. oscura/{quality → validation/quality}/explainer.py +3 -3
  422. oscura/{quality → validation/quality}/scoring.py +1 -1
  423. oscura/{quality → validation/quality}/warnings.py +4 -4
  424. oscura/validation/regression_suite.py +808 -0
  425. oscura/validation/replay.py +788 -0
  426. oscura/{testing → validation/testing}/__init__.py +2 -2
  427. oscura/{testing → validation/testing}/synthetic.py +5 -5
  428. oscura/visualization/__init__.py +9 -0
  429. oscura/visualization/accessibility.py +1 -1
  430. oscura/visualization/annotations.py +64 -67
  431. oscura/visualization/colors.py +7 -7
  432. oscura/visualization/digital.py +180 -81
  433. oscura/visualization/eye.py +236 -85
  434. oscura/visualization/interactive.py +320 -143
  435. oscura/visualization/jitter.py +587 -247
  436. oscura/visualization/layout.py +169 -134
  437. oscura/visualization/optimization.py +103 -52
  438. oscura/visualization/palettes.py +1 -1
  439. oscura/visualization/power.py +427 -211
  440. oscura/visualization/power_extended.py +626 -297
  441. oscura/visualization/presets.py +2 -0
  442. oscura/visualization/protocols.py +495 -181
  443. oscura/visualization/render.py +79 -63
  444. oscura/visualization/reverse_engineering.py +171 -124
  445. oscura/visualization/signal_integrity.py +460 -279
  446. oscura/visualization/specialized.py +190 -100
  447. oscura/visualization/spectral.py +670 -255
  448. oscura/visualization/thumbnails.py +166 -137
  449. oscura/visualization/waveform.py +150 -63
  450. oscura/workflows/__init__.py +3 -0
  451. oscura/{batch → workflows/batch}/__init__.py +5 -5
  452. oscura/{batch → workflows/batch}/advanced.py +150 -75
  453. oscura/workflows/batch/aggregate.py +531 -0
  454. oscura/workflows/batch/analyze.py +236 -0
  455. oscura/{batch → workflows/batch}/logging.py +2 -2
  456. oscura/{batch → workflows/batch}/metrics.py +1 -1
  457. oscura/workflows/complete_re.py +1144 -0
  458. oscura/workflows/compliance.py +44 -54
  459. oscura/workflows/digital.py +197 -51
  460. oscura/workflows/legacy/__init__.py +12 -0
  461. oscura/{workflow → workflows/legacy}/dag.py +4 -1
  462. oscura/workflows/multi_trace.py +9 -9
  463. oscura/workflows/power.py +42 -62
  464. oscura/workflows/protocol.py +82 -49
  465. oscura/workflows/reverse_engineering.py +351 -150
  466. oscura/workflows/signal_integrity.py +157 -82
  467. oscura-0.6.0.dist-info/METADATA +643 -0
  468. oscura-0.6.0.dist-info/RECORD +590 -0
  469. oscura/analyzers/digital/ic_database.py +0 -498
  470. oscura/analyzers/digital/timing_paths.py +0 -339
  471. oscura/analyzers/digital/vintage.py +0 -377
  472. oscura/analyzers/digital/vintage_result.py +0 -148
  473. oscura/analyzers/protocols/parallel_bus.py +0 -449
  474. oscura/batch/aggregate.py +0 -300
  475. oscura/batch/analyze.py +0 -139
  476. oscura/dsl/__init__.py +0 -73
  477. oscura/exceptions.py +0 -59
  478. oscura/exploratory/fuzzy.py +0 -513
  479. oscura/exploratory/sync.py +0 -384
  480. oscura/export/wavedrom.py +0 -430
  481. oscura/exporters/__init__.py +0 -94
  482. oscura/exporters/csv.py +0 -303
  483. oscura/exporters/exporters.py +0 -44
  484. oscura/exporters/hdf5.py +0 -217
  485. oscura/exporters/html_export.py +0 -701
  486. oscura/exporters/json_export.py +0 -338
  487. oscura/exporters/markdown_export.py +0 -367
  488. oscura/exporters/matlab_export.py +0 -354
  489. oscura/exporters/npz_export.py +0 -219
  490. oscura/exporters/spice_export.py +0 -210
  491. oscura/exporters/vintage_logic_csv.py +0 -247
  492. oscura/reporting/vintage_logic_report.py +0 -523
  493. oscura/search/context.py +0 -149
  494. oscura/session/__init__.py +0 -34
  495. oscura/session/annotations.py +0 -289
  496. oscura/session/history.py +0 -313
  497. oscura/session/session.py +0 -520
  498. oscura/visualization/digital_advanced.py +0 -718
  499. oscura/visualization/figure_manager.py +0 -156
  500. oscura/workflow/__init__.py +0 -13
  501. oscura-0.5.0.dist-info/METADATA +0 -407
  502. oscura-0.5.0.dist-info/RECORD +0 -486
  503. /oscura/core/{config.py → config/legacy.py} +0 -0
  504. /oscura/{extensibility → core/extensibility}/__init__.py +0 -0
  505. /oscura/{extensibility → core/extensibility}/registry.py +0 -0
  506. /oscura/{plugins → core/plugins}/isolation.py +0 -0
  507. /oscura/{builders → utils/builders}/signal_builder.py +0 -0
  508. /oscura/{optimization → utils/optimization}/parallel.py +0 -0
  509. /oscura/{pipeline → utils/pipeline}/__init__.py +0 -0
  510. /oscura/{streaming → utils/streaming}/__init__.py +0 -0
  511. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/WHEEL +0 -0
  512. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/entry_points.txt +0 -0
  513. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -65,15 +65,15 @@ class I2SDecoder(SyncDecoder):
65
65
  longname = "Inter-IC Sound"
66
66
  desc = "I2S audio bus protocol decoder"
67
67
 
68
- channels = [ # noqa: RUF012
68
+ channels = [
69
69
  ChannelDef("bck", "BCK", "Bit Clock (SCLK)", required=True),
70
70
  ChannelDef("ws", "WS", "Word Select (LRCLK)", required=True),
71
71
  ChannelDef("sd", "SD", "Serial Data", required=True),
72
72
  ]
73
73
 
74
- optional_channels = [] # noqa: RUF012
74
+ optional_channels = []
75
75
 
76
- options = [ # noqa: RUF012
76
+ options = [
77
77
  OptionDef(
78
78
  "bit_depth",
79
79
  "Bit depth",
@@ -90,7 +90,7 @@ class I2SDecoder(SyncDecoder):
90
90
  ),
91
91
  ]
92
92
 
93
- annotations = [ # noqa: RUF012
93
+ annotations = [
94
94
  ("left", "Left channel sample"),
95
95
  ("right", "Right channel sample"),
96
96
  ("word", "Word boundary"),
@@ -140,15 +140,8 @@ class I2SDecoder(SyncDecoder):
140
140
  if bck is None or ws is None or sd is None:
141
141
  return
142
142
 
143
- n_samples = min(len(bck), len(ws), len(sd))
144
- bck = bck[:n_samples]
145
- ws = ws[:n_samples]
146
- sd = sd[:n_samples]
147
-
148
- # Find rising edges of BCK (data sampled on rising edge in I2S)
143
+ bck, ws, sd = self._align_signals(bck, ws, sd)
149
144
  rising_edges = np.where(~bck[:-1] & bck[1:])[0] + 1
150
-
151
- # Find WS transitions to identify word boundaries
152
145
  ws_transitions = np.where(ws[:-1] != ws[1:])[0] + 1
153
146
 
154
147
  if len(rising_edges) == 0 or len(ws_transitions) == 0:
@@ -156,105 +149,40 @@ class I2SDecoder(SyncDecoder):
156
149
 
157
150
  trans_num = 0
158
151
  ws_idx = 0
152
+ left_sample = 0
153
+ right_sample = 0
154
+ first_start_time = 0.0
159
155
 
160
156
  while ws_idx < len(ws_transitions) - 1:
161
- # Get word boundaries
162
157
  word_start_idx = ws_transitions[ws_idx]
163
158
  word_end_idx = ws_transitions[ws_idx + 1]
164
159
 
165
- # Determine channel (WS=0 is left, WS=1 is right in standard I2S)
166
160
  is_left = not ws[word_start_idx]
167
-
168
- # Find BCK edges in this word period
169
- word_edges = rising_edges[
170
- (rising_edges >= word_start_idx) & (rising_edges < word_end_idx)
171
- ]
161
+ word_edges = self._get_word_edges(rising_edges, word_start_idx, word_end_idx)
172
162
 
173
163
  if len(word_edges) == 0:
174
164
  ws_idx += 1
175
165
  continue
176
166
 
177
- # In standard I2S mode, data starts 1 clock after WS change
178
- # In left-justified mode, data starts at WS change
179
- # In right-justified mode, data is aligned to end of word period
180
- if self._mode == I2SMode.STANDARD:
181
- # Skip first edge (data starts on second edge)
182
- data_edges = word_edges[1:] if len(word_edges) > 1 else []
183
- elif self._mode == I2SMode.LEFT_JUSTIFIED:
184
- data_edges = word_edges
185
- else: # RIGHT_JUSTIFIED
186
- # Take last bit_depth edges
187
- data_edges = (
188
- word_edges[-self._bit_depth :]
189
- if len(word_edges) >= self._bit_depth
190
- else word_edges
191
- )
192
-
193
- # Extract sample data (MSB first)
194
- sample_bits = []
195
- for edge_idx in data_edges[: self._bit_depth]:
196
- if edge_idx < len(sd):
197
- sample_bits.append(1 if sd[edge_idx] else 0)
198
-
199
- if len(sample_bits) < self._bit_depth:
200
- # Incomplete sample, pad with zeros
201
- sample_bits.extend([0] * (self._bit_depth - len(sample_bits)))
202
-
203
- # Convert to signed integer value (MSB first, two's complement)
204
- sample_value = 0
205
- for bit in sample_bits:
206
- sample_value = (sample_value << 1) | bit
167
+ data_edges = self._select_data_edges(word_edges)
168
+ sample_value = self._extract_sample(sd, data_edges)
207
169
 
208
- # Convert from unsigned to signed (two's complement)
209
- if sample_bits[0] == 1: # Negative number
210
- sample_value = sample_value - (1 << self._bit_depth)
211
-
212
- # Calculate timing
213
170
  start_time = word_start_idx / sample_rate
214
171
  end_time = word_end_idx / sample_rate
215
172
 
216
- # Store left and right channels
173
+ # Accumulate stereo pair
217
174
  if ws_idx % 2 == 0:
218
- # First word of stereo pair
219
175
  left_sample = sample_value if is_left else 0
220
176
  right_sample = 0 if is_left else sample_value
221
177
  first_start_time = start_time
222
178
  else:
223
- # Second word of stereo pair - emit packet
224
179
  if is_left:
225
180
  left_sample = sample_value
226
181
  else:
227
182
  right_sample = sample_value
228
183
 
229
- # Add annotation
230
- self.put_annotation(
231
- first_start_time,
232
- end_time,
233
- AnnotationLevel.PACKETS,
234
- f"L: {left_sample} / R: {right_sample}",
235
- )
236
-
237
- # Create packet
238
- annotations = {
239
- "sample_num": trans_num,
240
- "left_sample": left_sample,
241
- "right_sample": right_sample,
242
- "bit_depth": self._bit_depth,
243
- "mode": self._mode.value,
244
- }
245
-
246
- # Encode as bytes (little-endian, signed)
247
- byte_count = (self._bit_depth + 7) // 8
248
- left_bytes = left_sample.to_bytes(byte_count, "little", signed=True)
249
- right_bytes = right_sample.to_bytes(byte_count, "little", signed=True)
250
- data_bytes = left_bytes + right_bytes
251
-
252
- packet = ProtocolPacket(
253
- timestamp=first_start_time,
254
- protocol="i2s",
255
- data=data_bytes,
256
- annotations=annotations,
257
- errors=[],
184
+ packet = self._build_stereo_packet(
185
+ left_sample, right_sample, first_start_time, end_time, trans_num
258
186
  )
259
187
 
260
188
  yield packet
@@ -262,6 +190,130 @@ class I2SDecoder(SyncDecoder):
262
190
 
263
191
  ws_idx += 1
264
192
 
193
+ def _align_signals(
194
+ self, bck: NDArray[np.bool_], ws: NDArray[np.bool_], sd: NDArray[np.bool_]
195
+ ) -> tuple[NDArray[np.bool_], NDArray[np.bool_], NDArray[np.bool_]]:
196
+ """Align all signals to minimum length.
197
+
198
+ Args:
199
+ bck: Bit clock signal.
200
+ ws: Word select signal.
201
+ sd: Serial data signal.
202
+
203
+ Returns:
204
+ Aligned signals.
205
+ """
206
+ n_samples = min(len(bck), len(ws), len(sd))
207
+ return bck[:n_samples], ws[:n_samples], sd[:n_samples]
208
+
209
+ def _get_word_edges(
210
+ self, rising_edges: NDArray[np.intp], start_idx: int, end_idx: int
211
+ ) -> NDArray[np.intp]:
212
+ """Get clock edges within word period.
213
+
214
+ Args:
215
+ rising_edges: All rising edge indices.
216
+ start_idx: Word start index.
217
+ end_idx: Word end index.
218
+
219
+ Returns:
220
+ Edges within word period.
221
+ """
222
+ return rising_edges[(rising_edges >= start_idx) & (rising_edges < end_idx)]
223
+
224
+ def _select_data_edges(self, word_edges: NDArray[np.intp]) -> NDArray[np.intp]:
225
+ """Select data edges based on I2S mode.
226
+
227
+ Args:
228
+ word_edges: All edges in word period.
229
+
230
+ Returns:
231
+ Edges containing valid data.
232
+ """
233
+ if self._mode == I2SMode.STANDARD:
234
+ # Skip first edge (data starts on second edge)
235
+ return word_edges[1:] if len(word_edges) > 1 else np.array([])
236
+ elif self._mode == I2SMode.LEFT_JUSTIFIED:
237
+ return word_edges
238
+ else: # RIGHT_JUSTIFIED
239
+ # Take last bit_depth edges
240
+ if len(word_edges) >= self._bit_depth:
241
+ return word_edges[-self._bit_depth :]
242
+ return word_edges
243
+
244
+ def _extract_sample(self, sd: NDArray[np.bool_], data_edges: NDArray[np.intp]) -> int:
245
+ """Extract and convert sample value.
246
+
247
+ Args:
248
+ sd: Serial data signal.
249
+ data_edges: Edges to sample.
250
+
251
+ Returns:
252
+ Signed sample value.
253
+ """
254
+ sample_bits = []
255
+ for edge_idx in data_edges[: self._bit_depth]:
256
+ if edge_idx < len(sd):
257
+ sample_bits.append(1 if sd[edge_idx] else 0)
258
+
259
+ # Pad incomplete samples
260
+ if len(sample_bits) < self._bit_depth:
261
+ sample_bits.extend([0] * (self._bit_depth - len(sample_bits)))
262
+
263
+ # Convert to signed integer (MSB first, two's complement)
264
+ sample_value = 0
265
+ for bit in sample_bits:
266
+ sample_value = (sample_value << 1) | bit
267
+
268
+ # Convert to signed
269
+ if sample_bits[0] == 1: # Negative number
270
+ sample_value = sample_value - (1 << self._bit_depth)
271
+
272
+ return sample_value
273
+
274
+ def _build_stereo_packet(
275
+ self, left: int, right: int, start_time: float, end_time: float, sample_num: int
276
+ ) -> ProtocolPacket:
277
+ """Build I2S stereo sample packet.
278
+
279
+ Args:
280
+ left: Left channel sample.
281
+ right: Right channel sample.
282
+ start_time: Packet start time.
283
+ end_time: Packet end time.
284
+ sample_num: Sample number.
285
+
286
+ Returns:
287
+ Protocol packet.
288
+ """
289
+ self.put_annotation(
290
+ start_time,
291
+ end_time,
292
+ AnnotationLevel.PACKETS,
293
+ f"L: {left} / R: {right}",
294
+ )
295
+
296
+ annotations = {
297
+ "sample_num": sample_num,
298
+ "left_sample": left,
299
+ "right_sample": right,
300
+ "bit_depth": self._bit_depth,
301
+ "mode": self._mode.value,
302
+ }
303
+
304
+ byte_count = (self._bit_depth + 7) // 8
305
+ left_bytes = left.to_bytes(byte_count, "little", signed=True)
306
+ right_bytes = right.to_bytes(byte_count, "little", signed=True)
307
+ data_bytes = left_bytes + right_bytes
308
+
309
+ return ProtocolPacket(
310
+ timestamp=start_time,
311
+ protocol="i2s",
312
+ data=data_bytes,
313
+ annotations=annotations,
314
+ errors=[],
315
+ )
316
+
265
317
 
266
318
  def decode_i2s(
267
319
  bck: NDArray[np.bool_],
@@ -0,0 +1,40 @@
1
+ """Industrial protocol analyzers.
2
+
3
+ This module provides protocol analyzers for industrial communication protocols
4
+ commonly used in manufacturing, building automation, and SCADA systems.
5
+
6
+ Supported protocols:
7
+ - Modbus RTU/TCP: Serial and Ethernet variants
8
+ - OPC UA: Unified Architecture for industrial communication
9
+ - BACnet IP/MSTP: Building automation and control networks
10
+ """
11
+
12
+ from oscura.analyzers.protocols.industrial.bacnet import (
13
+ BACnetAnalyzer,
14
+ BACnetDevice,
15
+ BACnetMessage,
16
+ BACnetObject,
17
+ )
18
+ from oscura.analyzers.protocols.industrial.modbus import (
19
+ ModbusAnalyzer,
20
+ ModbusDevice,
21
+ ModbusMessage,
22
+ )
23
+ from oscura.analyzers.protocols.industrial.opcua import (
24
+ OPCUAAnalyzer,
25
+ OPCUAMessage,
26
+ OPCUANode,
27
+ )
28
+
29
+ __all__ = [
30
+ "BACnetAnalyzer",
31
+ "BACnetDevice",
32
+ "BACnetMessage",
33
+ "BACnetObject",
34
+ "ModbusAnalyzer",
35
+ "ModbusDevice",
36
+ "ModbusMessage",
37
+ "OPCUAAnalyzer",
38
+ "OPCUAMessage",
39
+ "OPCUANode",
40
+ ]
@@ -0,0 +1,33 @@
1
+ """BACnet protocol analyzer package.
2
+
3
+ This package provides BACnet (Building Automation and Control Networks) protocol
4
+ analysis for both BACnet/IP (UDP) and BACnet/MSTP (serial) variants. Supports
5
+ NPDU/APDU parsing, service decoding, and device discovery for HVAC and building
6
+ automation systems.
7
+
8
+ Example:
9
+ >>> from oscura.analyzers.protocols.industrial.bacnet import BACnetAnalyzer
10
+ >>> analyzer = BACnetAnalyzer()
11
+ >>> # Parse BACnet/IP message
12
+ >>> message = analyzer.parse_bacnet_ip(udp_payload, timestamp=0.0)
13
+ >>> # Parse BACnet MSTP frame
14
+ >>> message = analyzer.parse_bacnet_mstp(serial_data, timestamp=0.0)
15
+
16
+ References:
17
+ ANSI/ASHRAE Standard 135-2020 (BACnet):
18
+ https://www.ashrae.org/technical-resources/bookstore/bacnet
19
+ """
20
+
21
+ from oscura.analyzers.protocols.industrial.bacnet.analyzer import (
22
+ BACnetAnalyzer,
23
+ BACnetDevice,
24
+ BACnetMessage,
25
+ BACnetObject,
26
+ )
27
+
28
+ __all__ = [
29
+ "BACnetAnalyzer",
30
+ "BACnetDevice",
31
+ "BACnetMessage",
32
+ "BACnetObject",
33
+ ]