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
@@ -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
+ ]