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
@@ -0,0 +1,341 @@
1
+ """LoRaWAN MAC command parsers.
2
+
3
+ This module provides parsers for LoRaWAN MAC commands transmitted in the
4
+ FOpts field or as port 0 payload as defined in LoRaWAN Specification 1.0.3.
5
+
6
+ References:
7
+ LoRaWAN Specification 1.0.3 Section 5 - MAC Commands
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import Any
13
+
14
+ # MAC Command identifiers (CID)
15
+ # Note: Same CID is used for Req(uplink) and Ans(downlink) - direction determines meaning
16
+ MAC_COMMANDS: dict[int, str] = {
17
+ # Class A commands
18
+ 0x02: "LinkCheck", # LinkCheckReq (up) / LinkCheckAns (down)
19
+ 0x03: "LinkADR", # LinkADRReq (down) / LinkADRAns (up)
20
+ 0x04: "DutyCycle", # DutyCycleReq (down) / DutyCycleAns (up)
21
+ 0x05: "RXParamSetup", # RXParamSetupReq (down) / RXParamSetupAns (up)
22
+ 0x06: "DevStatus", # DevStatusReq (down) / DevStatusAns (up)
23
+ 0x07: "NewChannel", # NewChannelReq (down) / NewChannelAns (up)
24
+ 0x08: "RXTimingSetup", # RXTimingSetupReq (down) / RXTimingSetupAns (up)
25
+ 0x09: "TxParamSetup", # TxParamSetupReq (down) / TxParamSetupAns (up) - LoRaWAN 1.0.2+
26
+ 0x0A: "DlChannel", # DlChannelReq (down) / DlChannelAns (up) - LoRaWAN 1.0.2+
27
+ # Class B commands
28
+ 0x10: "PingSlotInfo", # PingSlotInfoReq (up) / PingSlotInfoAns (down)
29
+ 0x11: "PingSlotChannel", # PingSlotChannelReq (down) / PingSlotChannelAns (up)
30
+ 0x12: "BeaconTiming", # BeaconTimingReq (up) / BeaconTimingAns (down) - deprecated in 1.0.3
31
+ 0x13: "BeaconFreq", # BeaconFreqReq (down) / BeaconFreqAns (up)
32
+ }
33
+
34
+ # MAC command lengths (payload bytes after CID)
35
+ # Format: {cid: (uplink_length, downlink_length)}
36
+ MAC_COMMAND_LENGTHS: dict[int, tuple[int, int]] = {
37
+ 0x02: (0, 2), # LinkCheck: Req=0, Ans=2 (margin, gw_cnt)
38
+ 0x03: (4, 1), # LinkADR: Req=4, Ans=1 (status)
39
+ 0x04: (1, 1), # DutyCycle: Req=1, Ans=0
40
+ 0x05: (4, 1), # RXParamSetup: Req=4, Ans=1 (status)
41
+ 0x06: (0, 2), # DevStatus: Req=0, Ans=2 (battery, margin)
42
+ 0x07: (5, 1), # NewChannel: Req=5, Ans=1 (status)
43
+ 0x08: (1, 0), # RXTimingSetup: Req=1, Ans=0
44
+ 0x09: (1, 0), # TxParamSetup: Req=1, Ans=0 (LoRaWAN 1.0.2+)
45
+ 0x0A: (4, 1), # DlChannel: Req=4, Ans=1 (LoRaWAN 1.0.2+)
46
+ 0x10: (1, 1), # PingSlotInfo: Req=1, Ans=0
47
+ 0x11: (4, 1), # PingSlotChannel: Req=4, Ans=1
48
+ 0x12: (0, 3), # BeaconTiming: Req=0, Ans=3 (deprecated)
49
+ 0x13: (3, 1), # BeaconFreq: Req=3, Ans=1
50
+ }
51
+
52
+
53
+ def parse_mac_command(
54
+ cid: int,
55
+ payload: bytes,
56
+ direction: str,
57
+ ) -> dict[str, Any]:
58
+ """Parse a LoRaWAN MAC command.
59
+
60
+ Args:
61
+ cid: Command identifier (CID).
62
+ payload: Command payload bytes (after CID).
63
+ direction: "up" for uplink, "down" for downlink.
64
+
65
+ Returns:
66
+ Dictionary with parsed command fields.
67
+
68
+ Example:
69
+ >>> payload = bytes([0x05, 0x03]) # LinkCheckAns: margin=5, gw_count=3
70
+ >>> result = parse_mac_command(0x02, payload, "down")
71
+ >>> result["margin"]
72
+ 5
73
+ """
74
+ cmd_name = get_mac_command_name(cid, direction)
75
+
76
+ result: dict[str, Any] = {
77
+ "cid": cid,
78
+ "name": cmd_name,
79
+ "direction": direction,
80
+ "payload": payload.hex(),
81
+ }
82
+
83
+ # Dispatch to command-specific parser
84
+ parsers = {
85
+ 0x02: _parse_link_check,
86
+ 0x03: _parse_link_adr,
87
+ 0x04: _parse_duty_cycle,
88
+ 0x05: _parse_rx_param_setup,
89
+ 0x06: _parse_dev_status,
90
+ 0x07: _parse_new_channel,
91
+ 0x08: _parse_rx_timing_setup,
92
+ 0x09: _parse_tx_param_setup,
93
+ 0x0A: _parse_dl_channel,
94
+ }
95
+
96
+ parser = parsers.get(cid)
97
+ if parser:
98
+ parser(payload, direction, result)
99
+
100
+ return result
101
+
102
+
103
+ def _parse_link_check(payload: bytes, direction: str, result: dict[str, Any]) -> None:
104
+ """Parse LinkCheck command.
105
+
106
+ Args:
107
+ payload: Command payload bytes.
108
+ direction: "up" or "down".
109
+ result: Result dictionary to update.
110
+ """
111
+ if direction == "down" and len(payload) >= 2: # LinkCheckAns
112
+ result["margin"] = payload[0]
113
+ result["gw_count"] = payload[1]
114
+ # LinkCheckReq has no payload
115
+
116
+
117
+ def _parse_link_adr(payload: bytes, direction: str, result: dict[str, Any]) -> None:
118
+ """Parse LinkADR command.
119
+
120
+ Args:
121
+ payload: Command payload bytes.
122
+ direction: "up" or "down".
123
+ result: Result dictionary to update.
124
+ """
125
+ if direction == "down" and len(payload) >= 4: # LinkADRReq
126
+ result["data_rate_tx_power"] = payload[0]
127
+ result["ch_mask"] = int.from_bytes(payload[1:3], "little")
128
+ result["redundancy"] = payload[3]
129
+ elif direction == "up" and len(payload) >= 1: # LinkADRAns
130
+ status = payload[0]
131
+ result["power_ack"] = bool(status & 0x04)
132
+ result["data_rate_ack"] = bool(status & 0x02)
133
+ result["channel_mask_ack"] = bool(status & 0x01)
134
+
135
+
136
+ def _parse_duty_cycle(payload: bytes, direction: str, result: dict[str, Any]) -> None:
137
+ """Parse DutyCycle command.
138
+
139
+ Args:
140
+ payload: Command payload bytes.
141
+ direction: "up" or "down".
142
+ result: Result dictionary to update.
143
+ """
144
+ if direction == "down" and len(payload) >= 1: # DutyCycleReq
145
+ result["max_duty_cycle"] = payload[0]
146
+ # DutyCycleAns has no payload
147
+
148
+
149
+ def _parse_rx_param_setup(payload: bytes, direction: str, result: dict[str, Any]) -> None:
150
+ """Parse RXParamSetup command.
151
+
152
+ Args:
153
+ payload: Command payload bytes.
154
+ direction: "up" or "down".
155
+ result: Result dictionary to update.
156
+ """
157
+ if direction == "down" and len(payload) >= 4: # RXParamSetupReq
158
+ result["dl_settings"] = payload[0]
159
+ result["frequency"] = int.from_bytes(payload[1:4], "little")
160
+ elif direction == "up" and len(payload) >= 1: # RXParamSetupAns
161
+ status = payload[0]
162
+ result["rx1_dr_offset_ack"] = bool(status & 0x04)
163
+ result["rx2_data_rate_ack"] = bool(status & 0x02)
164
+ result["channel_ack"] = bool(status & 0x01)
165
+
166
+
167
+ def _parse_dev_status(payload: bytes, direction: str, result: dict[str, Any]) -> None:
168
+ """Parse DevStatus command.
169
+
170
+ Args:
171
+ payload: Command payload bytes.
172
+ direction: "up" or "down".
173
+ result: Result dictionary to update.
174
+ """
175
+ if direction == "up" and len(payload) >= 2: # DevStatusAns
176
+ result["battery"] = payload[0]
177
+ margin = payload[1] & 0x3F
178
+ # Convert to signed 6-bit value
179
+ if margin & 0x20:
180
+ margin = margin - 64
181
+ result["margin"] = margin
182
+ # DevStatusReq has no payload
183
+
184
+
185
+ def _parse_new_channel(payload: bytes, direction: str, result: dict[str, Any]) -> None:
186
+ """Parse NewChannel command.
187
+
188
+ Args:
189
+ payload: Command payload bytes.
190
+ direction: "up" or "down".
191
+ result: Result dictionary to update.
192
+ """
193
+ if direction == "down" and len(payload) >= 5: # NewChannelReq
194
+ result["ch_index"] = payload[0]
195
+ result["freq"] = int.from_bytes(payload[1:4], "little")
196
+ result["dr_range"] = payload[4]
197
+ elif direction == "up" and len(payload) >= 1: # NewChannelAns
198
+ status = payload[0]
199
+ result["data_rate_range_ok"] = bool(status & 0x02)
200
+ result["channel_freq_ok"] = bool(status & 0x01)
201
+
202
+
203
+ def _parse_rx_timing_setup(payload: bytes, direction: str, result: dict[str, Any]) -> None:
204
+ """Parse RXTimingSetup command.
205
+
206
+ Args:
207
+ payload: Command payload bytes.
208
+ direction: "up" or "down".
209
+ result: Result dictionary to update.
210
+ """
211
+ if direction == "down" and len(payload) >= 1: # RXTimingSetupReq
212
+ result["settings"] = payload[0] & 0x0F
213
+ # RXTimingSetupAns has no payload
214
+
215
+
216
+ def _parse_tx_param_setup(payload: bytes, direction: str, result: dict[str, Any]) -> None:
217
+ """Parse TxParamSetup command.
218
+
219
+ Args:
220
+ payload: Command payload bytes.
221
+ direction: "up" or "down".
222
+ result: Result dictionary to update.
223
+ """
224
+ if direction == "down" and len(payload) >= 1: # TxParamSetupReq
225
+ result["eirp_dwell_time"] = payload[0]
226
+ # TxParamSetupAns has no payload
227
+
228
+
229
+ def _parse_dl_channel(payload: bytes, direction: str, result: dict[str, Any]) -> None:
230
+ """Parse DlChannel command.
231
+
232
+ Args:
233
+ payload: Command payload bytes.
234
+ direction: "up" or "down".
235
+ result: Result dictionary to update.
236
+ """
237
+ if direction == "down" and len(payload) >= 4: # DlChannelReq
238
+ result["ch_index"] = payload[0]
239
+ result["freq"] = int.from_bytes(payload[1:4], "little")
240
+ elif direction == "up" and len(payload) >= 1: # DlChannelAns
241
+ status = payload[0]
242
+ result["uplink_freq_exists"] = bool(status & 0x02)
243
+ result["channel_freq_ok"] = bool(status & 0x01)
244
+
245
+
246
+ def parse_mac_commands(
247
+ fopts: bytes,
248
+ direction: str,
249
+ ) -> list[dict[str, Any]]:
250
+ """Parse multiple MAC commands from FOpts field.
251
+
252
+ Args:
253
+ fopts: FOpts field bytes containing MAC commands.
254
+ direction: "up" for uplink, "down" for downlink.
255
+
256
+ Returns:
257
+ List of parsed MAC command dictionaries.
258
+
259
+ Example:
260
+ >>> fopts = bytes([0x02, 0x05, 0x03]) # LinkCheckAns
261
+ >>> commands = parse_mac_commands(fopts, "down")
262
+ >>> len(commands)
263
+ 1
264
+ """
265
+ commands = []
266
+ idx = 0
267
+
268
+ while idx < len(fopts):
269
+ if idx >= len(fopts):
270
+ break
271
+
272
+ cid = fopts[idx]
273
+ idx += 1
274
+
275
+ # Determine payload length
276
+ length = 0
277
+ if cid in MAC_COMMAND_LENGTHS:
278
+ up_len, down_len = MAC_COMMAND_LENGTHS[cid]
279
+ length = up_len if direction == "up" else down_len
280
+
281
+ # Extract payload
282
+ if idx + length <= len(fopts):
283
+ payload = fopts[idx : idx + length]
284
+ idx += length
285
+ else:
286
+ # Insufficient bytes for complete command
287
+ payload = fopts[idx:]
288
+ idx = len(fopts)
289
+
290
+ # Parse command
291
+ cmd = parse_mac_command(cid, payload, direction)
292
+ commands.append(cmd)
293
+
294
+ return commands
295
+
296
+
297
+ def get_mac_command_name(cid: int, direction: str) -> str:
298
+ """Get MAC command name from CID and direction.
299
+
300
+ Args:
301
+ cid: Command identifier.
302
+ direction: "up" for uplink, "down" for downlink.
303
+
304
+ Returns:
305
+ Command name string.
306
+
307
+ Example:
308
+ >>> get_mac_command_name(0x02, "down")
309
+ 'LinkCheckAns'
310
+ """
311
+ base_name = MAC_COMMANDS.get(cid, f"Unknown_0x{cid:02X}")
312
+
313
+ # Unknown commands don't get Req/Ans suffix
314
+ if "Unknown" in base_name:
315
+ return base_name
316
+
317
+ # Add direction-specific suffix
318
+ # Special cases: commands that originated from different directions
319
+ # Most uplink commands use "Req" (request), downlink use "Req" (command/request)
320
+ # Responses use "Ans" (answer)
321
+ if cid in {0x02, 0x10, 0x12}: # LinkCheck, PingSlotInfo, BeaconTiming
322
+ # These are initiated by end device (uplink Req, downlink Ans)
323
+ if direction == "up":
324
+ return f"{base_name}Req"
325
+ else:
326
+ return f"{base_name}Ans"
327
+ else:
328
+ # Most commands are initiated by network server (downlink Req, uplink Ans)
329
+ if direction == "down":
330
+ return f"{base_name}Req"
331
+ else:
332
+ return f"{base_name}Ans"
333
+
334
+
335
+ __all__ = [
336
+ "MAC_COMMANDS",
337
+ "MAC_COMMAND_LENGTHS",
338
+ "get_mac_command_name",
339
+ "parse_mac_command",
340
+ "parse_mac_commands",
341
+ ]
@@ -0,0 +1,27 @@
1
+ """MQTT protocol analysis for versions 3.1.1 and 5.0.
2
+
3
+ This module provides MQTT (Message Queuing Telemetry Transport) protocol
4
+ analysis including packet parsing, topic hierarchy discovery, and session tracking.
5
+
6
+ Example:
7
+ >>> from oscura.iot.mqtt import MQTTAnalyzer, MQTTPacket
8
+ >>> analyzer = MQTTAnalyzer()
9
+ >>> packet = analyzer.parse_packet(mqtt_data, timestamp=0.0)
10
+ >>> topology = analyzer.get_topic_hierarchy()
11
+
12
+ References:
13
+ MQTT 3.1.1: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/
14
+ MQTT 5.0: https://docs.oasis-open.org/mqtt/mqtt/v5.0/
15
+ """
16
+
17
+ from oscura.iot.mqtt.analyzer import (
18
+ MQTTAnalyzer,
19
+ MQTTPacket,
20
+ MQTTSession,
21
+ )
22
+
23
+ __all__ = [
24
+ "MQTTAnalyzer",
25
+ "MQTTPacket",
26
+ "MQTTSession",
27
+ ]