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
@@ -6,7 +6,7 @@ versioning, and CLI operations.
6
6
 
7
7
 
8
8
  Example:
9
- >>> from oscura.plugins.manager import PluginManager
9
+ >>> from oscura.core.plugins.manager import PluginManager
10
10
  >>> manager = PluginManager()
11
11
  >>> manager.discover_and_load()
12
12
  >>> plugin = manager.get_plugin("uart_decoder")
@@ -19,21 +19,21 @@ import logging
19
19
  from pathlib import Path
20
20
  from typing import TYPE_CHECKING, Any
21
21
 
22
- from oscura.plugins.discovery import discover_plugins, get_plugin_paths
23
- from oscura.plugins.isolation import IsolationManager, PermissionSet, ResourceLimits
24
- from oscura.plugins.lifecycle import (
22
+ from oscura.core.plugins.discovery import discover_plugins, get_plugin_paths
23
+ from oscura.core.plugins.isolation import IsolationManager, PermissionSet, ResourceLimits
24
+ from oscura.core.plugins.lifecycle import (
25
25
  DependencyGraph,
26
26
  PluginLifecycleManager,
27
27
  )
28
- from oscura.plugins.registry import (
28
+ from oscura.core.plugins.registry import (
29
29
  PluginConflictError,
30
30
  PluginRegistry,
31
31
  PluginVersionError,
32
32
  )
33
- from oscura.plugins.versioning import MigrationManager
33
+ from oscura.core.plugins.versioning import MigrationManager
34
34
 
35
35
  if TYPE_CHECKING:
36
- from oscura.plugins.base import PluginBase, PluginCapability, PluginMetadata
36
+ from oscura.core.plugins.base import PluginBase, PluginCapability, PluginMetadata
37
37
 
38
38
  logger = logging.getLogger(__name__)
39
39
 
@@ -5,7 +5,7 @@ registering, and accessing plugins.
5
5
 
6
6
 
7
7
  Example:
8
- >>> from oscura.plugins.registry import register_plugin, get_plugin
8
+ >>> from oscura.core.plugins.registry import register_plugin, get_plugin
9
9
  >>> register_plugin(MyDecoder)
10
10
  >>> decoder = get_plugin("my_decoder")
11
11
  """
@@ -15,14 +15,14 @@ from __future__ import annotations
15
15
  import logging
16
16
  from typing import TYPE_CHECKING, Any
17
17
 
18
- from oscura.plugins.discovery import (
18
+ from oscura.core.plugins.discovery import (
19
19
  OSCURA_API_VERSION,
20
20
  DiscoveredPlugin,
21
21
  discover_plugins,
22
22
  )
23
23
 
24
24
  if TYPE_CHECKING:
25
- from oscura.plugins.base import PluginBase, PluginCapability, PluginMetadata
25
+ from oscura.core.plugins.base import PluginBase, PluginCapability, PluginMetadata
26
26
 
27
27
  logger = logging.getLogger(__name__)
28
28
 
@@ -13,7 +13,7 @@ from typing import TYPE_CHECKING, Any
13
13
  if TYPE_CHECKING:
14
14
  from collections.abc import Callable
15
15
 
16
- from oscura.plugins.base import PluginBase
16
+ from oscura.core.plugins.base import PluginBase
17
17
 
18
18
  logger = logging.getLogger(__name__)
19
19
 
oscura/core/progress.py CHANGED
@@ -23,7 +23,14 @@ import time
23
23
  import warnings
24
24
  from typing import TYPE_CHECKING, Protocol
25
25
 
26
- import psutil
26
+ # Lazy import for optional system monitoring
27
+ try:
28
+ import psutil
29
+
30
+ _HAS_PSUTIL = True
31
+ except ImportError:
32
+ psutil = None # type: ignore[assignment]
33
+ _HAS_PSUTIL = False
27
34
 
28
35
  if TYPE_CHECKING:
29
36
  from collections.abc import Callable
@@ -423,6 +430,10 @@ def check_memory_available(required_bytes: int, *, threshold: float = 0.8) -> bo
423
430
  References:
424
431
  PROG-003: Memory Usage Warnings
425
432
  """
433
+ # If psutil not available, assume memory is sufficient
434
+ if not _HAS_PSUTIL:
435
+ return True
436
+
426
437
  memory = psutil.virtual_memory()
427
438
  available_bytes = memory.available
428
439
  threshold_bytes = available_bytes * threshold
@@ -454,6 +465,10 @@ def warn_memory_usage(
454
465
  References:
455
466
  PROG-003: Memory Usage Warnings
456
467
  """
468
+ # If psutil not available, skip memory warning
469
+ if not _HAS_PSUTIL:
470
+ return
471
+
457
472
  memory = psutil.virtual_memory()
458
473
  available_bytes = memory.available
459
474
  threshold_bytes = available_bytes * threshold
oscura/core/provenance.py CHANGED
@@ -17,8 +17,14 @@ import numpy as np
17
17
  if TYPE_CHECKING:
18
18
  from numpy.typing import NDArray
19
19
 
20
- # Oscura version (in production would import from __version__)
21
- OSCURA_VERSION = "0.1.0"
20
+ # Oscura version dynamically imported from package metadata (SSOT: pyproject.toml)
21
+ try:
22
+ from importlib.metadata import version
23
+
24
+ OSCURA_VERSION = version("oscura")
25
+ except Exception:
26
+ # Fallback for development/testing when package not installed
27
+ OSCURA_VERSION = "0.0.0+dev"
22
28
 
23
29
 
24
30
  @dataclass
@@ -6,7 +6,7 @@ device mappings, bus configurations, and protocol definitions.
6
6
 
7
7
 
8
8
  Example:
9
- >>> from oscura.schemas import load_schema, validate_config
9
+ >>> from oscura.core.schemas import load_schema, validate_config
10
10
  >>> schema = load_schema("packet_format")
11
11
  >>> validate_config(config_dict, "packet_format")
12
12
  True
@@ -18,7 +18,7 @@ import json
18
18
  from pathlib import Path
19
19
  from typing import Any
20
20
 
21
- from oscura.config.schema import (
21
+ from oscura.core.config.schema import (
22
22
  ConfigSchema,
23
23
  get_schema_registry,
24
24
  register_schema,
@@ -0,0 +1,322 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://oscura.io/schemas/bus_configuration.json",
4
+ "title": "Bus Configuration Schema",
5
+ "description": "Schema for validating parallel bus configurations for multi-bit protocols (CFG-001).",
6
+ "type": "object",
7
+ "required": ["name", "settings"],
8
+ "additionalProperties": true,
9
+ "properties": {
10
+ "name": {
11
+ "type": "string",
12
+ "description": "Bus configuration identifier",
13
+ "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$",
14
+ "minLength": 1
15
+ },
16
+ "version": {
17
+ "type": "string",
18
+ "description": "Configuration version",
19
+ "pattern": "^\\d+\\.\\d+$"
20
+ },
21
+ "description": {
22
+ "type": "string",
23
+ "description": "Human-readable description"
24
+ },
25
+ "settings": {
26
+ "type": "object",
27
+ "description": "Global bus settings",
28
+ "properties": {
29
+ "active_low": {
30
+ "type": "boolean",
31
+ "description": "Signals are active-low (inverted)"
32
+ },
33
+ "sample_on": {
34
+ "type": "string",
35
+ "enum": ["rising", "falling", "both"],
36
+ "description": "Sample on clock/timing pulse edge"
37
+ },
38
+ "bit_numbering": {
39
+ "type": "string",
40
+ "enum": ["lsb_0", "msb_0"],
41
+ "description": "Bit numbering convention"
42
+ }
43
+ },
44
+ "additionalProperties": false
45
+ },
46
+ "data_bus": {
47
+ "type": "object",
48
+ "description": "Data bus definition",
49
+ "required": ["name", "width", "bits"],
50
+ "properties": {
51
+ "name": {
52
+ "type": "string",
53
+ "description": "Bus name",
54
+ "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$"
55
+ },
56
+ "width": {
57
+ "type": "integer",
58
+ "minimum": 1,
59
+ "maximum": 128,
60
+ "description": "Bus width in bits"
61
+ },
62
+ "description": {
63
+ "type": "string",
64
+ "description": "Bus description"
65
+ },
66
+ "active_low": {
67
+ "type": "boolean",
68
+ "description": "Override global active_low setting"
69
+ },
70
+ "bits": {
71
+ "type": "array",
72
+ "description": "Bit mappings from channel to position",
73
+ "minItems": 1,
74
+ "items": {
75
+ "type": "object",
76
+ "required": ["channel", "bit"],
77
+ "properties": {
78
+ "channel": {
79
+ "type": "integer",
80
+ "minimum": 0,
81
+ "description": "Source channel index"
82
+ },
83
+ "bit": {
84
+ "type": "integer",
85
+ "minimum": 0,
86
+ "description": "Bit position in bus"
87
+ },
88
+ "name": {
89
+ "type": "string",
90
+ "description": "Signal name",
91
+ "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$"
92
+ }
93
+ },
94
+ "additionalProperties": false
95
+ }
96
+ }
97
+ },
98
+ "additionalProperties": false
99
+ },
100
+ "address_bus": {
101
+ "type": "object",
102
+ "description": "Address bus definition",
103
+ "required": ["name", "width", "bits"],
104
+ "properties": {
105
+ "name": {
106
+ "type": "string",
107
+ "description": "Bus name",
108
+ "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$"
109
+ },
110
+ "width": {
111
+ "type": "integer",
112
+ "minimum": 1,
113
+ "maximum": 128,
114
+ "description": "Bus width in bits"
115
+ },
116
+ "description": {
117
+ "type": "string",
118
+ "description": "Bus description"
119
+ },
120
+ "active_low": {
121
+ "type": "boolean",
122
+ "description": "Override global active_low setting"
123
+ },
124
+ "bits": {
125
+ "type": "array",
126
+ "description": "Bit mappings from channel to position",
127
+ "minItems": 1,
128
+ "items": {
129
+ "type": "object",
130
+ "required": ["channel", "bit"],
131
+ "properties": {
132
+ "channel": {
133
+ "type": "integer",
134
+ "minimum": 0,
135
+ "description": "Source channel index"
136
+ },
137
+ "bit": {
138
+ "type": "integer",
139
+ "minimum": 0,
140
+ "description": "Bit position in bus"
141
+ },
142
+ "name": {
143
+ "type": "string",
144
+ "description": "Signal name",
145
+ "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$"
146
+ }
147
+ },
148
+ "additionalProperties": false
149
+ }
150
+ }
151
+ },
152
+ "additionalProperties": false
153
+ },
154
+ "control_signals": {
155
+ "type": "array",
156
+ "description": "Control signal definitions",
157
+ "items": {
158
+ "type": "object",
159
+ "required": ["name", "channel"],
160
+ "properties": {
161
+ "name": {
162
+ "type": "string",
163
+ "description": "Signal name",
164
+ "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$"
165
+ },
166
+ "channel": {
167
+ "type": "integer",
168
+ "minimum": 0,
169
+ "description": "Source channel index"
170
+ },
171
+ "active_low": {
172
+ "type": "boolean",
173
+ "description": "Signal is active-low"
174
+ },
175
+ "description": {
176
+ "type": "string",
177
+ "description": "Signal description"
178
+ },
179
+ "short_name": {
180
+ "type": "string",
181
+ "description": "Short name/abbreviation",
182
+ "maxLength": 8
183
+ }
184
+ },
185
+ "additionalProperties": false
186
+ }
187
+ },
188
+ "timing": {
189
+ "type": "object",
190
+ "description": "Timing constraints and validation",
191
+ "properties": {
192
+ "clock_period_ns": {
193
+ "type": "number",
194
+ "exclusiveMinimum": 0,
195
+ "description": "Clock period in nanoseconds"
196
+ },
197
+ "setup_time_ns": {
198
+ "type": "number",
199
+ "minimum": 0,
200
+ "description": "Setup time requirement in nanoseconds"
201
+ },
202
+ "hold_time_ns": {
203
+ "type": "number",
204
+ "minimum": 0,
205
+ "description": "Hold time requirement in nanoseconds"
206
+ },
207
+ "pulse_width_ns": {
208
+ "type": "object",
209
+ "description": "Pulse width requirements by signal type",
210
+ "additionalProperties": {
211
+ "type": "number",
212
+ "minimum": 0
213
+ }
214
+ }
215
+ },
216
+ "additionalProperties": false
217
+ },
218
+ "transactions": {
219
+ "type": "object",
220
+ "description": "Transaction decoding rules",
221
+ "properties": {
222
+ "types": {
223
+ "type": "array",
224
+ "description": "Transaction type definitions",
225
+ "items": {
226
+ "type": "object",
227
+ "required": ["name", "conditions"],
228
+ "properties": {
229
+ "name": {
230
+ "type": "string",
231
+ "description": "Transaction type name",
232
+ "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$"
233
+ },
234
+ "conditions": {
235
+ "type": "object",
236
+ "description": "Signal conditions for this transaction",
237
+ "additionalProperties": {
238
+ "type": "boolean"
239
+ }
240
+ },
241
+ "sample_on": {
242
+ "type": "string",
243
+ "description": "Control signal to sample on"
244
+ },
245
+ "capture": {
246
+ "type": "object",
247
+ "description": "Buses/signals to capture",
248
+ "additionalProperties": {
249
+ "type": "string"
250
+ }
251
+ }
252
+ },
253
+ "additionalProperties": false
254
+ }
255
+ }
256
+ },
257
+ "additionalProperties": false
258
+ },
259
+ "instruction_decode": {
260
+ "type": "object",
261
+ "description": "Instruction decoding (if data contains opcodes)",
262
+ "properties": {
263
+ "enabled": {
264
+ "type": "boolean",
265
+ "description": "Enable instruction decoding"
266
+ },
267
+ "opcode_bits": {
268
+ "type": "array",
269
+ "description": "Bit range for opcode [start, end]",
270
+ "items": { "type": "integer", "minimum": 0 },
271
+ "minItems": 2,
272
+ "maxItems": 2
273
+ },
274
+ "opcodes": {
275
+ "type": "object",
276
+ "description": "Opcode to instruction mappings (keys can be integers or binary/hex strings)",
277
+ "additionalProperties": {
278
+ "type": "object",
279
+ "required": ["name"],
280
+ "properties": {
281
+ "name": {
282
+ "type": "string",
283
+ "description": "Instruction mnemonic"
284
+ },
285
+ "description": {
286
+ "type": "string",
287
+ "description": "Instruction description"
288
+ }
289
+ },
290
+ "additionalProperties": false
291
+ }
292
+ }
293
+ },
294
+ "additionalProperties": false
295
+ },
296
+ "output": {
297
+ "type": "object",
298
+ "description": "Output formatting options",
299
+ "properties": {
300
+ "format": {
301
+ "type": "string",
302
+ "enum": ["raw", "transaction", "annotated"],
303
+ "description": "Output format type"
304
+ },
305
+ "timestamp_format": {
306
+ "type": "string",
307
+ "enum": ["absolute", "relative_us", "relative_ns", "sample_index"],
308
+ "description": "Timestamp format"
309
+ },
310
+ "include_raw_values": {
311
+ "type": "boolean",
312
+ "description": "Include raw values in output"
313
+ },
314
+ "hex_format": {
315
+ "type": "boolean",
316
+ "description": "Display values in hexadecimal"
317
+ }
318
+ },
319
+ "additionalProperties": false
320
+ }
321
+ }
322
+ }
@@ -0,0 +1,182 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://oscura.io/schemas/device_mapping.json",
4
+ "title": "Device Mapping Configuration Schema",
5
+ "description": "Schema for validating device ID to name mappings and device-specific parameters (CFG-001).",
6
+ "type": "object",
7
+ "required": ["name", "devices"],
8
+ "additionalProperties": true,
9
+ "properties": {
10
+ "name": {
11
+ "type": "string",
12
+ "description": "Mapping configuration identifier",
13
+ "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$",
14
+ "minLength": 1
15
+ },
16
+ "version": {
17
+ "type": "string",
18
+ "description": "Configuration version",
19
+ "pattern": "^\\d+\\.\\d+$"
20
+ },
21
+ "description": {
22
+ "type": "string",
23
+ "description": "Human-readable description"
24
+ },
25
+ "devices": {
26
+ "type": "object",
27
+ "description": "Device ID to configuration mappings (keys can be integers or hex strings)",
28
+ "minProperties": 1,
29
+ "additionalProperties": {
30
+ "type": "object",
31
+ "description": "Device configuration (key is hex 0xNN or decimal ID)",
32
+ "required": ["name"],
33
+ "properties": {
34
+ "name": {
35
+ "type": "string",
36
+ "description": "Full device name",
37
+ "minLength": 1
38
+ },
39
+ "short_name": {
40
+ "type": "string",
41
+ "description": "Short/abbreviated device name",
42
+ "maxLength": 16
43
+ },
44
+ "description": {
45
+ "type": "string",
46
+ "description": "Device description"
47
+ },
48
+ "category": {
49
+ "type": "string",
50
+ "description": "Device category for grouping"
51
+ },
52
+ "sample_rate": {
53
+ "oneOf": [
54
+ { "type": "number", "exclusiveMinimum": 0 },
55
+ {
56
+ "type": "string",
57
+ "pattern": "^[0-9]+(\\.[0-9]+)?[eE][+-]?[0-9]+$"
58
+ }
59
+ ],
60
+ "description": "Device sample rate in Hz (number or scientific notation string)"
61
+ },
62
+ "channels": {
63
+ "type": "integer",
64
+ "minimum": 1,
65
+ "description": "Number of channels"
66
+ },
67
+ "properties": {
68
+ "type": "object",
69
+ "description": "Device-specific properties",
70
+ "additionalProperties": true
71
+ }
72
+ },
73
+ "additionalProperties": false
74
+ }
75
+ },
76
+ "categories": {
77
+ "type": "object",
78
+ "description": "Category definitions for grouping and display",
79
+ "patternProperties": {
80
+ "^[a-zA-Z][a-zA-Z0-9_]*$": {
81
+ "type": "object",
82
+ "properties": {
83
+ "description": {
84
+ "type": "string",
85
+ "description": "Category description"
86
+ },
87
+ "color": {
88
+ "type": "string",
89
+ "description": "Display color (hex format)",
90
+ "pattern": "^#[0-9A-Fa-f]{6}$"
91
+ }
92
+ },
93
+ "additionalProperties": false
94
+ }
95
+ },
96
+ "additionalProperties": false
97
+ },
98
+ "channels": {
99
+ "type": "object",
100
+ "description": "Channel/lane configuration (keys can be integers or numeric strings)",
101
+ "additionalProperties": {
102
+ "type": "object",
103
+ "properties": {
104
+ "name": {
105
+ "type": "string",
106
+ "description": "Channel name"
107
+ },
108
+ "description": {
109
+ "type": "string",
110
+ "description": "Channel description"
111
+ },
112
+ "default_threshold": {
113
+ "type": "number",
114
+ "description": "Default threshold voltage"
115
+ }
116
+ },
117
+ "additionalProperties": false
118
+ }
119
+ },
120
+ "unknown_device": {
121
+ "type": "object",
122
+ "description": "Handling for unknown device IDs",
123
+ "properties": {
124
+ "policy": {
125
+ "type": "string",
126
+ "enum": ["error", "warn", "ignore"],
127
+ "description": "Action when unknown device encountered"
128
+ },
129
+ "default_name": {
130
+ "type": "string",
131
+ "description": "Default name for unknown devices"
132
+ },
133
+ "default_category": {
134
+ "type": "string",
135
+ "description": "Default category for unknown devices"
136
+ }
137
+ },
138
+ "additionalProperties": false
139
+ },
140
+ "filters": {
141
+ "type": "object",
142
+ "description": "Device filtering options",
143
+ "properties": {
144
+ "enabled": {
145
+ "type": "boolean",
146
+ "description": "Enable filtering"
147
+ },
148
+ "include_devices": {
149
+ "type": "array",
150
+ "description": "Device IDs to include (whitelist)",
151
+ "items": {
152
+ "oneOf": [
153
+ { "type": "integer" },
154
+ { "type": "string", "pattern": "^0[xX][0-9A-Fa-f]+$" }
155
+ ]
156
+ }
157
+ },
158
+ "exclude_devices": {
159
+ "type": "array",
160
+ "description": "Device IDs to exclude (blacklist)",
161
+ "items": {
162
+ "oneOf": [
163
+ { "type": "integer" },
164
+ { "type": "string", "pattern": "^0[xX][0-9A-Fa-f]+$" }
165
+ ]
166
+ }
167
+ },
168
+ "include_categories": {
169
+ "type": "array",
170
+ "description": "Categories to include",
171
+ "items": { "type": "string" }
172
+ },
173
+ "exclude_categories": {
174
+ "type": "array",
175
+ "description": "Categories to exclude",
176
+ "items": { "type": "string" }
177
+ }
178
+ },
179
+ "additionalProperties": false
180
+ }
181
+ }
182
+ }