oscura 0.5.1__py3-none-any.whl → 0.7.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 (497) 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/edges.py +325 -65
  5. oscura/analyzers/digital/quality.py +293 -166
  6. oscura/analyzers/digital/timing.py +260 -115
  7. oscura/analyzers/digital/timing_numba.py +334 -0
  8. oscura/analyzers/entropy.py +605 -0
  9. oscura/analyzers/eye/diagram.py +176 -109
  10. oscura/analyzers/eye/metrics.py +5 -5
  11. oscura/analyzers/jitter/__init__.py +6 -4
  12. oscura/analyzers/jitter/ber.py +52 -52
  13. oscura/analyzers/jitter/classification.py +156 -0
  14. oscura/analyzers/jitter/decomposition.py +163 -113
  15. oscura/analyzers/jitter/spectrum.py +80 -64
  16. oscura/analyzers/ml/__init__.py +39 -0
  17. oscura/analyzers/ml/features.py +600 -0
  18. oscura/analyzers/ml/signal_classifier.py +604 -0
  19. oscura/analyzers/packet/daq.py +246 -158
  20. oscura/analyzers/packet/parser.py +12 -1
  21. oscura/analyzers/packet/payload.py +50 -2110
  22. oscura/analyzers/packet/payload_analysis.py +361 -181
  23. oscura/analyzers/packet/payload_patterns.py +133 -70
  24. oscura/analyzers/packet/stream.py +84 -23
  25. oscura/analyzers/patterns/__init__.py +26 -5
  26. oscura/analyzers/patterns/anomaly_detection.py +908 -0
  27. oscura/analyzers/patterns/clustering.py +169 -108
  28. oscura/analyzers/patterns/clustering_optimized.py +227 -0
  29. oscura/analyzers/patterns/discovery.py +1 -1
  30. oscura/analyzers/patterns/matching.py +581 -197
  31. oscura/analyzers/patterns/pattern_mining.py +778 -0
  32. oscura/analyzers/patterns/periodic.py +121 -38
  33. oscura/analyzers/patterns/sequences.py +175 -78
  34. oscura/analyzers/power/conduction.py +1 -1
  35. oscura/analyzers/power/soa.py +6 -6
  36. oscura/analyzers/power/switching.py +250 -110
  37. oscura/analyzers/protocol/__init__.py +17 -1
  38. oscura/analyzers/protocols/base.py +6 -6
  39. oscura/analyzers/protocols/ble/__init__.py +38 -0
  40. oscura/analyzers/protocols/ble/analyzer.py +809 -0
  41. oscura/analyzers/protocols/ble/uuids.py +288 -0
  42. oscura/analyzers/protocols/can.py +257 -127
  43. oscura/analyzers/protocols/can_fd.py +107 -80
  44. oscura/analyzers/protocols/flexray.py +139 -80
  45. oscura/analyzers/protocols/hdlc.py +93 -58
  46. oscura/analyzers/protocols/i2c.py +247 -106
  47. oscura/analyzers/protocols/i2s.py +138 -86
  48. oscura/analyzers/protocols/industrial/__init__.py +40 -0
  49. oscura/analyzers/protocols/industrial/bacnet/__init__.py +33 -0
  50. oscura/analyzers/protocols/industrial/bacnet/analyzer.py +708 -0
  51. oscura/analyzers/protocols/industrial/bacnet/encoding.py +412 -0
  52. oscura/analyzers/protocols/industrial/bacnet/services.py +622 -0
  53. oscura/analyzers/protocols/industrial/ethercat/__init__.py +30 -0
  54. oscura/analyzers/protocols/industrial/ethercat/analyzer.py +474 -0
  55. oscura/analyzers/protocols/industrial/ethercat/mailbox.py +339 -0
  56. oscura/analyzers/protocols/industrial/ethercat/topology.py +166 -0
  57. oscura/analyzers/protocols/industrial/modbus/__init__.py +31 -0
  58. oscura/analyzers/protocols/industrial/modbus/analyzer.py +525 -0
  59. oscura/analyzers/protocols/industrial/modbus/crc.py +79 -0
  60. oscura/analyzers/protocols/industrial/modbus/functions.py +436 -0
  61. oscura/analyzers/protocols/industrial/opcua/__init__.py +21 -0
  62. oscura/analyzers/protocols/industrial/opcua/analyzer.py +552 -0
  63. oscura/analyzers/protocols/industrial/opcua/datatypes.py +446 -0
  64. oscura/analyzers/protocols/industrial/opcua/services.py +264 -0
  65. oscura/analyzers/protocols/industrial/profinet/__init__.py +23 -0
  66. oscura/analyzers/protocols/industrial/profinet/analyzer.py +441 -0
  67. oscura/analyzers/protocols/industrial/profinet/dcp.py +263 -0
  68. oscura/analyzers/protocols/industrial/profinet/ptcp.py +200 -0
  69. oscura/analyzers/protocols/jtag.py +180 -98
  70. oscura/analyzers/protocols/lin.py +219 -114
  71. oscura/analyzers/protocols/manchester.py +4 -4
  72. oscura/analyzers/protocols/onewire.py +253 -149
  73. oscura/analyzers/protocols/parallel_bus/__init__.py +20 -0
  74. oscura/analyzers/protocols/parallel_bus/centronics.py +92 -0
  75. oscura/analyzers/protocols/parallel_bus/gpib.py +137 -0
  76. oscura/analyzers/protocols/spi.py +192 -95
  77. oscura/analyzers/protocols/swd.py +321 -167
  78. oscura/analyzers/protocols/uart.py +267 -125
  79. oscura/analyzers/protocols/usb.py +235 -131
  80. oscura/analyzers/side_channel/power.py +17 -12
  81. oscura/analyzers/signal/__init__.py +15 -0
  82. oscura/analyzers/signal/timing_analysis.py +1086 -0
  83. oscura/analyzers/signal_integrity/__init__.py +4 -1
  84. oscura/analyzers/signal_integrity/sparams.py +2 -19
  85. oscura/analyzers/spectral/chunked.py +129 -60
  86. oscura/analyzers/spectral/chunked_fft.py +300 -94
  87. oscura/analyzers/spectral/chunked_wavelet.py +100 -80
  88. oscura/analyzers/statistical/checksum.py +376 -217
  89. oscura/analyzers/statistical/classification.py +229 -107
  90. oscura/analyzers/statistical/entropy.py +78 -53
  91. oscura/analyzers/statistics/correlation.py +407 -211
  92. oscura/analyzers/statistics/outliers.py +2 -2
  93. oscura/analyzers/statistics/streaming.py +30 -5
  94. oscura/analyzers/validation.py +216 -101
  95. oscura/analyzers/waveform/measurements.py +9 -0
  96. oscura/analyzers/waveform/measurements_with_uncertainty.py +31 -15
  97. oscura/analyzers/waveform/spectral.py +500 -228
  98. oscura/api/__init__.py +31 -5
  99. oscura/api/dsl/__init__.py +582 -0
  100. oscura/{dsl → api/dsl}/commands.py +43 -76
  101. oscura/{dsl → api/dsl}/interpreter.py +26 -51
  102. oscura/{dsl → api/dsl}/parser.py +107 -77
  103. oscura/{dsl → api/dsl}/repl.py +2 -2
  104. oscura/api/dsl.py +1 -1
  105. oscura/{integrations → api/integrations}/__init__.py +1 -1
  106. oscura/{integrations → api/integrations}/llm.py +201 -102
  107. oscura/api/operators.py +3 -3
  108. oscura/api/optimization.py +144 -30
  109. oscura/api/rest_server.py +921 -0
  110. oscura/api/server/__init__.py +17 -0
  111. oscura/api/server/dashboard.py +850 -0
  112. oscura/api/server/static/README.md +34 -0
  113. oscura/api/server/templates/base.html +181 -0
  114. oscura/api/server/templates/export.html +120 -0
  115. oscura/api/server/templates/home.html +284 -0
  116. oscura/api/server/templates/protocols.html +58 -0
  117. oscura/api/server/templates/reports.html +43 -0
  118. oscura/api/server/templates/session_detail.html +89 -0
  119. oscura/api/server/templates/sessions.html +83 -0
  120. oscura/api/server/templates/waveforms.html +73 -0
  121. oscura/automotive/__init__.py +8 -1
  122. oscura/automotive/can/__init__.py +10 -0
  123. oscura/automotive/can/checksum.py +3 -1
  124. oscura/automotive/can/dbc_generator.py +590 -0
  125. oscura/automotive/can/message_wrapper.py +121 -74
  126. oscura/automotive/can/patterns.py +98 -21
  127. oscura/automotive/can/session.py +292 -56
  128. oscura/automotive/can/state_machine.py +6 -3
  129. oscura/automotive/can/stimulus_response.py +97 -75
  130. oscura/automotive/dbc/__init__.py +10 -2
  131. oscura/automotive/dbc/generator.py +84 -56
  132. oscura/automotive/dbc/parser.py +6 -6
  133. oscura/automotive/dtc/data.json +17 -102
  134. oscura/automotive/dtc/database.py +2 -2
  135. oscura/automotive/flexray/__init__.py +31 -0
  136. oscura/automotive/flexray/analyzer.py +504 -0
  137. oscura/automotive/flexray/crc.py +185 -0
  138. oscura/automotive/flexray/fibex.py +449 -0
  139. oscura/automotive/j1939/__init__.py +45 -8
  140. oscura/automotive/j1939/analyzer.py +605 -0
  141. oscura/automotive/j1939/spns.py +326 -0
  142. oscura/automotive/j1939/transport.py +306 -0
  143. oscura/automotive/lin/__init__.py +47 -0
  144. oscura/automotive/lin/analyzer.py +612 -0
  145. oscura/automotive/loaders/blf.py +13 -2
  146. oscura/automotive/loaders/csv_can.py +143 -72
  147. oscura/automotive/loaders/dispatcher.py +50 -2
  148. oscura/automotive/loaders/mdf.py +86 -45
  149. oscura/automotive/loaders/pcap.py +111 -61
  150. oscura/automotive/uds/__init__.py +4 -0
  151. oscura/automotive/uds/analyzer.py +725 -0
  152. oscura/automotive/uds/decoder.py +140 -58
  153. oscura/automotive/uds/models.py +7 -1
  154. oscura/automotive/visualization.py +1 -1
  155. oscura/cli/analyze.py +348 -0
  156. oscura/cli/batch.py +142 -122
  157. oscura/cli/benchmark.py +275 -0
  158. oscura/cli/characterize.py +137 -82
  159. oscura/cli/compare.py +224 -131
  160. oscura/cli/completion.py +250 -0
  161. oscura/cli/config_cmd.py +361 -0
  162. oscura/cli/decode.py +164 -87
  163. oscura/cli/export.py +286 -0
  164. oscura/cli/main.py +115 -31
  165. oscura/{onboarding → cli/onboarding}/__init__.py +3 -3
  166. oscura/{onboarding → cli/onboarding}/help.py +80 -58
  167. oscura/{onboarding → cli/onboarding}/tutorials.py +97 -72
  168. oscura/{onboarding → cli/onboarding}/wizard.py +55 -36
  169. oscura/cli/progress.py +147 -0
  170. oscura/cli/shell.py +157 -135
  171. oscura/cli/validate_cmd.py +204 -0
  172. oscura/cli/visualize.py +158 -0
  173. oscura/convenience.py +125 -79
  174. oscura/core/__init__.py +4 -2
  175. oscura/core/backend_selector.py +3 -3
  176. oscura/core/cache.py +126 -15
  177. oscura/core/cancellation.py +1 -1
  178. oscura/{config → core/config}/__init__.py +20 -11
  179. oscura/{config → core/config}/defaults.py +1 -1
  180. oscura/{config → core/config}/loader.py +7 -5
  181. oscura/{config → core/config}/memory.py +5 -5
  182. oscura/{config → core/config}/migration.py +1 -1
  183. oscura/{config → core/config}/pipeline.py +99 -23
  184. oscura/{config → core/config}/preferences.py +1 -1
  185. oscura/{config → core/config}/protocol.py +3 -3
  186. oscura/{config → core/config}/schema.py +426 -272
  187. oscura/{config → core/config}/settings.py +1 -1
  188. oscura/{config → core/config}/thresholds.py +195 -153
  189. oscura/core/correlation.py +5 -6
  190. oscura/core/cross_domain.py +0 -2
  191. oscura/core/debug.py +9 -5
  192. oscura/{extensibility → core/extensibility}/docs.py +158 -70
  193. oscura/{extensibility → core/extensibility}/extensions.py +160 -76
  194. oscura/{extensibility → core/extensibility}/logging.py +1 -1
  195. oscura/{extensibility → core/extensibility}/measurements.py +1 -1
  196. oscura/{extensibility → core/extensibility}/plugins.py +1 -1
  197. oscura/{extensibility → core/extensibility}/templates.py +73 -3
  198. oscura/{extensibility → core/extensibility}/validation.py +1 -1
  199. oscura/core/gpu_backend.py +11 -7
  200. oscura/core/log_query.py +101 -11
  201. oscura/core/logging.py +126 -54
  202. oscura/core/logging_advanced.py +5 -5
  203. oscura/core/memory_limits.py +108 -70
  204. oscura/core/memory_monitor.py +2 -2
  205. oscura/core/memory_progress.py +7 -7
  206. oscura/core/memory_warnings.py +1 -1
  207. oscura/core/numba_backend.py +13 -13
  208. oscura/{plugins → core/plugins}/__init__.py +9 -9
  209. oscura/{plugins → core/plugins}/base.py +7 -7
  210. oscura/{plugins → core/plugins}/cli.py +3 -3
  211. oscura/{plugins → core/plugins}/discovery.py +186 -106
  212. oscura/{plugins → core/plugins}/lifecycle.py +1 -1
  213. oscura/{plugins → core/plugins}/manager.py +7 -7
  214. oscura/{plugins → core/plugins}/registry.py +3 -3
  215. oscura/{plugins → core/plugins}/versioning.py +1 -1
  216. oscura/core/progress.py +16 -1
  217. oscura/core/provenance.py +8 -2
  218. oscura/{schemas → core/schemas}/__init__.py +2 -2
  219. oscura/{schemas → core/schemas}/device_mapping.json +2 -8
  220. oscura/{schemas → core/schemas}/packet_format.json +4 -24
  221. oscura/{schemas → core/schemas}/protocol_definition.json +2 -12
  222. oscura/core/types.py +4 -0
  223. oscura/core/uncertainty.py +3 -3
  224. oscura/correlation/__init__.py +52 -0
  225. oscura/correlation/multi_protocol.py +811 -0
  226. oscura/discovery/auto_decoder.py +117 -35
  227. oscura/discovery/comparison.py +191 -86
  228. oscura/discovery/quality_validator.py +155 -68
  229. oscura/discovery/signal_detector.py +196 -79
  230. oscura/export/__init__.py +18 -8
  231. oscura/export/kaitai_struct.py +513 -0
  232. oscura/export/scapy_layer.py +801 -0
  233. oscura/export/wireshark/generator.py +1 -1
  234. oscura/export/wireshark/templates/dissector.lua.j2 +2 -2
  235. oscura/export/wireshark_dissector.py +746 -0
  236. oscura/guidance/wizard.py +207 -111
  237. oscura/hardware/__init__.py +19 -0
  238. oscura/{acquisition → hardware/acquisition}/__init__.py +4 -4
  239. oscura/{acquisition → hardware/acquisition}/file.py +2 -2
  240. oscura/{acquisition → hardware/acquisition}/hardware.py +7 -7
  241. oscura/{acquisition → hardware/acquisition}/saleae.py +15 -12
  242. oscura/{acquisition → hardware/acquisition}/socketcan.py +1 -1
  243. oscura/{acquisition → hardware/acquisition}/streaming.py +2 -2
  244. oscura/{acquisition → hardware/acquisition}/synthetic.py +3 -3
  245. oscura/{acquisition → hardware/acquisition}/visa.py +33 -11
  246. oscura/hardware/firmware/__init__.py +29 -0
  247. oscura/hardware/firmware/pattern_recognition.py +874 -0
  248. oscura/hardware/hal_detector.py +736 -0
  249. oscura/hardware/security/__init__.py +37 -0
  250. oscura/hardware/security/side_channel_detector.py +1126 -0
  251. oscura/inference/__init__.py +4 -0
  252. oscura/inference/active_learning/observation_table.py +4 -1
  253. oscura/inference/alignment.py +216 -123
  254. oscura/inference/bayesian.py +113 -33
  255. oscura/inference/crc_reverse.py +101 -55
  256. oscura/inference/logic.py +6 -2
  257. oscura/inference/message_format.py +342 -183
  258. oscura/inference/protocol.py +95 -44
  259. oscura/inference/protocol_dsl.py +180 -82
  260. oscura/inference/signal_intelligence.py +1439 -706
  261. oscura/inference/spectral.py +99 -57
  262. oscura/inference/state_machine.py +810 -158
  263. oscura/inference/stream.py +270 -110
  264. oscura/iot/__init__.py +34 -0
  265. oscura/iot/coap/__init__.py +32 -0
  266. oscura/iot/coap/analyzer.py +668 -0
  267. oscura/iot/coap/options.py +212 -0
  268. oscura/iot/lorawan/__init__.py +21 -0
  269. oscura/iot/lorawan/crypto.py +206 -0
  270. oscura/iot/lorawan/decoder.py +801 -0
  271. oscura/iot/lorawan/mac_commands.py +341 -0
  272. oscura/iot/mqtt/__init__.py +27 -0
  273. oscura/iot/mqtt/analyzer.py +999 -0
  274. oscura/iot/mqtt/properties.py +315 -0
  275. oscura/iot/zigbee/__init__.py +31 -0
  276. oscura/iot/zigbee/analyzer.py +615 -0
  277. oscura/iot/zigbee/security.py +153 -0
  278. oscura/iot/zigbee/zcl.py +349 -0
  279. oscura/jupyter/display.py +125 -45
  280. oscura/{exploratory → jupyter/exploratory}/__init__.py +8 -8
  281. oscura/{exploratory → jupyter/exploratory}/error_recovery.py +298 -141
  282. oscura/jupyter/exploratory/fuzzy.py +746 -0
  283. oscura/{exploratory → jupyter/exploratory}/fuzzy_advanced.py +258 -100
  284. oscura/{exploratory → jupyter/exploratory}/legacy.py +464 -242
  285. oscura/{exploratory → jupyter/exploratory}/parse.py +167 -145
  286. oscura/{exploratory → jupyter/exploratory}/recovery.py +119 -87
  287. oscura/jupyter/exploratory/sync.py +612 -0
  288. oscura/{exploratory → jupyter/exploratory}/unknown.py +299 -176
  289. oscura/jupyter/magic.py +4 -4
  290. oscura/{ui → jupyter/ui}/__init__.py +2 -2
  291. oscura/{ui → jupyter/ui}/formatters.py +3 -3
  292. oscura/{ui → jupyter/ui}/progressive_display.py +153 -82
  293. oscura/loaders/__init__.py +183 -67
  294. oscura/loaders/binary.py +88 -1
  295. oscura/loaders/chipwhisperer.py +153 -137
  296. oscura/loaders/configurable.py +208 -86
  297. oscura/loaders/csv_loader.py +458 -215
  298. oscura/loaders/hdf5_loader.py +278 -119
  299. oscura/loaders/lazy.py +87 -54
  300. oscura/loaders/mmap_loader.py +1 -1
  301. oscura/loaders/numpy_loader.py +253 -116
  302. oscura/loaders/pcap.py +226 -151
  303. oscura/loaders/rigol.py +110 -49
  304. oscura/loaders/sigrok.py +201 -78
  305. oscura/loaders/tdms.py +81 -58
  306. oscura/loaders/tektronix.py +291 -174
  307. oscura/loaders/touchstone.py +182 -87
  308. oscura/loaders/tss.py +456 -0
  309. oscura/loaders/vcd.py +215 -117
  310. oscura/loaders/wav.py +155 -68
  311. oscura/reporting/__init__.py +9 -0
  312. oscura/reporting/analyze.py +352 -146
  313. oscura/reporting/argument_preparer.py +69 -14
  314. oscura/reporting/auto_report.py +97 -61
  315. oscura/reporting/batch.py +131 -58
  316. oscura/reporting/chart_selection.py +57 -45
  317. oscura/reporting/comparison.py +63 -17
  318. oscura/reporting/content/executive.py +76 -24
  319. oscura/reporting/core_formats/multi_format.py +11 -8
  320. oscura/reporting/engine.py +312 -158
  321. oscura/reporting/enhanced_reports.py +949 -0
  322. oscura/reporting/export.py +86 -43
  323. oscura/reporting/formatting/numbers.py +69 -42
  324. oscura/reporting/html.py +139 -58
  325. oscura/reporting/index.py +137 -65
  326. oscura/reporting/output.py +158 -67
  327. oscura/reporting/pdf.py +67 -102
  328. oscura/reporting/plots.py +191 -112
  329. oscura/reporting/sections.py +88 -47
  330. oscura/reporting/standards.py +104 -61
  331. oscura/reporting/summary_generator.py +75 -55
  332. oscura/reporting/tables.py +138 -54
  333. oscura/reporting/templates/enhanced/protocol_re.html +525 -0
  334. oscura/sessions/__init__.py +14 -23
  335. oscura/sessions/base.py +3 -3
  336. oscura/sessions/blackbox.py +106 -10
  337. oscura/sessions/generic.py +2 -2
  338. oscura/sessions/legacy.py +783 -0
  339. oscura/side_channel/__init__.py +63 -0
  340. oscura/side_channel/dpa.py +1025 -0
  341. oscura/utils/__init__.py +15 -1
  342. oscura/utils/bitwise.py +118 -0
  343. oscura/{builders → utils/builders}/__init__.py +1 -1
  344. oscura/{comparison → utils/comparison}/__init__.py +6 -6
  345. oscura/{comparison → utils/comparison}/compare.py +202 -101
  346. oscura/{comparison → utils/comparison}/golden.py +83 -63
  347. oscura/{comparison → utils/comparison}/limits.py +313 -89
  348. oscura/{comparison → utils/comparison}/mask.py +151 -45
  349. oscura/{comparison → utils/comparison}/trace_diff.py +1 -1
  350. oscura/{comparison → utils/comparison}/visualization.py +147 -89
  351. oscura/{component → utils/component}/__init__.py +3 -3
  352. oscura/{component → utils/component}/impedance.py +122 -58
  353. oscura/{component → utils/component}/reactive.py +165 -168
  354. oscura/{component → utils/component}/transmission_line.py +3 -3
  355. oscura/{filtering → utils/filtering}/__init__.py +6 -6
  356. oscura/{filtering → utils/filtering}/base.py +1 -1
  357. oscura/{filtering → utils/filtering}/convenience.py +2 -2
  358. oscura/{filtering → utils/filtering}/design.py +169 -93
  359. oscura/{filtering → utils/filtering}/filters.py +2 -2
  360. oscura/{filtering → utils/filtering}/introspection.py +2 -2
  361. oscura/utils/geometry.py +31 -0
  362. oscura/utils/imports.py +184 -0
  363. oscura/utils/lazy.py +1 -1
  364. oscura/{math → utils/math}/__init__.py +2 -2
  365. oscura/{math → utils/math}/arithmetic.py +114 -48
  366. oscura/{math → utils/math}/interpolation.py +139 -106
  367. oscura/utils/memory.py +129 -66
  368. oscura/utils/memory_advanced.py +92 -9
  369. oscura/utils/memory_extensions.py +10 -8
  370. oscura/{optimization → utils/optimization}/__init__.py +1 -1
  371. oscura/{optimization → utils/optimization}/search.py +2 -2
  372. oscura/utils/performance/__init__.py +58 -0
  373. oscura/utils/performance/caching.py +889 -0
  374. oscura/utils/performance/lsh_clustering.py +333 -0
  375. oscura/utils/performance/memory_optimizer.py +699 -0
  376. oscura/utils/performance/optimizations.py +675 -0
  377. oscura/utils/performance/parallel.py +654 -0
  378. oscura/utils/performance/profiling.py +661 -0
  379. oscura/{pipeline → utils/pipeline}/base.py +1 -1
  380. oscura/{pipeline → utils/pipeline}/composition.py +1 -1
  381. oscura/{pipeline → utils/pipeline}/parallel.py +3 -2
  382. oscura/{pipeline → utils/pipeline}/pipeline.py +1 -1
  383. oscura/{pipeline → utils/pipeline}/reverse_engineering.py +412 -221
  384. oscura/{search → utils/search}/__init__.py +3 -3
  385. oscura/{search → utils/search}/anomaly.py +188 -58
  386. oscura/utils/search/context.py +294 -0
  387. oscura/{search → utils/search}/pattern.py +138 -10
  388. oscura/utils/serial.py +51 -0
  389. oscura/utils/storage/__init__.py +61 -0
  390. oscura/utils/storage/database.py +1166 -0
  391. oscura/{streaming → utils/streaming}/chunked.py +302 -143
  392. oscura/{streaming → utils/streaming}/progressive.py +1 -1
  393. oscura/{streaming → utils/streaming}/realtime.py +3 -2
  394. oscura/{triggering → utils/triggering}/__init__.py +6 -6
  395. oscura/{triggering → utils/triggering}/base.py +6 -6
  396. oscura/{triggering → utils/triggering}/edge.py +2 -2
  397. oscura/{triggering → utils/triggering}/pattern.py +2 -2
  398. oscura/{triggering → utils/triggering}/pulse.py +115 -74
  399. oscura/{triggering → utils/triggering}/window.py +2 -2
  400. oscura/utils/validation.py +32 -0
  401. oscura/validation/__init__.py +121 -0
  402. oscura/{compliance → validation/compliance}/__init__.py +5 -5
  403. oscura/{compliance → validation/compliance}/advanced.py +5 -5
  404. oscura/{compliance → validation/compliance}/masks.py +1 -1
  405. oscura/{compliance → validation/compliance}/reporting.py +127 -53
  406. oscura/{compliance → validation/compliance}/testing.py +114 -52
  407. oscura/validation/compliance_tests.py +915 -0
  408. oscura/validation/fuzzer.py +990 -0
  409. oscura/validation/grammar_tests.py +596 -0
  410. oscura/validation/grammar_validator.py +904 -0
  411. oscura/validation/hil_testing.py +977 -0
  412. oscura/{quality → validation/quality}/__init__.py +4 -4
  413. oscura/{quality → validation/quality}/ensemble.py +251 -171
  414. oscura/{quality → validation/quality}/explainer.py +3 -3
  415. oscura/{quality → validation/quality}/scoring.py +1 -1
  416. oscura/{quality → validation/quality}/warnings.py +4 -4
  417. oscura/validation/regression_suite.py +808 -0
  418. oscura/validation/replay.py +788 -0
  419. oscura/{testing → validation/testing}/__init__.py +2 -2
  420. oscura/{testing → validation/testing}/synthetic.py +5 -5
  421. oscura/visualization/__init__.py +9 -0
  422. oscura/visualization/accessibility.py +1 -1
  423. oscura/visualization/annotations.py +64 -67
  424. oscura/visualization/colors.py +7 -7
  425. oscura/visualization/digital.py +180 -81
  426. oscura/visualization/eye.py +236 -85
  427. oscura/visualization/interactive.py +320 -143
  428. oscura/visualization/jitter.py +587 -247
  429. oscura/visualization/layout.py +169 -134
  430. oscura/visualization/optimization.py +103 -52
  431. oscura/visualization/palettes.py +1 -1
  432. oscura/visualization/power.py +427 -211
  433. oscura/visualization/power_extended.py +626 -297
  434. oscura/visualization/presets.py +2 -0
  435. oscura/visualization/protocols.py +495 -181
  436. oscura/visualization/render.py +79 -63
  437. oscura/visualization/reverse_engineering.py +171 -124
  438. oscura/visualization/signal_integrity.py +460 -279
  439. oscura/visualization/specialized.py +190 -100
  440. oscura/visualization/spectral.py +670 -255
  441. oscura/visualization/thumbnails.py +166 -137
  442. oscura/visualization/waveform.py +150 -63
  443. oscura/workflows/__init__.py +3 -0
  444. oscura/{batch → workflows/batch}/__init__.py +5 -5
  445. oscura/{batch → workflows/batch}/advanced.py +150 -75
  446. oscura/workflows/batch/aggregate.py +531 -0
  447. oscura/workflows/batch/analyze.py +236 -0
  448. oscura/{batch → workflows/batch}/logging.py +2 -2
  449. oscura/{batch → workflows/batch}/metrics.py +1 -1
  450. oscura/workflows/complete_re.py +1144 -0
  451. oscura/workflows/compliance.py +44 -54
  452. oscura/workflows/digital.py +197 -51
  453. oscura/workflows/legacy/__init__.py +12 -0
  454. oscura/{workflow → workflows/legacy}/dag.py +4 -1
  455. oscura/workflows/multi_trace.py +9 -9
  456. oscura/workflows/power.py +42 -62
  457. oscura/workflows/protocol.py +82 -49
  458. oscura/workflows/reverse_engineering.py +351 -150
  459. oscura/workflows/signal_integrity.py +157 -82
  460. oscura-0.7.0.dist-info/METADATA +661 -0
  461. oscura-0.7.0.dist-info/RECORD +591 -0
  462. oscura/batch/aggregate.py +0 -300
  463. oscura/batch/analyze.py +0 -139
  464. oscura/dsl/__init__.py +0 -73
  465. oscura/exceptions.py +0 -59
  466. oscura/exploratory/fuzzy.py +0 -513
  467. oscura/exploratory/sync.py +0 -384
  468. oscura/exporters/__init__.py +0 -94
  469. oscura/exporters/csv.py +0 -303
  470. oscura/exporters/exporters.py +0 -44
  471. oscura/exporters/hdf5.py +0 -217
  472. oscura/exporters/html_export.py +0 -701
  473. oscura/exporters/json_export.py +0 -291
  474. oscura/exporters/markdown_export.py +0 -367
  475. oscura/exporters/matlab_export.py +0 -354
  476. oscura/exporters/npz_export.py +0 -219
  477. oscura/exporters/spice_export.py +0 -210
  478. oscura/search/context.py +0 -149
  479. oscura/session/__init__.py +0 -34
  480. oscura/session/annotations.py +0 -289
  481. oscura/session/history.py +0 -313
  482. oscura/session/session.py +0 -520
  483. oscura/workflow/__init__.py +0 -13
  484. oscura-0.5.1.dist-info/METADATA +0 -583
  485. oscura-0.5.1.dist-info/RECORD +0 -481
  486. /oscura/core/{config.py → config/legacy.py} +0 -0
  487. /oscura/{extensibility → core/extensibility}/__init__.py +0 -0
  488. /oscura/{extensibility → core/extensibility}/registry.py +0 -0
  489. /oscura/{plugins → core/plugins}/isolation.py +0 -0
  490. /oscura/{schemas → core/schemas}/bus_configuration.json +0 -0
  491. /oscura/{builders → utils/builders}/signal_builder.py +0 -0
  492. /oscura/{optimization → utils/optimization}/parallel.py +0 -0
  493. /oscura/{pipeline → utils/pipeline}/__init__.py +0 -0
  494. /oscura/{streaming → utils/streaming}/__init__.py +0 -0
  495. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/WHEEL +0 -0
  496. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/entry_points.txt +0 -0
  497. {oscura-0.5.1.dist-info → oscura-0.7.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
+ ]