oscura 0.0.1__py3-none-any.whl → 0.1.1__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 (465) hide show
  1. oscura/__init__.py +813 -8
  2. oscura/__main__.py +392 -0
  3. oscura/analyzers/__init__.py +37 -0
  4. oscura/analyzers/digital/__init__.py +177 -0
  5. oscura/analyzers/digital/bus.py +691 -0
  6. oscura/analyzers/digital/clock.py +805 -0
  7. oscura/analyzers/digital/correlation.py +720 -0
  8. oscura/analyzers/digital/edges.py +632 -0
  9. oscura/analyzers/digital/extraction.py +413 -0
  10. oscura/analyzers/digital/quality.py +878 -0
  11. oscura/analyzers/digital/signal_quality.py +877 -0
  12. oscura/analyzers/digital/thresholds.py +708 -0
  13. oscura/analyzers/digital/timing.py +1104 -0
  14. oscura/analyzers/eye/__init__.py +46 -0
  15. oscura/analyzers/eye/diagram.py +434 -0
  16. oscura/analyzers/eye/metrics.py +555 -0
  17. oscura/analyzers/jitter/__init__.py +83 -0
  18. oscura/analyzers/jitter/ber.py +333 -0
  19. oscura/analyzers/jitter/decomposition.py +759 -0
  20. oscura/analyzers/jitter/measurements.py +413 -0
  21. oscura/analyzers/jitter/spectrum.py +220 -0
  22. oscura/analyzers/measurements.py +40 -0
  23. oscura/analyzers/packet/__init__.py +171 -0
  24. oscura/analyzers/packet/daq.py +1077 -0
  25. oscura/analyzers/packet/metrics.py +437 -0
  26. oscura/analyzers/packet/parser.py +327 -0
  27. oscura/analyzers/packet/payload.py +2156 -0
  28. oscura/analyzers/packet/payload_analysis.py +1312 -0
  29. oscura/analyzers/packet/payload_extraction.py +236 -0
  30. oscura/analyzers/packet/payload_patterns.py +670 -0
  31. oscura/analyzers/packet/stream.py +359 -0
  32. oscura/analyzers/patterns/__init__.py +266 -0
  33. oscura/analyzers/patterns/clustering.py +1036 -0
  34. oscura/analyzers/patterns/discovery.py +539 -0
  35. oscura/analyzers/patterns/learning.py +797 -0
  36. oscura/analyzers/patterns/matching.py +1091 -0
  37. oscura/analyzers/patterns/periodic.py +650 -0
  38. oscura/analyzers/patterns/sequences.py +767 -0
  39. oscura/analyzers/power/__init__.py +116 -0
  40. oscura/analyzers/power/ac_power.py +391 -0
  41. oscura/analyzers/power/basic.py +383 -0
  42. oscura/analyzers/power/conduction.py +314 -0
  43. oscura/analyzers/power/efficiency.py +297 -0
  44. oscura/analyzers/power/ripple.py +356 -0
  45. oscura/analyzers/power/soa.py +372 -0
  46. oscura/analyzers/power/switching.py +479 -0
  47. oscura/analyzers/protocol/__init__.py +150 -0
  48. oscura/analyzers/protocols/__init__.py +150 -0
  49. oscura/analyzers/protocols/base.py +500 -0
  50. oscura/analyzers/protocols/can.py +620 -0
  51. oscura/analyzers/protocols/can_fd.py +448 -0
  52. oscura/analyzers/protocols/flexray.py +405 -0
  53. oscura/analyzers/protocols/hdlc.py +399 -0
  54. oscura/analyzers/protocols/i2c.py +368 -0
  55. oscura/analyzers/protocols/i2s.py +296 -0
  56. oscura/analyzers/protocols/jtag.py +393 -0
  57. oscura/analyzers/protocols/lin.py +445 -0
  58. oscura/analyzers/protocols/manchester.py +333 -0
  59. oscura/analyzers/protocols/onewire.py +501 -0
  60. oscura/analyzers/protocols/spi.py +334 -0
  61. oscura/analyzers/protocols/swd.py +325 -0
  62. oscura/analyzers/protocols/uart.py +393 -0
  63. oscura/analyzers/protocols/usb.py +495 -0
  64. oscura/analyzers/signal_integrity/__init__.py +63 -0
  65. oscura/analyzers/signal_integrity/embedding.py +294 -0
  66. oscura/analyzers/signal_integrity/equalization.py +370 -0
  67. oscura/analyzers/signal_integrity/sparams.py +484 -0
  68. oscura/analyzers/spectral/__init__.py +53 -0
  69. oscura/analyzers/spectral/chunked.py +273 -0
  70. oscura/analyzers/spectral/chunked_fft.py +571 -0
  71. oscura/analyzers/spectral/chunked_wavelet.py +391 -0
  72. oscura/analyzers/spectral/fft.py +92 -0
  73. oscura/analyzers/statistical/__init__.py +250 -0
  74. oscura/analyzers/statistical/checksum.py +923 -0
  75. oscura/analyzers/statistical/chunked_corr.py +228 -0
  76. oscura/analyzers/statistical/classification.py +778 -0
  77. oscura/analyzers/statistical/entropy.py +1113 -0
  78. oscura/analyzers/statistical/ngrams.py +614 -0
  79. oscura/analyzers/statistics/__init__.py +119 -0
  80. oscura/analyzers/statistics/advanced.py +885 -0
  81. oscura/analyzers/statistics/basic.py +263 -0
  82. oscura/analyzers/statistics/correlation.py +630 -0
  83. oscura/analyzers/statistics/distribution.py +298 -0
  84. oscura/analyzers/statistics/outliers.py +463 -0
  85. oscura/analyzers/statistics/streaming.py +93 -0
  86. oscura/analyzers/statistics/trend.py +520 -0
  87. oscura/analyzers/validation.py +598 -0
  88. oscura/analyzers/waveform/__init__.py +36 -0
  89. oscura/analyzers/waveform/measurements.py +943 -0
  90. oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
  91. oscura/analyzers/waveform/spectral.py +1689 -0
  92. oscura/analyzers/waveform/wavelets.py +298 -0
  93. oscura/api/__init__.py +62 -0
  94. oscura/api/dsl.py +538 -0
  95. oscura/api/fluent.py +571 -0
  96. oscura/api/operators.py +498 -0
  97. oscura/api/optimization.py +392 -0
  98. oscura/api/profiling.py +396 -0
  99. oscura/automotive/__init__.py +73 -0
  100. oscura/automotive/can/__init__.py +52 -0
  101. oscura/automotive/can/analysis.py +356 -0
  102. oscura/automotive/can/checksum.py +250 -0
  103. oscura/automotive/can/correlation.py +212 -0
  104. oscura/automotive/can/discovery.py +355 -0
  105. oscura/automotive/can/message_wrapper.py +375 -0
  106. oscura/automotive/can/models.py +385 -0
  107. oscura/automotive/can/patterns.py +381 -0
  108. oscura/automotive/can/session.py +452 -0
  109. oscura/automotive/can/state_machine.py +300 -0
  110. oscura/automotive/can/stimulus_response.py +461 -0
  111. oscura/automotive/dbc/__init__.py +15 -0
  112. oscura/automotive/dbc/generator.py +156 -0
  113. oscura/automotive/dbc/parser.py +146 -0
  114. oscura/automotive/dtc/__init__.py +30 -0
  115. oscura/automotive/dtc/database.py +3036 -0
  116. oscura/automotive/j1939/__init__.py +14 -0
  117. oscura/automotive/j1939/decoder.py +745 -0
  118. oscura/automotive/loaders/__init__.py +35 -0
  119. oscura/automotive/loaders/asc.py +98 -0
  120. oscura/automotive/loaders/blf.py +77 -0
  121. oscura/automotive/loaders/csv_can.py +136 -0
  122. oscura/automotive/loaders/dispatcher.py +136 -0
  123. oscura/automotive/loaders/mdf.py +331 -0
  124. oscura/automotive/loaders/pcap.py +132 -0
  125. oscura/automotive/obd/__init__.py +14 -0
  126. oscura/automotive/obd/decoder.py +707 -0
  127. oscura/automotive/uds/__init__.py +48 -0
  128. oscura/automotive/uds/decoder.py +265 -0
  129. oscura/automotive/uds/models.py +64 -0
  130. oscura/automotive/visualization.py +369 -0
  131. oscura/batch/__init__.py +55 -0
  132. oscura/batch/advanced.py +627 -0
  133. oscura/batch/aggregate.py +300 -0
  134. oscura/batch/analyze.py +139 -0
  135. oscura/batch/logging.py +487 -0
  136. oscura/batch/metrics.py +556 -0
  137. oscura/builders/__init__.py +41 -0
  138. oscura/builders/signal_builder.py +1131 -0
  139. oscura/cli/__init__.py +14 -0
  140. oscura/cli/batch.py +339 -0
  141. oscura/cli/characterize.py +273 -0
  142. oscura/cli/compare.py +775 -0
  143. oscura/cli/decode.py +551 -0
  144. oscura/cli/main.py +247 -0
  145. oscura/cli/shell.py +350 -0
  146. oscura/comparison/__init__.py +66 -0
  147. oscura/comparison/compare.py +397 -0
  148. oscura/comparison/golden.py +487 -0
  149. oscura/comparison/limits.py +391 -0
  150. oscura/comparison/mask.py +434 -0
  151. oscura/comparison/trace_diff.py +30 -0
  152. oscura/comparison/visualization.py +481 -0
  153. oscura/compliance/__init__.py +70 -0
  154. oscura/compliance/advanced.py +756 -0
  155. oscura/compliance/masks.py +363 -0
  156. oscura/compliance/reporting.py +483 -0
  157. oscura/compliance/testing.py +298 -0
  158. oscura/component/__init__.py +38 -0
  159. oscura/component/impedance.py +365 -0
  160. oscura/component/reactive.py +598 -0
  161. oscura/component/transmission_line.py +312 -0
  162. oscura/config/__init__.py +191 -0
  163. oscura/config/defaults.py +254 -0
  164. oscura/config/loader.py +348 -0
  165. oscura/config/memory.py +271 -0
  166. oscura/config/migration.py +458 -0
  167. oscura/config/pipeline.py +1077 -0
  168. oscura/config/preferences.py +530 -0
  169. oscura/config/protocol.py +875 -0
  170. oscura/config/schema.py +713 -0
  171. oscura/config/settings.py +420 -0
  172. oscura/config/thresholds.py +599 -0
  173. oscura/convenience.py +457 -0
  174. oscura/core/__init__.py +299 -0
  175. oscura/core/audit.py +457 -0
  176. oscura/core/backend_selector.py +405 -0
  177. oscura/core/cache.py +590 -0
  178. oscura/core/cancellation.py +439 -0
  179. oscura/core/confidence.py +225 -0
  180. oscura/core/config.py +506 -0
  181. oscura/core/correlation.py +216 -0
  182. oscura/core/cross_domain.py +422 -0
  183. oscura/core/debug.py +301 -0
  184. oscura/core/edge_cases.py +541 -0
  185. oscura/core/exceptions.py +535 -0
  186. oscura/core/gpu_backend.py +523 -0
  187. oscura/core/lazy.py +832 -0
  188. oscura/core/log_query.py +540 -0
  189. oscura/core/logging.py +931 -0
  190. oscura/core/logging_advanced.py +952 -0
  191. oscura/core/memoize.py +171 -0
  192. oscura/core/memory_check.py +274 -0
  193. oscura/core/memory_guard.py +290 -0
  194. oscura/core/memory_limits.py +336 -0
  195. oscura/core/memory_monitor.py +453 -0
  196. oscura/core/memory_progress.py +465 -0
  197. oscura/core/memory_warnings.py +315 -0
  198. oscura/core/numba_backend.py +362 -0
  199. oscura/core/performance.py +352 -0
  200. oscura/core/progress.py +524 -0
  201. oscura/core/provenance.py +358 -0
  202. oscura/core/results.py +331 -0
  203. oscura/core/types.py +504 -0
  204. oscura/core/uncertainty.py +383 -0
  205. oscura/discovery/__init__.py +52 -0
  206. oscura/discovery/anomaly_detector.py +672 -0
  207. oscura/discovery/auto_decoder.py +415 -0
  208. oscura/discovery/comparison.py +497 -0
  209. oscura/discovery/quality_validator.py +528 -0
  210. oscura/discovery/signal_detector.py +769 -0
  211. oscura/dsl/__init__.py +73 -0
  212. oscura/dsl/commands.py +246 -0
  213. oscura/dsl/interpreter.py +455 -0
  214. oscura/dsl/parser.py +689 -0
  215. oscura/dsl/repl.py +172 -0
  216. oscura/exceptions.py +59 -0
  217. oscura/exploratory/__init__.py +111 -0
  218. oscura/exploratory/error_recovery.py +642 -0
  219. oscura/exploratory/fuzzy.py +513 -0
  220. oscura/exploratory/fuzzy_advanced.py +786 -0
  221. oscura/exploratory/legacy.py +831 -0
  222. oscura/exploratory/parse.py +358 -0
  223. oscura/exploratory/recovery.py +275 -0
  224. oscura/exploratory/sync.py +382 -0
  225. oscura/exploratory/unknown.py +707 -0
  226. oscura/export/__init__.py +25 -0
  227. oscura/export/wireshark/README.md +265 -0
  228. oscura/export/wireshark/__init__.py +47 -0
  229. oscura/export/wireshark/generator.py +312 -0
  230. oscura/export/wireshark/lua_builder.py +159 -0
  231. oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
  232. oscura/export/wireshark/type_mapping.py +165 -0
  233. oscura/export/wireshark/validator.py +105 -0
  234. oscura/exporters/__init__.py +94 -0
  235. oscura/exporters/csv.py +303 -0
  236. oscura/exporters/exporters.py +44 -0
  237. oscura/exporters/hdf5.py +219 -0
  238. oscura/exporters/html_export.py +701 -0
  239. oscura/exporters/json_export.py +291 -0
  240. oscura/exporters/markdown_export.py +367 -0
  241. oscura/exporters/matlab_export.py +354 -0
  242. oscura/exporters/npz_export.py +219 -0
  243. oscura/exporters/spice_export.py +210 -0
  244. oscura/extensibility/__init__.py +131 -0
  245. oscura/extensibility/docs.py +752 -0
  246. oscura/extensibility/extensions.py +1125 -0
  247. oscura/extensibility/logging.py +259 -0
  248. oscura/extensibility/measurements.py +485 -0
  249. oscura/extensibility/plugins.py +414 -0
  250. oscura/extensibility/registry.py +346 -0
  251. oscura/extensibility/templates.py +913 -0
  252. oscura/extensibility/validation.py +651 -0
  253. oscura/filtering/__init__.py +89 -0
  254. oscura/filtering/base.py +563 -0
  255. oscura/filtering/convenience.py +564 -0
  256. oscura/filtering/design.py +725 -0
  257. oscura/filtering/filters.py +32 -0
  258. oscura/filtering/introspection.py +605 -0
  259. oscura/guidance/__init__.py +24 -0
  260. oscura/guidance/recommender.py +429 -0
  261. oscura/guidance/wizard.py +518 -0
  262. oscura/inference/__init__.py +251 -0
  263. oscura/inference/active_learning/README.md +153 -0
  264. oscura/inference/active_learning/__init__.py +38 -0
  265. oscura/inference/active_learning/lstar.py +257 -0
  266. oscura/inference/active_learning/observation_table.py +230 -0
  267. oscura/inference/active_learning/oracle.py +78 -0
  268. oscura/inference/active_learning/teachers/__init__.py +15 -0
  269. oscura/inference/active_learning/teachers/simulator.py +192 -0
  270. oscura/inference/adaptive_tuning.py +453 -0
  271. oscura/inference/alignment.py +653 -0
  272. oscura/inference/bayesian.py +943 -0
  273. oscura/inference/binary.py +1016 -0
  274. oscura/inference/crc_reverse.py +711 -0
  275. oscura/inference/logic.py +288 -0
  276. oscura/inference/message_format.py +1305 -0
  277. oscura/inference/protocol.py +417 -0
  278. oscura/inference/protocol_dsl.py +1084 -0
  279. oscura/inference/protocol_library.py +1230 -0
  280. oscura/inference/sequences.py +809 -0
  281. oscura/inference/signal_intelligence.py +1509 -0
  282. oscura/inference/spectral.py +215 -0
  283. oscura/inference/state_machine.py +634 -0
  284. oscura/inference/stream.py +918 -0
  285. oscura/integrations/__init__.py +59 -0
  286. oscura/integrations/llm.py +1827 -0
  287. oscura/jupyter/__init__.py +32 -0
  288. oscura/jupyter/display.py +268 -0
  289. oscura/jupyter/magic.py +334 -0
  290. oscura/loaders/__init__.py +526 -0
  291. oscura/loaders/binary.py +69 -0
  292. oscura/loaders/configurable.py +1255 -0
  293. oscura/loaders/csv.py +26 -0
  294. oscura/loaders/csv_loader.py +473 -0
  295. oscura/loaders/hdf5.py +9 -0
  296. oscura/loaders/hdf5_loader.py +510 -0
  297. oscura/loaders/lazy.py +370 -0
  298. oscura/loaders/mmap_loader.py +583 -0
  299. oscura/loaders/numpy_loader.py +436 -0
  300. oscura/loaders/pcap.py +432 -0
  301. oscura/loaders/preprocessing.py +368 -0
  302. oscura/loaders/rigol.py +287 -0
  303. oscura/loaders/sigrok.py +321 -0
  304. oscura/loaders/tdms.py +367 -0
  305. oscura/loaders/tektronix.py +711 -0
  306. oscura/loaders/validation.py +584 -0
  307. oscura/loaders/vcd.py +464 -0
  308. oscura/loaders/wav.py +233 -0
  309. oscura/math/__init__.py +45 -0
  310. oscura/math/arithmetic.py +824 -0
  311. oscura/math/interpolation.py +413 -0
  312. oscura/onboarding/__init__.py +39 -0
  313. oscura/onboarding/help.py +498 -0
  314. oscura/onboarding/tutorials.py +405 -0
  315. oscura/onboarding/wizard.py +466 -0
  316. oscura/optimization/__init__.py +19 -0
  317. oscura/optimization/parallel.py +440 -0
  318. oscura/optimization/search.py +532 -0
  319. oscura/pipeline/__init__.py +43 -0
  320. oscura/pipeline/base.py +338 -0
  321. oscura/pipeline/composition.py +242 -0
  322. oscura/pipeline/parallel.py +448 -0
  323. oscura/pipeline/pipeline.py +375 -0
  324. oscura/pipeline/reverse_engineering.py +1119 -0
  325. oscura/plugins/__init__.py +122 -0
  326. oscura/plugins/base.py +272 -0
  327. oscura/plugins/cli.py +497 -0
  328. oscura/plugins/discovery.py +411 -0
  329. oscura/plugins/isolation.py +418 -0
  330. oscura/plugins/lifecycle.py +959 -0
  331. oscura/plugins/manager.py +493 -0
  332. oscura/plugins/registry.py +421 -0
  333. oscura/plugins/versioning.py +372 -0
  334. oscura/py.typed +0 -0
  335. oscura/quality/__init__.py +65 -0
  336. oscura/quality/ensemble.py +740 -0
  337. oscura/quality/explainer.py +338 -0
  338. oscura/quality/scoring.py +616 -0
  339. oscura/quality/warnings.py +456 -0
  340. oscura/reporting/__init__.py +248 -0
  341. oscura/reporting/advanced.py +1234 -0
  342. oscura/reporting/analyze.py +448 -0
  343. oscura/reporting/argument_preparer.py +596 -0
  344. oscura/reporting/auto_report.py +507 -0
  345. oscura/reporting/batch.py +615 -0
  346. oscura/reporting/chart_selection.py +223 -0
  347. oscura/reporting/comparison.py +330 -0
  348. oscura/reporting/config.py +615 -0
  349. oscura/reporting/content/__init__.py +39 -0
  350. oscura/reporting/content/executive.py +127 -0
  351. oscura/reporting/content/filtering.py +191 -0
  352. oscura/reporting/content/minimal.py +257 -0
  353. oscura/reporting/content/verbosity.py +162 -0
  354. oscura/reporting/core.py +508 -0
  355. oscura/reporting/core_formats/__init__.py +17 -0
  356. oscura/reporting/core_formats/multi_format.py +210 -0
  357. oscura/reporting/engine.py +836 -0
  358. oscura/reporting/export.py +366 -0
  359. oscura/reporting/formatting/__init__.py +129 -0
  360. oscura/reporting/formatting/emphasis.py +81 -0
  361. oscura/reporting/formatting/numbers.py +403 -0
  362. oscura/reporting/formatting/standards.py +55 -0
  363. oscura/reporting/formatting.py +466 -0
  364. oscura/reporting/html.py +578 -0
  365. oscura/reporting/index.py +590 -0
  366. oscura/reporting/multichannel.py +296 -0
  367. oscura/reporting/output.py +379 -0
  368. oscura/reporting/pdf.py +373 -0
  369. oscura/reporting/plots.py +731 -0
  370. oscura/reporting/pptx_export.py +360 -0
  371. oscura/reporting/renderers/__init__.py +11 -0
  372. oscura/reporting/renderers/pdf.py +94 -0
  373. oscura/reporting/sections.py +471 -0
  374. oscura/reporting/standards.py +680 -0
  375. oscura/reporting/summary_generator.py +368 -0
  376. oscura/reporting/tables.py +397 -0
  377. oscura/reporting/template_system.py +724 -0
  378. oscura/reporting/templates/__init__.py +15 -0
  379. oscura/reporting/templates/definition.py +205 -0
  380. oscura/reporting/templates/index.html +649 -0
  381. oscura/reporting/templates/index.md +173 -0
  382. oscura/schemas/__init__.py +158 -0
  383. oscura/schemas/bus_configuration.json +322 -0
  384. oscura/schemas/device_mapping.json +182 -0
  385. oscura/schemas/packet_format.json +418 -0
  386. oscura/schemas/protocol_definition.json +363 -0
  387. oscura/search/__init__.py +16 -0
  388. oscura/search/anomaly.py +292 -0
  389. oscura/search/context.py +149 -0
  390. oscura/search/pattern.py +160 -0
  391. oscura/session/__init__.py +34 -0
  392. oscura/session/annotations.py +289 -0
  393. oscura/session/history.py +313 -0
  394. oscura/session/session.py +445 -0
  395. oscura/streaming/__init__.py +43 -0
  396. oscura/streaming/chunked.py +611 -0
  397. oscura/streaming/progressive.py +393 -0
  398. oscura/streaming/realtime.py +622 -0
  399. oscura/testing/__init__.py +54 -0
  400. oscura/testing/synthetic.py +808 -0
  401. oscura/triggering/__init__.py +68 -0
  402. oscura/triggering/base.py +229 -0
  403. oscura/triggering/edge.py +353 -0
  404. oscura/triggering/pattern.py +344 -0
  405. oscura/triggering/pulse.py +581 -0
  406. oscura/triggering/window.py +453 -0
  407. oscura/ui/__init__.py +48 -0
  408. oscura/ui/formatters.py +526 -0
  409. oscura/ui/progressive_display.py +340 -0
  410. oscura/utils/__init__.py +99 -0
  411. oscura/utils/autodetect.py +338 -0
  412. oscura/utils/buffer.py +389 -0
  413. oscura/utils/lazy.py +407 -0
  414. oscura/utils/lazy_imports.py +147 -0
  415. oscura/utils/memory.py +836 -0
  416. oscura/utils/memory_advanced.py +1326 -0
  417. oscura/utils/memory_extensions.py +465 -0
  418. oscura/utils/progressive.py +352 -0
  419. oscura/utils/windowing.py +362 -0
  420. oscura/visualization/__init__.py +321 -0
  421. oscura/visualization/accessibility.py +526 -0
  422. oscura/visualization/annotations.py +374 -0
  423. oscura/visualization/axis_scaling.py +305 -0
  424. oscura/visualization/colors.py +453 -0
  425. oscura/visualization/digital.py +337 -0
  426. oscura/visualization/eye.py +420 -0
  427. oscura/visualization/histogram.py +281 -0
  428. oscura/visualization/interactive.py +858 -0
  429. oscura/visualization/jitter.py +702 -0
  430. oscura/visualization/keyboard.py +394 -0
  431. oscura/visualization/layout.py +365 -0
  432. oscura/visualization/optimization.py +1028 -0
  433. oscura/visualization/palettes.py +446 -0
  434. oscura/visualization/plot.py +92 -0
  435. oscura/visualization/power.py +290 -0
  436. oscura/visualization/power_extended.py +626 -0
  437. oscura/visualization/presets.py +467 -0
  438. oscura/visualization/protocols.py +932 -0
  439. oscura/visualization/render.py +207 -0
  440. oscura/visualization/rendering.py +444 -0
  441. oscura/visualization/reverse_engineering.py +791 -0
  442. oscura/visualization/signal_integrity.py +808 -0
  443. oscura/visualization/specialized.py +553 -0
  444. oscura/visualization/spectral.py +811 -0
  445. oscura/visualization/styles.py +381 -0
  446. oscura/visualization/thumbnails.py +311 -0
  447. oscura/visualization/time_axis.py +351 -0
  448. oscura/visualization/waveform.py +367 -0
  449. oscura/workflow/__init__.py +13 -0
  450. oscura/workflow/dag.py +377 -0
  451. oscura/workflows/__init__.py +58 -0
  452. oscura/workflows/compliance.py +280 -0
  453. oscura/workflows/digital.py +272 -0
  454. oscura/workflows/multi_trace.py +502 -0
  455. oscura/workflows/power.py +178 -0
  456. oscura/workflows/protocol.py +492 -0
  457. oscura/workflows/reverse_engineering.py +639 -0
  458. oscura/workflows/signal_integrity.py +227 -0
  459. oscura-0.1.1.dist-info/METADATA +300 -0
  460. oscura-0.1.1.dist-info/RECORD +463 -0
  461. oscura-0.1.1.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/licenses/LICENSE +1 -1
  463. oscura-0.0.1.dist-info/METADATA +0 -63
  464. oscura-0.0.1.dist-info/RECORD +0 -5
  465. {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,1230 @@
1
+ """Protocol Format Library for common protocol definitions.
2
+
3
+ - RE-DSL-003: Protocol Format Library
4
+
5
+ This module provides a library of common protocol definitions for industrial,
6
+ IoT, and communication protocols to enable immediate decoding without
7
+ user-defined definitions.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass
13
+ from typing import Literal, overload
14
+
15
+ from oscura.inference.protocol_dsl import (
16
+ FieldDefinition,
17
+ ProtocolDecoder,
18
+ ProtocolDefinition,
19
+ )
20
+
21
+
22
+ @dataclass
23
+ class ProtocolInfo:
24
+ """Information about a protocol in the library.
25
+
26
+ Attributes:
27
+ name: Protocol name.
28
+ category: Protocol category.
29
+ version: Protocol version.
30
+ description: Human-readable description.
31
+ reference: Reference documentation URL.
32
+ definition: Protocol definition for decoding.
33
+ """
34
+
35
+ name: str
36
+ category: Literal["industrial", "iot", "network", "automotive", "building", "serial", "custom"]
37
+ version: str
38
+ description: str
39
+ reference: str = ""
40
+ definition: ProtocolDefinition | None = None
41
+
42
+
43
+ class ProtocolLibrary:
44
+ """Library of common protocol definitions.
45
+
46
+ Implements RE-DSL-003: Protocol Format Library.
47
+
48
+ Provides pre-defined protocol definitions for common industrial,
49
+ IoT, and communication protocols.
50
+
51
+ Example:
52
+ >>> library = ProtocolLibrary()
53
+ >>> modbus = library.get("modbus_rtu")
54
+ >>> decoder = library.get_decoder("modbus_rtu")
55
+ >>> message = decoder.decode(data)
56
+ """
57
+
58
+ def __init__(self) -> None:
59
+ """Initialize protocol library with built-in protocols."""
60
+ self._protocols: dict[str, ProtocolInfo] = {}
61
+ self._decoders: dict[str, ProtocolDecoder] = {}
62
+ self._load_builtin_protocols()
63
+
64
+ def _load_builtin_protocols(self) -> None:
65
+ """Load all built-in protocol definitions."""
66
+ # Industrial protocols
67
+ self._add_modbus_rtu()
68
+ self._add_modbus_tcp()
69
+ self._add_dnp3()
70
+ self._add_bacnet()
71
+
72
+ # IoT protocols
73
+ self._add_mqtt()
74
+ self._add_coap()
75
+ self._add_cbor()
76
+ self._add_messagepack()
77
+
78
+ # Automotive protocols
79
+ self._add_obd2()
80
+ self._add_j1939()
81
+ self._add_can()
82
+
83
+ # Network protocols
84
+ self._add_http()
85
+ self._add_dns()
86
+ self._add_ntp()
87
+ self._add_syslog()
88
+
89
+ # Serial protocols
90
+ self._add_nmea()
91
+ self._add_xmodem()
92
+
93
+ # Building automation
94
+ self._add_knx()
95
+ self._add_lonworks()
96
+
97
+ # Custom/generic
98
+ self._add_tlv()
99
+ self._add_length_prefixed()
100
+
101
+ def list_protocols(self, category: str | None = None) -> list[ProtocolInfo]:
102
+ """List available protocols.
103
+
104
+ Args:
105
+ category: Filter by category (optional).
106
+
107
+ Returns:
108
+ List of ProtocolInfo for available protocols.
109
+
110
+ Example:
111
+ >>> protocols = library.list_protocols(category="industrial")
112
+ >>> for p in protocols:
113
+ ... print(f"{p.name}: {p.description}")
114
+ """
115
+ protocols = list(self._protocols.values())
116
+ if category:
117
+ protocols = [p for p in protocols if p.category == category]
118
+ return protocols
119
+
120
+ def list_protocol_names(self, category: str | None = None) -> list[str]:
121
+ """List available protocol names.
122
+
123
+ Args:
124
+ category: Filter by category (optional).
125
+
126
+ Returns:
127
+ List of protocol name strings.
128
+ """
129
+ protocols = self.list_protocols(category)
130
+ return [p.name for p in protocols]
131
+
132
+ def get(self, name: str) -> ProtocolInfo | None:
133
+ """Get protocol information by name.
134
+
135
+ Args:
136
+ name: Protocol name (case-insensitive).
137
+
138
+ Returns:
139
+ ProtocolInfo or None if not found.
140
+ """
141
+ return self._protocols.get(name.lower())
142
+
143
+ def get_decoder(self, name: str) -> ProtocolDecoder | None:
144
+ """Get a decoder for a protocol.
145
+
146
+ Args:
147
+ name: Protocol name.
148
+
149
+ Returns:
150
+ ProtocolDecoder instance or None if not found.
151
+
152
+ Example:
153
+ >>> decoder = library.get_decoder("modbus_rtu")
154
+ >>> if decoder:
155
+ ... message = decoder.decode(data)
156
+ """
157
+ name = name.lower()
158
+ if name in self._decoders:
159
+ return self._decoders[name]
160
+
161
+ info = self._protocols.get(name)
162
+ if info and info.definition:
163
+ decoder = ProtocolDecoder(info.definition)
164
+ self._decoders[name] = decoder
165
+ return decoder
166
+
167
+ return None
168
+
169
+ def get_definition(self, name: str) -> ProtocolDefinition | None:
170
+ """Get protocol definition by name.
171
+
172
+ Args:
173
+ name: Protocol name.
174
+
175
+ Returns:
176
+ ProtocolDefinition or None if not found.
177
+ """
178
+ info = self._protocols.get(name.lower())
179
+ return info.definition if info else None
180
+
181
+ def add_protocol(
182
+ self,
183
+ info: ProtocolInfo,
184
+ ) -> None:
185
+ """Add a custom protocol to the library.
186
+
187
+ Args:
188
+ info: Protocol information and definition.
189
+
190
+ Example:
191
+ >>> custom = ProtocolInfo(
192
+ ... name="my_protocol",
193
+ ... category="custom",
194
+ ... version="1.0",
195
+ ... description="My custom protocol",
196
+ ... definition=my_definition
197
+ ... )
198
+ >>> library.add_protocol(custom)
199
+ """
200
+ self._protocols[info.name.lower()] = info
201
+
202
+ def categories(self) -> list[str]:
203
+ """Get list of protocol categories.
204
+
205
+ Returns:
206
+ List of category names.
207
+ """
208
+ return sorted({p.category for p in self._protocols.values()})
209
+
210
+ # =========================================================================
211
+ # Built-in Protocol Definitions
212
+ # =========================================================================
213
+
214
+ def _add_modbus_rtu(self) -> None:
215
+ """Add Modbus RTU protocol definition."""
216
+ definition = ProtocolDefinition(
217
+ name="modbus_rtu",
218
+ description="Modbus RTU serial protocol",
219
+ endian="big",
220
+ fields=[
221
+ FieldDefinition(
222
+ name="address",
223
+ field_type="uint8",
224
+ description="Slave address (1-247)",
225
+ ),
226
+ FieldDefinition(
227
+ name="function_code",
228
+ field_type="uint8",
229
+ description="Function code",
230
+ enum={
231
+ 1: "read_coils",
232
+ 2: "read_discrete_inputs",
233
+ 3: "read_holding_registers",
234
+ 4: "read_input_registers",
235
+ 5: "write_single_coil",
236
+ 6: "write_single_register",
237
+ 15: "write_multiple_coils",
238
+ 16: "write_multiple_registers",
239
+ },
240
+ ),
241
+ FieldDefinition(
242
+ name="data",
243
+ field_type="bytes",
244
+ size_ref="remaining",
245
+ description="Function-specific data",
246
+ ),
247
+ FieldDefinition(
248
+ name="crc",
249
+ field_type="uint16",
250
+ endian="little",
251
+ description="CRC-16 checksum",
252
+ ),
253
+ ],
254
+ )
255
+
256
+ self._protocols["modbus_rtu"] = ProtocolInfo(
257
+ name="modbus_rtu",
258
+ category="industrial",
259
+ version="1.0",
260
+ description="Modbus RTU serial protocol for industrial automation",
261
+ reference="https://modbus.org/specs.php",
262
+ definition=definition,
263
+ )
264
+
265
+ def _add_modbus_tcp(self) -> None:
266
+ """Add Modbus TCP protocol definition."""
267
+ definition = ProtocolDefinition(
268
+ name="modbus_tcp",
269
+ description="Modbus TCP/IP protocol",
270
+ endian="big",
271
+ fields=[
272
+ FieldDefinition(
273
+ name="transaction_id",
274
+ field_type="uint16",
275
+ description="Transaction identifier",
276
+ ),
277
+ FieldDefinition(
278
+ name="protocol_id",
279
+ field_type="uint16",
280
+ description="Protocol identifier (0 for Modbus)",
281
+ ),
282
+ FieldDefinition(
283
+ name="length",
284
+ field_type="uint16",
285
+ description="Length of remaining message",
286
+ ),
287
+ FieldDefinition(
288
+ name="unit_id",
289
+ field_type="uint8",
290
+ description="Unit identifier",
291
+ ),
292
+ FieldDefinition(
293
+ name="function_code",
294
+ field_type="uint8",
295
+ description="Function code",
296
+ enum={
297
+ 1: "read_coils",
298
+ 2: "read_discrete_inputs",
299
+ 3: "read_holding_registers",
300
+ 4: "read_input_registers",
301
+ 5: "write_single_coil",
302
+ 6: "write_single_register",
303
+ 15: "write_multiple_coils",
304
+ 16: "write_multiple_registers",
305
+ },
306
+ ),
307
+ FieldDefinition(
308
+ name="data",
309
+ field_type="bytes",
310
+ size_ref="remaining",
311
+ description="Function-specific data",
312
+ ),
313
+ ],
314
+ )
315
+
316
+ self._protocols["modbus_tcp"] = ProtocolInfo(
317
+ name="modbus_tcp",
318
+ category="industrial",
319
+ version="1.0",
320
+ description="Modbus TCP/IP protocol for industrial automation",
321
+ reference="https://modbus.org/specs.php",
322
+ definition=definition,
323
+ )
324
+
325
+ def _add_dnp3(self) -> None:
326
+ """Add DNP3 protocol definition."""
327
+ definition = ProtocolDefinition(
328
+ name="dnp3",
329
+ description="Distributed Network Protocol 3",
330
+ endian="little",
331
+ fields=[
332
+ FieldDefinition(
333
+ name="start",
334
+ field_type="uint16",
335
+ value=0x0564,
336
+ description="Start bytes (0x0564)",
337
+ ),
338
+ FieldDefinition(
339
+ name="length",
340
+ field_type="uint8",
341
+ description="Data link layer length",
342
+ ),
343
+ FieldDefinition(
344
+ name="control",
345
+ field_type="uint8",
346
+ description="Control byte",
347
+ ),
348
+ FieldDefinition(
349
+ name="destination",
350
+ field_type="uint16",
351
+ description="Destination address",
352
+ ),
353
+ FieldDefinition(
354
+ name="source",
355
+ field_type="uint16",
356
+ description="Source address",
357
+ ),
358
+ FieldDefinition(
359
+ name="crc",
360
+ field_type="uint16",
361
+ description="CRC-16 checksum",
362
+ ),
363
+ FieldDefinition(
364
+ name="transport_header",
365
+ field_type="uint8",
366
+ description="Transport layer header",
367
+ ),
368
+ FieldDefinition(
369
+ name="application_data",
370
+ field_type="bytes",
371
+ size_ref="remaining",
372
+ description="Application layer data",
373
+ ),
374
+ ],
375
+ )
376
+
377
+ self._protocols["dnp3"] = ProtocolInfo(
378
+ name="dnp3",
379
+ category="industrial",
380
+ version="3.0",
381
+ description="Distributed Network Protocol for SCADA systems",
382
+ reference="https://www.dnp.org/",
383
+ definition=definition,
384
+ )
385
+
386
+ def _add_bacnet(self) -> None:
387
+ """Add BACnet protocol definition."""
388
+ definition = ProtocolDefinition(
389
+ name="bacnet",
390
+ description="Building Automation and Control Networks",
391
+ endian="big",
392
+ fields=[
393
+ FieldDefinition(
394
+ name="type",
395
+ field_type="uint8",
396
+ description="BVLC type (0x81 for BACnet/IP)",
397
+ ),
398
+ FieldDefinition(
399
+ name="function",
400
+ field_type="uint8",
401
+ description="BVLC function",
402
+ enum={
403
+ 0x00: "bvlc_result",
404
+ 0x01: "write_broadcast_table",
405
+ 0x04: "forwarded_npdu",
406
+ 0x0A: "original_unicast_npdu",
407
+ 0x0B: "original_broadcast_npdu",
408
+ },
409
+ ),
410
+ FieldDefinition(
411
+ name="length",
412
+ field_type="uint16",
413
+ description="Total BVLC length",
414
+ ),
415
+ FieldDefinition(
416
+ name="npdu",
417
+ field_type="bytes",
418
+ size_ref="remaining",
419
+ description="Network Protocol Data Unit",
420
+ ),
421
+ ],
422
+ )
423
+
424
+ self._protocols["bacnet"] = ProtocolInfo(
425
+ name="bacnet",
426
+ category="building",
427
+ version="2020",
428
+ description="Building Automation and Control Networks protocol",
429
+ reference="https://www.bacnetinternational.org/",
430
+ definition=definition,
431
+ )
432
+
433
+ def _add_http(self) -> None:
434
+ """Add HTTP protocol definition (simplified for binary inspection)."""
435
+ # HTTP is text-based, so we provide a simplified binary representation
436
+ definition = ProtocolDefinition(
437
+ name="http",
438
+ description="Hypertext Transfer Protocol (simplified)",
439
+ endian="big",
440
+ fields=[
441
+ FieldDefinition(
442
+ name="request_line",
443
+ field_type="string",
444
+ description="HTTP request/status line",
445
+ ),
446
+ FieldDefinition(
447
+ name="headers",
448
+ field_type="string",
449
+ size_ref="remaining",
450
+ description="HTTP headers and body",
451
+ ),
452
+ ],
453
+ )
454
+
455
+ self._protocols["http"] = ProtocolInfo(
456
+ name="http",
457
+ category="network",
458
+ version="1.1",
459
+ description="Hypertext Transfer Protocol",
460
+ reference="https://tools.ietf.org/html/rfc2616",
461
+ definition=definition,
462
+ )
463
+
464
+ def _add_mqtt(self) -> None:
465
+ """Add MQTT protocol definition."""
466
+ definition = ProtocolDefinition(
467
+ name="mqtt",
468
+ description="Message Queuing Telemetry Transport",
469
+ endian="big",
470
+ fields=[
471
+ FieldDefinition(
472
+ name="fixed_header",
473
+ field_type="uint8",
474
+ description="Fixed header (type + flags)",
475
+ ),
476
+ FieldDefinition(
477
+ name="remaining_length",
478
+ field_type="uint8",
479
+ description="Remaining length (variable encoding)",
480
+ ),
481
+ FieldDefinition(
482
+ name="payload",
483
+ field_type="bytes",
484
+ size_ref="remaining",
485
+ description="Variable header + payload",
486
+ ),
487
+ ],
488
+ )
489
+
490
+ self._protocols["mqtt"] = ProtocolInfo(
491
+ name="mqtt",
492
+ category="iot",
493
+ version="5.0",
494
+ description="MQTT IoT messaging protocol",
495
+ reference="https://mqtt.org/",
496
+ definition=definition,
497
+ )
498
+
499
+ def _add_coap(self) -> None:
500
+ """Add CoAP protocol definition."""
501
+ definition = ProtocolDefinition(
502
+ name="coap",
503
+ description="Constrained Application Protocol",
504
+ endian="big",
505
+ fields=[
506
+ FieldDefinition(
507
+ name="version_type_tkl",
508
+ field_type="uint8",
509
+ description="Version (2b) + Type (2b) + Token Length (4b)",
510
+ ),
511
+ FieldDefinition(
512
+ name="code",
513
+ field_type="uint8",
514
+ description="Method/Response code",
515
+ enum={
516
+ 0x01: "GET",
517
+ 0x02: "POST",
518
+ 0x03: "PUT",
519
+ 0x04: "DELETE",
520
+ 0x44: "2.04 Changed",
521
+ 0x45: "2.05 Content",
522
+ 0x81: "4.01 Unauthorized",
523
+ 0x84: "4.04 Not Found",
524
+ },
525
+ ),
526
+ FieldDefinition(
527
+ name="message_id",
528
+ field_type="uint16",
529
+ description="Message ID",
530
+ ),
531
+ FieldDefinition(
532
+ name="token_options_payload",
533
+ field_type="bytes",
534
+ size_ref="remaining",
535
+ description="Token + Options + Payload",
536
+ ),
537
+ ],
538
+ )
539
+
540
+ self._protocols["coap"] = ProtocolInfo(
541
+ name="coap",
542
+ category="iot",
543
+ version="RFC 7252",
544
+ description="Constrained Application Protocol for IoT",
545
+ reference="https://tools.ietf.org/html/rfc7252",
546
+ definition=definition,
547
+ )
548
+
549
+ def _add_cbor(self) -> None:
550
+ """Add CBOR protocol definition (simplified header)."""
551
+ definition = ProtocolDefinition(
552
+ name="cbor",
553
+ description="Concise Binary Object Representation",
554
+ endian="big",
555
+ fields=[
556
+ FieldDefinition(
557
+ name="initial_byte",
558
+ field_type="uint8",
559
+ description="Major type (3b) + Additional info (5b)",
560
+ ),
561
+ FieldDefinition(
562
+ name="data",
563
+ field_type="bytes",
564
+ size_ref="remaining",
565
+ description="CBOR data",
566
+ ),
567
+ ],
568
+ )
569
+
570
+ self._protocols["cbor"] = ProtocolInfo(
571
+ name="cbor",
572
+ category="iot",
573
+ version="RFC 8949",
574
+ description="Concise Binary Object Representation",
575
+ reference="https://tools.ietf.org/html/rfc8949",
576
+ definition=definition,
577
+ )
578
+
579
+ def _add_messagepack(self) -> None:
580
+ """Add MessagePack protocol definition (simplified header)."""
581
+ definition = ProtocolDefinition(
582
+ name="messagepack",
583
+ description="MessagePack binary serialization",
584
+ endian="big",
585
+ fields=[
586
+ FieldDefinition(
587
+ name="format",
588
+ field_type="uint8",
589
+ description="Format byte",
590
+ ),
591
+ FieldDefinition(
592
+ name="data",
593
+ field_type="bytes",
594
+ size_ref="remaining",
595
+ description="MessagePack data",
596
+ ),
597
+ ],
598
+ )
599
+
600
+ self._protocols["messagepack"] = ProtocolInfo(
601
+ name="messagepack",
602
+ category="iot",
603
+ version="1.0",
604
+ description="MessagePack binary serialization format",
605
+ reference="https://msgpack.org/",
606
+ definition=definition,
607
+ )
608
+
609
+ def _add_obd2(self) -> None:
610
+ """Add OBD-II protocol definition."""
611
+ definition = ProtocolDefinition(
612
+ name="obd2",
613
+ description="On-Board Diagnostics II",
614
+ endian="big",
615
+ fields=[
616
+ FieldDefinition(
617
+ name="mode",
618
+ field_type="uint8",
619
+ description="Service/mode",
620
+ enum={
621
+ 0x01: "show_current_data",
622
+ 0x02: "show_freeze_frame",
623
+ 0x03: "show_dtc",
624
+ 0x04: "clear_dtc",
625
+ 0x09: "request_vehicle_info",
626
+ },
627
+ ),
628
+ FieldDefinition(
629
+ name="pid",
630
+ field_type="uint8",
631
+ description="Parameter ID",
632
+ ),
633
+ FieldDefinition(
634
+ name="data",
635
+ field_type="bytes",
636
+ size_ref="remaining",
637
+ description="Parameter data",
638
+ ),
639
+ ],
640
+ )
641
+
642
+ self._protocols["obd2"] = ProtocolInfo(
643
+ name="obd2",
644
+ category="automotive",
645
+ version="ISO 15031",
646
+ description="On-Board Diagnostics II automotive protocol",
647
+ reference="https://www.iso.org/standard/66369.html",
648
+ definition=definition,
649
+ )
650
+
651
+ def _add_j1939(self) -> None:
652
+ """Add SAE J1939 protocol definition."""
653
+ definition = ProtocolDefinition(
654
+ name="j1939",
655
+ description="SAE J1939 Heavy Duty Vehicle Protocol",
656
+ endian="big",
657
+ fields=[
658
+ FieldDefinition(
659
+ name="priority",
660
+ field_type="uint8",
661
+ size=3,
662
+ description="Message priority (0-7)",
663
+ ),
664
+ FieldDefinition(
665
+ name="pgn",
666
+ field_type="uint32",
667
+ size=18,
668
+ description="Parameter Group Number",
669
+ ),
670
+ FieldDefinition(
671
+ name="source_address",
672
+ field_type="uint8",
673
+ description="Source address",
674
+ ),
675
+ FieldDefinition(
676
+ name="data",
677
+ field_type="bytes",
678
+ size=8,
679
+ description="Data bytes (up to 8)",
680
+ ),
681
+ ],
682
+ )
683
+
684
+ self._protocols["j1939"] = ProtocolInfo(
685
+ name="j1939",
686
+ category="automotive",
687
+ version="J1939-21",
688
+ description="SAE J1939 protocol for heavy-duty vehicles",
689
+ reference="https://www.sae.org/standards/content/j1939_202210/",
690
+ definition=definition,
691
+ )
692
+
693
+ def _add_can(self) -> None:
694
+ """Add CAN bus frame definition."""
695
+ definition = ProtocolDefinition(
696
+ name="can",
697
+ description="Controller Area Network",
698
+ endian="big",
699
+ fields=[
700
+ FieldDefinition(
701
+ name="identifier",
702
+ field_type="uint32",
703
+ description="CAN ID (11 or 29 bits)",
704
+ ),
705
+ FieldDefinition(
706
+ name="dlc",
707
+ field_type="uint8",
708
+ description="Data Length Code (0-8)",
709
+ ),
710
+ FieldDefinition(
711
+ name="data",
712
+ field_type="bytes",
713
+ size=8,
714
+ description="Data bytes",
715
+ ),
716
+ ],
717
+ )
718
+
719
+ self._protocols["can"] = ProtocolInfo(
720
+ name="can",
721
+ category="automotive",
722
+ version="2.0B",
723
+ description="Controller Area Network bus protocol",
724
+ reference="https://www.iso.org/standard/63648.html",
725
+ definition=definition,
726
+ )
727
+
728
+ def _add_dns(self) -> None:
729
+ """Add DNS protocol definition."""
730
+ definition = ProtocolDefinition(
731
+ name="dns",
732
+ description="Domain Name System",
733
+ endian="big",
734
+ fields=[
735
+ FieldDefinition(
736
+ name="transaction_id",
737
+ field_type="uint16",
738
+ description="Transaction ID",
739
+ ),
740
+ FieldDefinition(
741
+ name="flags",
742
+ field_type="uint16",
743
+ description="Flags",
744
+ ),
745
+ FieldDefinition(
746
+ name="questions",
747
+ field_type="uint16",
748
+ description="Question count",
749
+ ),
750
+ FieldDefinition(
751
+ name="answer_rrs",
752
+ field_type="uint16",
753
+ description="Answer RR count",
754
+ ),
755
+ FieldDefinition(
756
+ name="authority_rrs",
757
+ field_type="uint16",
758
+ description="Authority RR count",
759
+ ),
760
+ FieldDefinition(
761
+ name="additional_rrs",
762
+ field_type="uint16",
763
+ description="Additional RR count",
764
+ ),
765
+ FieldDefinition(
766
+ name="data",
767
+ field_type="bytes",
768
+ size_ref="remaining",
769
+ description="Questions, answers, authority, additional",
770
+ ),
771
+ ],
772
+ )
773
+
774
+ self._protocols["dns"] = ProtocolInfo(
775
+ name="dns",
776
+ category="network",
777
+ version="RFC 1035",
778
+ description="Domain Name System protocol",
779
+ reference="https://tools.ietf.org/html/rfc1035",
780
+ definition=definition,
781
+ )
782
+
783
+ def _add_ntp(self) -> None:
784
+ """Add NTP protocol definition."""
785
+ definition = ProtocolDefinition(
786
+ name="ntp",
787
+ description="Network Time Protocol",
788
+ endian="big",
789
+ fields=[
790
+ FieldDefinition(
791
+ name="flags",
792
+ field_type="uint8",
793
+ description="LI (2b) + VN (3b) + Mode (3b)",
794
+ ),
795
+ FieldDefinition(
796
+ name="stratum",
797
+ field_type="uint8",
798
+ description="Stratum level",
799
+ ),
800
+ FieldDefinition(
801
+ name="poll",
802
+ field_type="uint8",
803
+ description="Poll interval",
804
+ ),
805
+ FieldDefinition(
806
+ name="precision",
807
+ field_type="int8",
808
+ description="Clock precision",
809
+ ),
810
+ FieldDefinition(
811
+ name="root_delay",
812
+ field_type="uint32",
813
+ description="Root delay",
814
+ ),
815
+ FieldDefinition(
816
+ name="root_dispersion",
817
+ field_type="uint32",
818
+ description="Root dispersion",
819
+ ),
820
+ FieldDefinition(
821
+ name="reference_id",
822
+ field_type="bytes",
823
+ size=4,
824
+ description="Reference identifier",
825
+ ),
826
+ FieldDefinition(
827
+ name="reference_timestamp",
828
+ field_type="uint64",
829
+ description="Reference timestamp",
830
+ ),
831
+ FieldDefinition(
832
+ name="origin_timestamp",
833
+ field_type="uint64",
834
+ description="Origin timestamp",
835
+ ),
836
+ FieldDefinition(
837
+ name="receive_timestamp",
838
+ field_type="uint64",
839
+ description="Receive timestamp",
840
+ ),
841
+ FieldDefinition(
842
+ name="transmit_timestamp",
843
+ field_type="uint64",
844
+ description="Transmit timestamp",
845
+ ),
846
+ ],
847
+ )
848
+
849
+ self._protocols["ntp"] = ProtocolInfo(
850
+ name="ntp",
851
+ category="network",
852
+ version="4",
853
+ description="Network Time Protocol for time synchronization",
854
+ reference="https://tools.ietf.org/html/rfc5905",
855
+ definition=definition,
856
+ )
857
+
858
+ def _add_syslog(self) -> None:
859
+ """Add Syslog protocol definition."""
860
+ definition = ProtocolDefinition(
861
+ name="syslog",
862
+ description="Syslog Protocol",
863
+ endian="big",
864
+ fields=[
865
+ FieldDefinition(
866
+ name="priority",
867
+ field_type="string",
868
+ description="Priority value in angle brackets",
869
+ ),
870
+ FieldDefinition(
871
+ name="message",
872
+ field_type="string",
873
+ size_ref="remaining",
874
+ description="Syslog message",
875
+ ),
876
+ ],
877
+ )
878
+
879
+ self._protocols["syslog"] = ProtocolInfo(
880
+ name="syslog",
881
+ category="network",
882
+ version="RFC 5424",
883
+ description="Syslog protocol for system logging",
884
+ reference="https://tools.ietf.org/html/rfc5424",
885
+ definition=definition,
886
+ )
887
+
888
+ def _add_nmea(self) -> None:
889
+ """Add NMEA 0183 protocol definition."""
890
+ definition = ProtocolDefinition(
891
+ name="nmea",
892
+ description="NMEA 0183 GPS Protocol",
893
+ endian="big",
894
+ fields=[
895
+ FieldDefinition(
896
+ name="start",
897
+ field_type="string",
898
+ size=1,
899
+ value="$",
900
+ description="Start delimiter",
901
+ ),
902
+ FieldDefinition(
903
+ name="talker_id",
904
+ field_type="string",
905
+ size=2,
906
+ description="Talker identifier (GP, GN, etc.)",
907
+ ),
908
+ FieldDefinition(
909
+ name="sentence_id",
910
+ field_type="string",
911
+ size=3,
912
+ description="Sentence identifier (GGA, RMC, etc.)",
913
+ ),
914
+ FieldDefinition(
915
+ name="data",
916
+ field_type="string",
917
+ size_ref="remaining",
918
+ description="Comma-separated data fields",
919
+ ),
920
+ ],
921
+ )
922
+
923
+ self._protocols["nmea"] = ProtocolInfo(
924
+ name="nmea",
925
+ category="serial",
926
+ version="0183",
927
+ description="NMEA 0183 GPS/navigation protocol",
928
+ reference="https://www.nmea.org/",
929
+ definition=definition,
930
+ )
931
+
932
+ def _add_xmodem(self) -> None:
933
+ """Add XMODEM protocol definition."""
934
+ definition = ProtocolDefinition(
935
+ name="xmodem",
936
+ description="XMODEM File Transfer Protocol",
937
+ endian="big",
938
+ fields=[
939
+ FieldDefinition(
940
+ name="header",
941
+ field_type="uint8",
942
+ description="SOH (0x01), EOT (0x04), or CAN (0x18)",
943
+ enum={
944
+ 0x01: "SOH",
945
+ 0x04: "EOT",
946
+ 0x06: "ACK",
947
+ 0x15: "NAK",
948
+ 0x18: "CAN",
949
+ },
950
+ ),
951
+ FieldDefinition(
952
+ name="block_number",
953
+ field_type="uint8",
954
+ description="Block number (1-255)",
955
+ ),
956
+ FieldDefinition(
957
+ name="block_complement",
958
+ field_type="uint8",
959
+ description="One's complement of block number",
960
+ ),
961
+ FieldDefinition(
962
+ name="data",
963
+ field_type="bytes",
964
+ size=128,
965
+ description="Data block (128 bytes)",
966
+ ),
967
+ FieldDefinition(
968
+ name="checksum",
969
+ field_type="uint8",
970
+ description="Arithmetic sum checksum",
971
+ ),
972
+ ],
973
+ )
974
+
975
+ self._protocols["xmodem"] = ProtocolInfo(
976
+ name="xmodem",
977
+ category="serial",
978
+ version="1.0",
979
+ description="XMODEM file transfer protocol",
980
+ reference="https://en.wikipedia.org/wiki/XMODEM",
981
+ definition=definition,
982
+ )
983
+
984
+ def _add_knx(self) -> None:
985
+ """Add KNX protocol definition."""
986
+ definition = ProtocolDefinition(
987
+ name="knx",
988
+ description="KNX Building Automation Protocol",
989
+ endian="big",
990
+ fields=[
991
+ FieldDefinition(
992
+ name="header_length",
993
+ field_type="uint8",
994
+ value=0x06,
995
+ description="Header length (always 6)",
996
+ ),
997
+ FieldDefinition(
998
+ name="protocol_version",
999
+ field_type="uint8",
1000
+ value=0x10,
1001
+ description="Protocol version (0x10)",
1002
+ ),
1003
+ FieldDefinition(
1004
+ name="service_type",
1005
+ field_type="uint16",
1006
+ description="Service type identifier",
1007
+ enum={
1008
+ 0x0201: "search_request",
1009
+ 0x0202: "search_response",
1010
+ 0x0203: "description_request",
1011
+ 0x0204: "description_response",
1012
+ 0x0205: "connect_request",
1013
+ 0x0206: "connect_response",
1014
+ 0x0420: "tunnelling_request",
1015
+ 0x0421: "tunnelling_ack",
1016
+ },
1017
+ ),
1018
+ FieldDefinition(
1019
+ name="total_length",
1020
+ field_type="uint16",
1021
+ description="Total length including header",
1022
+ ),
1023
+ FieldDefinition(
1024
+ name="data",
1025
+ field_type="bytes",
1026
+ size_ref="remaining",
1027
+ description="Service-specific data",
1028
+ ),
1029
+ ],
1030
+ )
1031
+
1032
+ self._protocols["knx"] = ProtocolInfo(
1033
+ name="knx",
1034
+ category="building",
1035
+ version="2.0",
1036
+ description="KNX building automation protocol",
1037
+ reference="https://www.knx.org/",
1038
+ definition=definition,
1039
+ )
1040
+
1041
+ def _add_lonworks(self) -> None:
1042
+ """Add LonWorks protocol definition (simplified)."""
1043
+ definition = ProtocolDefinition(
1044
+ name="lonworks",
1045
+ description="LonWorks Control Network Protocol",
1046
+ endian="big",
1047
+ fields=[
1048
+ FieldDefinition(
1049
+ name="npdu",
1050
+ field_type="uint8",
1051
+ description="Network PDU byte",
1052
+ ),
1053
+ FieldDefinition(
1054
+ name="domain_length",
1055
+ field_type="uint8",
1056
+ description="Domain length (0, 1, 3, 6)",
1057
+ ),
1058
+ FieldDefinition(
1059
+ name="data",
1060
+ field_type="bytes",
1061
+ size_ref="remaining",
1062
+ description="LonWorks data",
1063
+ ),
1064
+ ],
1065
+ )
1066
+
1067
+ self._protocols["lonworks"] = ProtocolInfo(
1068
+ name="lonworks",
1069
+ category="building",
1070
+ version="1.0",
1071
+ description="LonWorks control network protocol",
1072
+ reference="https://www.echelon.com/",
1073
+ definition=definition,
1074
+ )
1075
+
1076
+ def _add_tlv(self) -> None:
1077
+ """Add generic TLV (Tag-Length-Value) format."""
1078
+ definition = ProtocolDefinition(
1079
+ name="tlv",
1080
+ description="Tag-Length-Value Generic Format",
1081
+ endian="big",
1082
+ fields=[
1083
+ FieldDefinition(
1084
+ name="tag",
1085
+ field_type="uint8",
1086
+ description="Type/tag identifier",
1087
+ ),
1088
+ FieldDefinition(
1089
+ name="length",
1090
+ field_type="uint8",
1091
+ description="Value length",
1092
+ ),
1093
+ FieldDefinition(
1094
+ name="value",
1095
+ field_type="bytes",
1096
+ size_ref="length",
1097
+ description="Value data",
1098
+ ),
1099
+ ],
1100
+ )
1101
+
1102
+ self._protocols["tlv"] = ProtocolInfo(
1103
+ name="tlv",
1104
+ category="custom",
1105
+ version="1.0",
1106
+ description="Generic Tag-Length-Value encoding",
1107
+ definition=definition,
1108
+ )
1109
+
1110
+ def _add_length_prefixed(self) -> None:
1111
+ """Add generic length-prefixed format."""
1112
+ definition = ProtocolDefinition(
1113
+ name="length_prefixed",
1114
+ description="Length-Prefixed Message Format",
1115
+ endian="big",
1116
+ fields=[
1117
+ FieldDefinition(
1118
+ name="length",
1119
+ field_type="uint16",
1120
+ description="Message length",
1121
+ ),
1122
+ FieldDefinition(
1123
+ name="payload",
1124
+ field_type="bytes",
1125
+ size_ref="length",
1126
+ description="Message payload",
1127
+ ),
1128
+ ],
1129
+ )
1130
+
1131
+ self._protocols["length_prefixed"] = ProtocolInfo(
1132
+ name="length_prefixed",
1133
+ category="custom",
1134
+ version="1.0",
1135
+ description="Generic length-prefixed message format",
1136
+ definition=definition,
1137
+ )
1138
+
1139
+
1140
+ # Global library instance
1141
+ _library: ProtocolLibrary | None = None
1142
+
1143
+
1144
+ def get_library() -> ProtocolLibrary:
1145
+ """Get the global protocol library instance.
1146
+
1147
+ Returns:
1148
+ ProtocolLibrary singleton instance.
1149
+ """
1150
+ global _library
1151
+ if _library is None:
1152
+ _library = ProtocolLibrary()
1153
+ return _library
1154
+
1155
+
1156
+ @overload
1157
+ def list_protocols(category: str | None = None, *, names_only: Literal[True]) -> list[str]: ...
1158
+
1159
+
1160
+ @overload
1161
+ def list_protocols(
1162
+ category: str | None = None, *, names_only: Literal[False] = ...
1163
+ ) -> list[ProtocolInfo]: ...
1164
+
1165
+
1166
+ def list_protocols(
1167
+ category: str | None = None, *, names_only: bool = False
1168
+ ) -> list[str] | list[ProtocolInfo]:
1169
+ """List available protocols in the library.
1170
+
1171
+ Implements RE-DSL-003: Protocol listing.
1172
+
1173
+ Args:
1174
+ category: Optional category filter.
1175
+ names_only: If True, return list of protocol names (strings).
1176
+ If False (default), return list of ProtocolInfo objects.
1177
+
1178
+ Returns:
1179
+ List of available protocols (names or ProtocolInfo).
1180
+
1181
+ Example:
1182
+ >>> # Get protocol names
1183
+ >>> names = list_protocols(names_only=True)
1184
+ >>> "http" in names
1185
+ True
1186
+
1187
+ >>> # Get full protocol info
1188
+ >>> protocols = list_protocols()
1189
+ >>> protocols[0].name
1190
+ 'modbus_rtu'
1191
+ """
1192
+ if names_only:
1193
+ return get_library().list_protocol_names(category)
1194
+ return get_library().list_protocols(category)
1195
+
1196
+
1197
+ def get_protocol(name: str) -> ProtocolInfo | None:
1198
+ """Get protocol information by name.
1199
+
1200
+ Args:
1201
+ name: Protocol name.
1202
+
1203
+ Returns:
1204
+ ProtocolInfo or None.
1205
+ """
1206
+ return get_library().get(name)
1207
+
1208
+
1209
+ def get_decoder(name: str) -> ProtocolDecoder | None:
1210
+ """Get a decoder for a protocol.
1211
+
1212
+ Implements RE-DSL-003: Protocol decoding.
1213
+
1214
+ Args:
1215
+ name: Protocol name.
1216
+
1217
+ Returns:
1218
+ ProtocolDecoder or None.
1219
+ """
1220
+ return get_library().get_decoder(name)
1221
+
1222
+
1223
+ __all__ = [
1224
+ "ProtocolInfo",
1225
+ "ProtocolLibrary",
1226
+ "get_decoder",
1227
+ "get_library",
1228
+ "get_protocol",
1229
+ "list_protocols",
1230
+ ]