oscura 0.5.0__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (513) hide show
  1. oscura/__init__.py +169 -167
  2. oscura/analyzers/__init__.py +3 -0
  3. oscura/analyzers/classification.py +659 -0
  4. oscura/analyzers/digital/__init__.py +0 -48
  5. oscura/analyzers/digital/edges.py +325 -65
  6. oscura/analyzers/digital/extraction.py +0 -195
  7. oscura/analyzers/digital/quality.py +293 -166
  8. oscura/analyzers/digital/timing.py +260 -115
  9. oscura/analyzers/digital/timing_numba.py +334 -0
  10. oscura/analyzers/entropy.py +605 -0
  11. oscura/analyzers/eye/diagram.py +176 -109
  12. oscura/analyzers/eye/metrics.py +5 -5
  13. oscura/analyzers/jitter/__init__.py +6 -4
  14. oscura/analyzers/jitter/ber.py +52 -52
  15. oscura/analyzers/jitter/classification.py +156 -0
  16. oscura/analyzers/jitter/decomposition.py +163 -113
  17. oscura/analyzers/jitter/spectrum.py +80 -64
  18. oscura/analyzers/ml/__init__.py +39 -0
  19. oscura/analyzers/ml/features.py +600 -0
  20. oscura/analyzers/ml/signal_classifier.py +604 -0
  21. oscura/analyzers/packet/daq.py +246 -158
  22. oscura/analyzers/packet/parser.py +12 -1
  23. oscura/analyzers/packet/payload.py +50 -2110
  24. oscura/analyzers/packet/payload_analysis.py +361 -181
  25. oscura/analyzers/packet/payload_patterns.py +133 -70
  26. oscura/analyzers/packet/stream.py +84 -23
  27. oscura/analyzers/patterns/__init__.py +26 -5
  28. oscura/analyzers/patterns/anomaly_detection.py +908 -0
  29. oscura/analyzers/patterns/clustering.py +169 -108
  30. oscura/analyzers/patterns/clustering_optimized.py +227 -0
  31. oscura/analyzers/patterns/discovery.py +1 -1
  32. oscura/analyzers/patterns/matching.py +581 -197
  33. oscura/analyzers/patterns/pattern_mining.py +778 -0
  34. oscura/analyzers/patterns/periodic.py +121 -38
  35. oscura/analyzers/patterns/sequences.py +175 -78
  36. oscura/analyzers/power/conduction.py +1 -1
  37. oscura/analyzers/power/soa.py +6 -6
  38. oscura/analyzers/power/switching.py +250 -110
  39. oscura/analyzers/protocol/__init__.py +17 -1
  40. oscura/analyzers/protocols/__init__.py +1 -22
  41. oscura/analyzers/protocols/base.py +6 -6
  42. oscura/analyzers/protocols/ble/__init__.py +38 -0
  43. oscura/analyzers/protocols/ble/analyzer.py +809 -0
  44. oscura/analyzers/protocols/ble/uuids.py +288 -0
  45. oscura/analyzers/protocols/can.py +257 -127
  46. oscura/analyzers/protocols/can_fd.py +107 -80
  47. oscura/analyzers/protocols/flexray.py +139 -80
  48. oscura/analyzers/protocols/hdlc.py +93 -58
  49. oscura/analyzers/protocols/i2c.py +247 -106
  50. oscura/analyzers/protocols/i2s.py +138 -86
  51. oscura/analyzers/protocols/industrial/__init__.py +40 -0
  52. oscura/analyzers/protocols/industrial/bacnet/__init__.py +33 -0
  53. oscura/analyzers/protocols/industrial/bacnet/analyzer.py +708 -0
  54. oscura/analyzers/protocols/industrial/bacnet/encoding.py +412 -0
  55. oscura/analyzers/protocols/industrial/bacnet/services.py +622 -0
  56. oscura/analyzers/protocols/industrial/ethercat/__init__.py +30 -0
  57. oscura/analyzers/protocols/industrial/ethercat/analyzer.py +474 -0
  58. oscura/analyzers/protocols/industrial/ethercat/mailbox.py +339 -0
  59. oscura/analyzers/protocols/industrial/ethercat/topology.py +166 -0
  60. oscura/analyzers/protocols/industrial/modbus/__init__.py +31 -0
  61. oscura/analyzers/protocols/industrial/modbus/analyzer.py +525 -0
  62. oscura/analyzers/protocols/industrial/modbus/crc.py +79 -0
  63. oscura/analyzers/protocols/industrial/modbus/functions.py +436 -0
  64. oscura/analyzers/protocols/industrial/opcua/__init__.py +21 -0
  65. oscura/analyzers/protocols/industrial/opcua/analyzer.py +552 -0
  66. oscura/analyzers/protocols/industrial/opcua/datatypes.py +446 -0
  67. oscura/analyzers/protocols/industrial/opcua/services.py +264 -0
  68. oscura/analyzers/protocols/industrial/profinet/__init__.py +23 -0
  69. oscura/analyzers/protocols/industrial/profinet/analyzer.py +441 -0
  70. oscura/analyzers/protocols/industrial/profinet/dcp.py +263 -0
  71. oscura/analyzers/protocols/industrial/profinet/ptcp.py +200 -0
  72. oscura/analyzers/protocols/jtag.py +180 -98
  73. oscura/analyzers/protocols/lin.py +219 -114
  74. oscura/analyzers/protocols/manchester.py +4 -4
  75. oscura/analyzers/protocols/onewire.py +253 -149
  76. oscura/analyzers/protocols/parallel_bus/__init__.py +20 -0
  77. oscura/analyzers/protocols/parallel_bus/centronics.py +92 -0
  78. oscura/analyzers/protocols/parallel_bus/gpib.py +137 -0
  79. oscura/analyzers/protocols/spi.py +192 -95
  80. oscura/analyzers/protocols/swd.py +321 -167
  81. oscura/analyzers/protocols/uart.py +267 -125
  82. oscura/analyzers/protocols/usb.py +235 -131
  83. oscura/analyzers/side_channel/power.py +17 -12
  84. oscura/analyzers/signal/__init__.py +15 -0
  85. oscura/analyzers/signal/timing_analysis.py +1086 -0
  86. oscura/analyzers/signal_integrity/__init__.py +4 -1
  87. oscura/analyzers/signal_integrity/sparams.py +2 -19
  88. oscura/analyzers/spectral/chunked.py +129 -60
  89. oscura/analyzers/spectral/chunked_fft.py +300 -94
  90. oscura/analyzers/spectral/chunked_wavelet.py +100 -80
  91. oscura/analyzers/statistical/checksum.py +376 -217
  92. oscura/analyzers/statistical/classification.py +229 -107
  93. oscura/analyzers/statistical/entropy.py +78 -53
  94. oscura/analyzers/statistics/correlation.py +407 -211
  95. oscura/analyzers/statistics/outliers.py +2 -2
  96. oscura/analyzers/statistics/streaming.py +30 -5
  97. oscura/analyzers/validation.py +216 -101
  98. oscura/analyzers/waveform/measurements.py +9 -0
  99. oscura/analyzers/waveform/measurements_with_uncertainty.py +31 -15
  100. oscura/analyzers/waveform/spectral.py +500 -228
  101. oscura/api/__init__.py +31 -5
  102. oscura/api/dsl/__init__.py +582 -0
  103. oscura/{dsl → api/dsl}/commands.py +43 -76
  104. oscura/{dsl → api/dsl}/interpreter.py +26 -51
  105. oscura/{dsl → api/dsl}/parser.py +107 -77
  106. oscura/{dsl → api/dsl}/repl.py +2 -2
  107. oscura/api/dsl.py +1 -1
  108. oscura/{integrations → api/integrations}/__init__.py +1 -1
  109. oscura/{integrations → api/integrations}/llm.py +201 -102
  110. oscura/api/operators.py +3 -3
  111. oscura/api/optimization.py +144 -30
  112. oscura/api/rest_server.py +921 -0
  113. oscura/api/server/__init__.py +17 -0
  114. oscura/api/server/dashboard.py +850 -0
  115. oscura/api/server/static/README.md +34 -0
  116. oscura/api/server/templates/base.html +181 -0
  117. oscura/api/server/templates/export.html +120 -0
  118. oscura/api/server/templates/home.html +284 -0
  119. oscura/api/server/templates/protocols.html +58 -0
  120. oscura/api/server/templates/reports.html +43 -0
  121. oscura/api/server/templates/session_detail.html +89 -0
  122. oscura/api/server/templates/sessions.html +83 -0
  123. oscura/api/server/templates/waveforms.html +73 -0
  124. oscura/automotive/__init__.py +8 -1
  125. oscura/automotive/can/__init__.py +10 -0
  126. oscura/automotive/can/checksum.py +3 -1
  127. oscura/automotive/can/dbc_generator.py +590 -0
  128. oscura/automotive/can/message_wrapper.py +121 -74
  129. oscura/automotive/can/patterns.py +98 -21
  130. oscura/automotive/can/session.py +292 -56
  131. oscura/automotive/can/state_machine.py +6 -3
  132. oscura/automotive/can/stimulus_response.py +97 -75
  133. oscura/automotive/dbc/__init__.py +10 -2
  134. oscura/automotive/dbc/generator.py +84 -56
  135. oscura/automotive/dbc/parser.py +6 -6
  136. oscura/automotive/dtc/data.json +2763 -0
  137. oscura/automotive/dtc/database.py +2 -2
  138. oscura/automotive/flexray/__init__.py +31 -0
  139. oscura/automotive/flexray/analyzer.py +504 -0
  140. oscura/automotive/flexray/crc.py +185 -0
  141. oscura/automotive/flexray/fibex.py +449 -0
  142. oscura/automotive/j1939/__init__.py +45 -8
  143. oscura/automotive/j1939/analyzer.py +605 -0
  144. oscura/automotive/j1939/spns.py +326 -0
  145. oscura/automotive/j1939/transport.py +306 -0
  146. oscura/automotive/lin/__init__.py +47 -0
  147. oscura/automotive/lin/analyzer.py +612 -0
  148. oscura/automotive/loaders/blf.py +13 -2
  149. oscura/automotive/loaders/csv_can.py +143 -72
  150. oscura/automotive/loaders/dispatcher.py +50 -2
  151. oscura/automotive/loaders/mdf.py +86 -45
  152. oscura/automotive/loaders/pcap.py +111 -61
  153. oscura/automotive/uds/__init__.py +4 -0
  154. oscura/automotive/uds/analyzer.py +725 -0
  155. oscura/automotive/uds/decoder.py +140 -58
  156. oscura/automotive/uds/models.py +7 -1
  157. oscura/automotive/visualization.py +1 -1
  158. oscura/cli/analyze.py +348 -0
  159. oscura/cli/batch.py +142 -122
  160. oscura/cli/benchmark.py +275 -0
  161. oscura/cli/characterize.py +137 -82
  162. oscura/cli/compare.py +224 -131
  163. oscura/cli/completion.py +250 -0
  164. oscura/cli/config_cmd.py +361 -0
  165. oscura/cli/decode.py +164 -87
  166. oscura/cli/export.py +286 -0
  167. oscura/cli/main.py +115 -31
  168. oscura/{onboarding → cli/onboarding}/__init__.py +3 -3
  169. oscura/{onboarding → cli/onboarding}/help.py +80 -58
  170. oscura/{onboarding → cli/onboarding}/tutorials.py +97 -72
  171. oscura/{onboarding → cli/onboarding}/wizard.py +55 -36
  172. oscura/cli/progress.py +147 -0
  173. oscura/cli/shell.py +157 -135
  174. oscura/cli/validate_cmd.py +204 -0
  175. oscura/cli/visualize.py +158 -0
  176. oscura/convenience.py +125 -79
  177. oscura/core/__init__.py +4 -2
  178. oscura/core/backend_selector.py +3 -3
  179. oscura/core/cache.py +126 -15
  180. oscura/core/cancellation.py +1 -1
  181. oscura/{config → core/config}/__init__.py +20 -11
  182. oscura/{config → core/config}/defaults.py +1 -1
  183. oscura/{config → core/config}/loader.py +7 -5
  184. oscura/{config → core/config}/memory.py +5 -5
  185. oscura/{config → core/config}/migration.py +1 -1
  186. oscura/{config → core/config}/pipeline.py +99 -23
  187. oscura/{config → core/config}/preferences.py +1 -1
  188. oscura/{config → core/config}/protocol.py +3 -3
  189. oscura/{config → core/config}/schema.py +426 -272
  190. oscura/{config → core/config}/settings.py +1 -1
  191. oscura/{config → core/config}/thresholds.py +195 -153
  192. oscura/core/correlation.py +5 -6
  193. oscura/core/cross_domain.py +0 -2
  194. oscura/core/debug.py +9 -5
  195. oscura/{extensibility → core/extensibility}/docs.py +158 -70
  196. oscura/{extensibility → core/extensibility}/extensions.py +160 -76
  197. oscura/{extensibility → core/extensibility}/logging.py +1 -1
  198. oscura/{extensibility → core/extensibility}/measurements.py +1 -1
  199. oscura/{extensibility → core/extensibility}/plugins.py +1 -1
  200. oscura/{extensibility → core/extensibility}/templates.py +73 -3
  201. oscura/{extensibility → core/extensibility}/validation.py +1 -1
  202. oscura/core/gpu_backend.py +11 -7
  203. oscura/core/log_query.py +101 -11
  204. oscura/core/logging.py +126 -54
  205. oscura/core/logging_advanced.py +5 -5
  206. oscura/core/memory_limits.py +108 -70
  207. oscura/core/memory_monitor.py +2 -2
  208. oscura/core/memory_progress.py +7 -7
  209. oscura/core/memory_warnings.py +1 -1
  210. oscura/core/numba_backend.py +13 -13
  211. oscura/{plugins → core/plugins}/__init__.py +9 -9
  212. oscura/{plugins → core/plugins}/base.py +7 -7
  213. oscura/{plugins → core/plugins}/cli.py +3 -3
  214. oscura/{plugins → core/plugins}/discovery.py +186 -106
  215. oscura/{plugins → core/plugins}/lifecycle.py +1 -1
  216. oscura/{plugins → core/plugins}/manager.py +7 -7
  217. oscura/{plugins → core/plugins}/registry.py +3 -3
  218. oscura/{plugins → core/plugins}/versioning.py +1 -1
  219. oscura/core/progress.py +16 -1
  220. oscura/core/provenance.py +8 -2
  221. oscura/{schemas → core/schemas}/__init__.py +2 -2
  222. oscura/core/schemas/bus_configuration.json +322 -0
  223. oscura/core/schemas/device_mapping.json +182 -0
  224. oscura/core/schemas/packet_format.json +418 -0
  225. oscura/core/schemas/protocol_definition.json +363 -0
  226. oscura/core/types.py +4 -0
  227. oscura/core/uncertainty.py +3 -3
  228. oscura/correlation/__init__.py +52 -0
  229. oscura/correlation/multi_protocol.py +811 -0
  230. oscura/discovery/auto_decoder.py +117 -35
  231. oscura/discovery/comparison.py +191 -86
  232. oscura/discovery/quality_validator.py +155 -68
  233. oscura/discovery/signal_detector.py +196 -79
  234. oscura/export/__init__.py +18 -20
  235. oscura/export/kaitai_struct.py +513 -0
  236. oscura/export/scapy_layer.py +801 -0
  237. oscura/export/wireshark/README.md +15 -15
  238. oscura/export/wireshark/generator.py +1 -1
  239. oscura/export/wireshark/templates/dissector.lua.j2 +2 -2
  240. oscura/export/wireshark_dissector.py +746 -0
  241. oscura/guidance/wizard.py +207 -111
  242. oscura/hardware/__init__.py +19 -0
  243. oscura/{acquisition → hardware/acquisition}/__init__.py +4 -4
  244. oscura/{acquisition → hardware/acquisition}/file.py +2 -2
  245. oscura/{acquisition → hardware/acquisition}/hardware.py +7 -7
  246. oscura/{acquisition → hardware/acquisition}/saleae.py +15 -12
  247. oscura/{acquisition → hardware/acquisition}/socketcan.py +1 -1
  248. oscura/{acquisition → hardware/acquisition}/streaming.py +2 -2
  249. oscura/{acquisition → hardware/acquisition}/synthetic.py +3 -3
  250. oscura/{acquisition → hardware/acquisition}/visa.py +33 -11
  251. oscura/hardware/firmware/__init__.py +29 -0
  252. oscura/hardware/firmware/pattern_recognition.py +874 -0
  253. oscura/hardware/hal_detector.py +736 -0
  254. oscura/hardware/security/__init__.py +37 -0
  255. oscura/hardware/security/side_channel_detector.py +1126 -0
  256. oscura/inference/__init__.py +4 -0
  257. oscura/inference/active_learning/README.md +7 -7
  258. oscura/inference/active_learning/observation_table.py +4 -1
  259. oscura/inference/alignment.py +216 -123
  260. oscura/inference/bayesian.py +113 -33
  261. oscura/inference/crc_reverse.py +101 -55
  262. oscura/inference/logic.py +6 -2
  263. oscura/inference/message_format.py +342 -183
  264. oscura/inference/protocol.py +95 -44
  265. oscura/inference/protocol_dsl.py +180 -82
  266. oscura/inference/signal_intelligence.py +1439 -706
  267. oscura/inference/spectral.py +99 -57
  268. oscura/inference/state_machine.py +810 -158
  269. oscura/inference/stream.py +270 -110
  270. oscura/iot/__init__.py +34 -0
  271. oscura/iot/coap/__init__.py +32 -0
  272. oscura/iot/coap/analyzer.py +668 -0
  273. oscura/iot/coap/options.py +212 -0
  274. oscura/iot/lorawan/__init__.py +21 -0
  275. oscura/iot/lorawan/crypto.py +206 -0
  276. oscura/iot/lorawan/decoder.py +801 -0
  277. oscura/iot/lorawan/mac_commands.py +341 -0
  278. oscura/iot/mqtt/__init__.py +27 -0
  279. oscura/iot/mqtt/analyzer.py +999 -0
  280. oscura/iot/mqtt/properties.py +315 -0
  281. oscura/iot/zigbee/__init__.py +31 -0
  282. oscura/iot/zigbee/analyzer.py +615 -0
  283. oscura/iot/zigbee/security.py +153 -0
  284. oscura/iot/zigbee/zcl.py +349 -0
  285. oscura/jupyter/display.py +125 -45
  286. oscura/{exploratory → jupyter/exploratory}/__init__.py +8 -8
  287. oscura/{exploratory → jupyter/exploratory}/error_recovery.py +298 -141
  288. oscura/jupyter/exploratory/fuzzy.py +746 -0
  289. oscura/{exploratory → jupyter/exploratory}/fuzzy_advanced.py +258 -100
  290. oscura/{exploratory → jupyter/exploratory}/legacy.py +464 -242
  291. oscura/{exploratory → jupyter/exploratory}/parse.py +167 -145
  292. oscura/{exploratory → jupyter/exploratory}/recovery.py +119 -87
  293. oscura/jupyter/exploratory/sync.py +612 -0
  294. oscura/{exploratory → jupyter/exploratory}/unknown.py +299 -176
  295. oscura/jupyter/magic.py +4 -4
  296. oscura/{ui → jupyter/ui}/__init__.py +2 -2
  297. oscura/{ui → jupyter/ui}/formatters.py +3 -3
  298. oscura/{ui → jupyter/ui}/progressive_display.py +153 -82
  299. oscura/loaders/__init__.py +171 -63
  300. oscura/loaders/binary.py +88 -1
  301. oscura/loaders/chipwhisperer.py +153 -137
  302. oscura/loaders/configurable.py +208 -86
  303. oscura/loaders/csv_loader.py +458 -215
  304. oscura/loaders/hdf5_loader.py +278 -119
  305. oscura/loaders/lazy.py +87 -54
  306. oscura/loaders/mmap_loader.py +1 -1
  307. oscura/loaders/numpy_loader.py +253 -116
  308. oscura/loaders/pcap.py +226 -151
  309. oscura/loaders/rigol.py +110 -49
  310. oscura/loaders/sigrok.py +201 -78
  311. oscura/loaders/tdms.py +81 -58
  312. oscura/loaders/tektronix.py +291 -174
  313. oscura/loaders/touchstone.py +182 -87
  314. oscura/loaders/vcd.py +215 -117
  315. oscura/loaders/wav.py +155 -68
  316. oscura/reporting/__init__.py +9 -7
  317. oscura/reporting/analyze.py +352 -146
  318. oscura/reporting/argument_preparer.py +69 -14
  319. oscura/reporting/auto_report.py +97 -61
  320. oscura/reporting/batch.py +131 -58
  321. oscura/reporting/chart_selection.py +57 -45
  322. oscura/reporting/comparison.py +63 -17
  323. oscura/reporting/content/executive.py +76 -24
  324. oscura/reporting/core_formats/multi_format.py +11 -8
  325. oscura/reporting/engine.py +312 -158
  326. oscura/reporting/enhanced_reports.py +949 -0
  327. oscura/reporting/export.py +86 -43
  328. oscura/reporting/formatting/numbers.py +69 -42
  329. oscura/reporting/html.py +139 -58
  330. oscura/reporting/index.py +137 -65
  331. oscura/reporting/output.py +158 -67
  332. oscura/reporting/pdf.py +67 -102
  333. oscura/reporting/plots.py +191 -112
  334. oscura/reporting/sections.py +88 -47
  335. oscura/reporting/standards.py +104 -61
  336. oscura/reporting/summary_generator.py +75 -55
  337. oscura/reporting/tables.py +138 -54
  338. oscura/reporting/templates/enhanced/protocol_re.html +525 -0
  339. oscura/reporting/templates/index.md +13 -13
  340. oscura/sessions/__init__.py +14 -23
  341. oscura/sessions/base.py +3 -3
  342. oscura/sessions/blackbox.py +106 -10
  343. oscura/sessions/generic.py +2 -2
  344. oscura/sessions/legacy.py +783 -0
  345. oscura/side_channel/__init__.py +63 -0
  346. oscura/side_channel/dpa.py +1025 -0
  347. oscura/utils/__init__.py +15 -1
  348. oscura/utils/autodetect.py +1 -5
  349. oscura/utils/bitwise.py +118 -0
  350. oscura/{builders → utils/builders}/__init__.py +1 -1
  351. oscura/{comparison → utils/comparison}/__init__.py +6 -6
  352. oscura/{comparison → utils/comparison}/compare.py +202 -101
  353. oscura/{comparison → utils/comparison}/golden.py +83 -63
  354. oscura/{comparison → utils/comparison}/limits.py +313 -89
  355. oscura/{comparison → utils/comparison}/mask.py +151 -45
  356. oscura/{comparison → utils/comparison}/trace_diff.py +1 -1
  357. oscura/{comparison → utils/comparison}/visualization.py +147 -89
  358. oscura/{component → utils/component}/__init__.py +3 -3
  359. oscura/{component → utils/component}/impedance.py +122 -58
  360. oscura/{component → utils/component}/reactive.py +165 -168
  361. oscura/{component → utils/component}/transmission_line.py +3 -3
  362. oscura/{filtering → utils/filtering}/__init__.py +6 -6
  363. oscura/{filtering → utils/filtering}/base.py +1 -1
  364. oscura/{filtering → utils/filtering}/convenience.py +2 -2
  365. oscura/{filtering → utils/filtering}/design.py +169 -93
  366. oscura/{filtering → utils/filtering}/filters.py +2 -2
  367. oscura/{filtering → utils/filtering}/introspection.py +2 -2
  368. oscura/utils/geometry.py +31 -0
  369. oscura/utils/imports.py +184 -0
  370. oscura/utils/lazy.py +1 -1
  371. oscura/{math → utils/math}/__init__.py +2 -2
  372. oscura/{math → utils/math}/arithmetic.py +114 -48
  373. oscura/{math → utils/math}/interpolation.py +139 -106
  374. oscura/utils/memory.py +129 -66
  375. oscura/utils/memory_advanced.py +92 -9
  376. oscura/utils/memory_extensions.py +10 -8
  377. oscura/{optimization → utils/optimization}/__init__.py +1 -1
  378. oscura/{optimization → utils/optimization}/search.py +2 -2
  379. oscura/utils/performance/__init__.py +58 -0
  380. oscura/utils/performance/caching.py +889 -0
  381. oscura/utils/performance/lsh_clustering.py +333 -0
  382. oscura/utils/performance/memory_optimizer.py +699 -0
  383. oscura/utils/performance/optimizations.py +675 -0
  384. oscura/utils/performance/parallel.py +654 -0
  385. oscura/utils/performance/profiling.py +661 -0
  386. oscura/{pipeline → utils/pipeline}/base.py +1 -1
  387. oscura/{pipeline → utils/pipeline}/composition.py +11 -3
  388. oscura/{pipeline → utils/pipeline}/parallel.py +3 -2
  389. oscura/{pipeline → utils/pipeline}/pipeline.py +1 -1
  390. oscura/{pipeline → utils/pipeline}/reverse_engineering.py +412 -221
  391. oscura/{search → utils/search}/__init__.py +3 -3
  392. oscura/{search → utils/search}/anomaly.py +188 -58
  393. oscura/utils/search/context.py +294 -0
  394. oscura/{search → utils/search}/pattern.py +138 -10
  395. oscura/utils/serial.py +51 -0
  396. oscura/utils/storage/__init__.py +61 -0
  397. oscura/utils/storage/database.py +1166 -0
  398. oscura/{streaming → utils/streaming}/chunked.py +302 -143
  399. oscura/{streaming → utils/streaming}/progressive.py +1 -1
  400. oscura/{streaming → utils/streaming}/realtime.py +3 -2
  401. oscura/{triggering → utils/triggering}/__init__.py +6 -6
  402. oscura/{triggering → utils/triggering}/base.py +6 -6
  403. oscura/{triggering → utils/triggering}/edge.py +2 -2
  404. oscura/{triggering → utils/triggering}/pattern.py +2 -2
  405. oscura/{triggering → utils/triggering}/pulse.py +115 -74
  406. oscura/{triggering → utils/triggering}/window.py +2 -2
  407. oscura/utils/validation.py +32 -0
  408. oscura/validation/__init__.py +121 -0
  409. oscura/{compliance → validation/compliance}/__init__.py +5 -5
  410. oscura/{compliance → validation/compliance}/advanced.py +5 -5
  411. oscura/{compliance → validation/compliance}/masks.py +1 -1
  412. oscura/{compliance → validation/compliance}/reporting.py +127 -53
  413. oscura/{compliance → validation/compliance}/testing.py +114 -52
  414. oscura/validation/compliance_tests.py +915 -0
  415. oscura/validation/fuzzer.py +990 -0
  416. oscura/validation/grammar_tests.py +596 -0
  417. oscura/validation/grammar_validator.py +904 -0
  418. oscura/validation/hil_testing.py +977 -0
  419. oscura/{quality → validation/quality}/__init__.py +4 -4
  420. oscura/{quality → validation/quality}/ensemble.py +251 -171
  421. oscura/{quality → validation/quality}/explainer.py +3 -3
  422. oscura/{quality → validation/quality}/scoring.py +1 -1
  423. oscura/{quality → validation/quality}/warnings.py +4 -4
  424. oscura/validation/regression_suite.py +808 -0
  425. oscura/validation/replay.py +788 -0
  426. oscura/{testing → validation/testing}/__init__.py +2 -2
  427. oscura/{testing → validation/testing}/synthetic.py +5 -5
  428. oscura/visualization/__init__.py +9 -0
  429. oscura/visualization/accessibility.py +1 -1
  430. oscura/visualization/annotations.py +64 -67
  431. oscura/visualization/colors.py +7 -7
  432. oscura/visualization/digital.py +180 -81
  433. oscura/visualization/eye.py +236 -85
  434. oscura/visualization/interactive.py +320 -143
  435. oscura/visualization/jitter.py +587 -247
  436. oscura/visualization/layout.py +169 -134
  437. oscura/visualization/optimization.py +103 -52
  438. oscura/visualization/palettes.py +1 -1
  439. oscura/visualization/power.py +427 -211
  440. oscura/visualization/power_extended.py +626 -297
  441. oscura/visualization/presets.py +2 -0
  442. oscura/visualization/protocols.py +495 -181
  443. oscura/visualization/render.py +79 -63
  444. oscura/visualization/reverse_engineering.py +171 -124
  445. oscura/visualization/signal_integrity.py +460 -279
  446. oscura/visualization/specialized.py +190 -100
  447. oscura/visualization/spectral.py +670 -255
  448. oscura/visualization/thumbnails.py +166 -137
  449. oscura/visualization/waveform.py +150 -63
  450. oscura/workflows/__init__.py +3 -0
  451. oscura/{batch → workflows/batch}/__init__.py +5 -5
  452. oscura/{batch → workflows/batch}/advanced.py +150 -75
  453. oscura/workflows/batch/aggregate.py +531 -0
  454. oscura/workflows/batch/analyze.py +236 -0
  455. oscura/{batch → workflows/batch}/logging.py +2 -2
  456. oscura/{batch → workflows/batch}/metrics.py +1 -1
  457. oscura/workflows/complete_re.py +1144 -0
  458. oscura/workflows/compliance.py +44 -54
  459. oscura/workflows/digital.py +197 -51
  460. oscura/workflows/legacy/__init__.py +12 -0
  461. oscura/{workflow → workflows/legacy}/dag.py +4 -1
  462. oscura/workflows/multi_trace.py +9 -9
  463. oscura/workflows/power.py +42 -62
  464. oscura/workflows/protocol.py +82 -49
  465. oscura/workflows/reverse_engineering.py +351 -150
  466. oscura/workflows/signal_integrity.py +157 -82
  467. oscura-0.6.0.dist-info/METADATA +643 -0
  468. oscura-0.6.0.dist-info/RECORD +590 -0
  469. oscura/analyzers/digital/ic_database.py +0 -498
  470. oscura/analyzers/digital/timing_paths.py +0 -339
  471. oscura/analyzers/digital/vintage.py +0 -377
  472. oscura/analyzers/digital/vintage_result.py +0 -148
  473. oscura/analyzers/protocols/parallel_bus.py +0 -449
  474. oscura/batch/aggregate.py +0 -300
  475. oscura/batch/analyze.py +0 -139
  476. oscura/dsl/__init__.py +0 -73
  477. oscura/exceptions.py +0 -59
  478. oscura/exploratory/fuzzy.py +0 -513
  479. oscura/exploratory/sync.py +0 -384
  480. oscura/export/wavedrom.py +0 -430
  481. oscura/exporters/__init__.py +0 -94
  482. oscura/exporters/csv.py +0 -303
  483. oscura/exporters/exporters.py +0 -44
  484. oscura/exporters/hdf5.py +0 -217
  485. oscura/exporters/html_export.py +0 -701
  486. oscura/exporters/json_export.py +0 -338
  487. oscura/exporters/markdown_export.py +0 -367
  488. oscura/exporters/matlab_export.py +0 -354
  489. oscura/exporters/npz_export.py +0 -219
  490. oscura/exporters/spice_export.py +0 -210
  491. oscura/exporters/vintage_logic_csv.py +0 -247
  492. oscura/reporting/vintage_logic_report.py +0 -523
  493. oscura/search/context.py +0 -149
  494. oscura/session/__init__.py +0 -34
  495. oscura/session/annotations.py +0 -289
  496. oscura/session/history.py +0 -313
  497. oscura/session/session.py +0 -520
  498. oscura/visualization/digital_advanced.py +0 -718
  499. oscura/visualization/figure_manager.py +0 -156
  500. oscura/workflow/__init__.py +0 -13
  501. oscura-0.5.0.dist-info/METADATA +0 -407
  502. oscura-0.5.0.dist-info/RECORD +0 -486
  503. /oscura/core/{config.py → config/legacy.py} +0 -0
  504. /oscura/{extensibility → core/extensibility}/__init__.py +0 -0
  505. /oscura/{extensibility → core/extensibility}/registry.py +0 -0
  506. /oscura/{plugins → core/plugins}/isolation.py +0 -0
  507. /oscura/{builders → utils/builders}/signal_builder.py +0 -0
  508. /oscura/{optimization → utils/optimization}/parallel.py +0 -0
  509. /oscura/{pipeline → utils/pipeline}/__init__.py +0 -0
  510. /oscura/{streaming → utils/streaming}/__init__.py +0 -0
  511. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/WHEEL +0 -0
  512. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/entry_points.txt +0 -0
  513. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,326 @@
1
+ """J1939 Suspect Parameter Number (SPN) definitions.
2
+
3
+ This module provides standard SPN definitions for common J1939 parameters
4
+ according to SAE J1939/71 (Vehicle Application Layer).
5
+
6
+ Example:
7
+ >>> from oscura.automotive.j1939.spns import get_standard_spns
8
+ >>> spns = get_standard_spns()
9
+ >>> engine_speed = next(s for s in spns[61444] if s.spn == 190)
10
+ >>> engine_speed.name
11
+ 'Engine Speed'
12
+ >>> engine_speed.unit
13
+ 'rpm'
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from oscura.automotive.j1939.analyzer import J1939SPN
19
+
20
+ __all__ = [
21
+ "STANDARD_SPNS",
22
+ "get_standard_spns",
23
+ ]
24
+
25
+
26
+ def get_standard_spns() -> dict[int, list[J1939SPN]]:
27
+ """Get standard SPN definitions for common PGNs.
28
+
29
+ Returns:
30
+ Dictionary mapping PGN to list of SPNs.
31
+
32
+ Example:
33
+ >>> spns = get_standard_spns()
34
+ >>> 61444 in spns # EEC1
35
+ True
36
+ >>> len(spns[61444])
37
+ 8
38
+ """
39
+ return STANDARD_SPNS.copy()
40
+
41
+
42
+ # Standard SPN definitions per SAE J1939/71
43
+ STANDARD_SPNS: dict[int, list[J1939SPN]] = {
44
+ # PGN 61444 - Electronic Engine Controller 1 (EEC1)
45
+ 61444: [
46
+ J1939SPN(
47
+ spn=190,
48
+ name="Engine Speed",
49
+ start_bit=24,
50
+ bit_length=16,
51
+ resolution=0.125,
52
+ offset=0.0,
53
+ unit="rpm",
54
+ data_range=(0.0, 8031.875),
55
+ ),
56
+ J1939SPN(
57
+ spn=899,
58
+ name="Engine Torque Mode",
59
+ start_bit=0,
60
+ bit_length=4,
61
+ resolution=1.0,
62
+ offset=0.0,
63
+ unit="",
64
+ data_range=(0.0, 15.0),
65
+ ),
66
+ J1939SPN(
67
+ spn=512,
68
+ name="Driver's Demand Engine Percent Torque",
69
+ start_bit=8,
70
+ bit_length=8,
71
+ resolution=1.0,
72
+ offset=-125.0,
73
+ unit="%",
74
+ data_range=(-125.0, 125.0),
75
+ ),
76
+ J1939SPN(
77
+ spn=513,
78
+ name="Actual Engine Percent Torque",
79
+ start_bit=16,
80
+ bit_length=8,
81
+ resolution=1.0,
82
+ offset=-125.0,
83
+ unit="%",
84
+ data_range=(-125.0, 125.0),
85
+ ),
86
+ J1939SPN(
87
+ spn=1483,
88
+ name="Source Address of Controlling Device",
89
+ start_bit=40,
90
+ bit_length=8,
91
+ resolution=1.0,
92
+ offset=0.0,
93
+ unit="",
94
+ data_range=(0.0, 255.0),
95
+ ),
96
+ J1939SPN(
97
+ spn=1675,
98
+ name="Engine Starter Mode",
99
+ start_bit=4,
100
+ bit_length=4,
101
+ resolution=1.0,
102
+ offset=0.0,
103
+ unit="",
104
+ data_range=(0.0, 15.0),
105
+ ),
106
+ J1939SPN(
107
+ spn=2432,
108
+ name="Engine Demand Percent Torque",
109
+ start_bit=48,
110
+ bit_length=8,
111
+ resolution=1.0,
112
+ offset=-125.0,
113
+ unit="%",
114
+ data_range=(-125.0, 125.0),
115
+ ),
116
+ ],
117
+ # PGN 61443 - Electronic Engine Controller 2 (EEC2)
118
+ 61443: [
119
+ J1939SPN(
120
+ spn=91,
121
+ name="Accelerator Pedal Position 1",
122
+ start_bit=0,
123
+ bit_length=8,
124
+ resolution=0.4,
125
+ offset=0.0,
126
+ unit="%",
127
+ data_range=(0.0, 100.0),
128
+ ),
129
+ J1939SPN(
130
+ spn=92,
131
+ name="Engine Percent Load At Current Speed",
132
+ start_bit=8,
133
+ bit_length=8,
134
+ resolution=1.0,
135
+ offset=0.0,
136
+ unit="%",
137
+ data_range=(0.0, 250.0),
138
+ ),
139
+ J1939SPN(
140
+ spn=974,
141
+ name="Remote Accelerator Pedal Position",
142
+ start_bit=16,
143
+ bit_length=8,
144
+ resolution=0.4,
145
+ offset=0.0,
146
+ unit="%",
147
+ data_range=(0.0, 100.0),
148
+ ),
149
+ J1939SPN(
150
+ spn=29,
151
+ name="Accelerator Pedal Position 2",
152
+ start_bit=24,
153
+ bit_length=8,
154
+ resolution=0.4,
155
+ offset=0.0,
156
+ unit="%",
157
+ data_range=(0.0, 100.0),
158
+ ),
159
+ J1939SPN(
160
+ spn=3357,
161
+ name="Vehicle Acceleration Rate Limit Status",
162
+ start_bit=32,
163
+ bit_length=2,
164
+ resolution=1.0,
165
+ offset=0.0,
166
+ unit="",
167
+ data_range=(0.0, 3.0),
168
+ ),
169
+ ],
170
+ # PGN 65265 - Cruise Control/Vehicle Speed (CCVS1)
171
+ 65265: [
172
+ J1939SPN(
173
+ spn=84,
174
+ name="Wheel-Based Vehicle Speed",
175
+ start_bit=8,
176
+ bit_length=16,
177
+ resolution=0.00390625,
178
+ offset=0.0,
179
+ unit="km/h",
180
+ data_range=(0.0, 250.996),
181
+ ),
182
+ J1939SPN(
183
+ spn=595,
184
+ name="Cruise Control Active",
185
+ start_bit=0,
186
+ bit_length=2,
187
+ resolution=1.0,
188
+ offset=0.0,
189
+ unit="",
190
+ data_range=(0.0, 3.0),
191
+ ),
192
+ J1939SPN(
193
+ spn=596,
194
+ name="Cruise Control Enable Switch",
195
+ start_bit=2,
196
+ bit_length=2,
197
+ resolution=1.0,
198
+ offset=0.0,
199
+ unit="",
200
+ data_range=(0.0, 3.0),
201
+ ),
202
+ J1939SPN(
203
+ spn=597,
204
+ name="Brake Switch",
205
+ start_bit=4,
206
+ bit_length=2,
207
+ resolution=1.0,
208
+ offset=0.0,
209
+ unit="",
210
+ data_range=(0.0, 3.0),
211
+ ),
212
+ J1939SPN(
213
+ spn=598,
214
+ name="Clutch Switch",
215
+ start_bit=6,
216
+ bit_length=2,
217
+ resolution=1.0,
218
+ offset=0.0,
219
+ unit="",
220
+ data_range=(0.0, 3.0),
221
+ ),
222
+ J1939SPN(
223
+ spn=599,
224
+ name="Cruise Control Set Switch",
225
+ start_bit=24,
226
+ bit_length=2,
227
+ resolution=1.0,
228
+ offset=0.0,
229
+ unit="",
230
+ data_range=(0.0, 3.0),
231
+ ),
232
+ J1939SPN(
233
+ spn=600,
234
+ name="Cruise Control Coast Switch",
235
+ start_bit=26,
236
+ bit_length=2,
237
+ resolution=1.0,
238
+ offset=0.0,
239
+ unit="",
240
+ data_range=(0.0, 3.0),
241
+ ),
242
+ J1939SPN(
243
+ spn=601,
244
+ name="Cruise Control Resume Switch",
245
+ start_bit=28,
246
+ bit_length=2,
247
+ resolution=1.0,
248
+ offset=0.0,
249
+ unit="",
250
+ data_range=(0.0, 3.0),
251
+ ),
252
+ J1939SPN(
253
+ spn=602,
254
+ name="Cruise Control Accelerate Switch",
255
+ start_bit=30,
256
+ bit_length=2,
257
+ resolution=1.0,
258
+ offset=0.0,
259
+ unit="",
260
+ data_range=(0.0, 3.0),
261
+ ),
262
+ J1939SPN(
263
+ spn=1633,
264
+ name="Cruise Control Set Speed",
265
+ start_bit=32,
266
+ bit_length=8,
267
+ resolution=1.0,
268
+ offset=0.0,
269
+ unit="km/h",
270
+ data_range=(0.0, 250.0),
271
+ ),
272
+ J1939SPN(
273
+ spn=976,
274
+ name="PTO State",
275
+ start_bit=40,
276
+ bit_length=5,
277
+ resolution=1.0,
278
+ offset=0.0,
279
+ unit="",
280
+ data_range=(0.0, 31.0),
281
+ ),
282
+ ],
283
+ # PGN 65226 - Active Diagnostic Trouble Codes (DM1)
284
+ 65226: [
285
+ J1939SPN(
286
+ spn=1213,
287
+ name="Malfunction Indicator Lamp Status",
288
+ start_bit=0,
289
+ bit_length=2,
290
+ resolution=1.0,
291
+ offset=0.0,
292
+ unit="",
293
+ data_range=(0.0, 3.0),
294
+ ),
295
+ J1939SPN(
296
+ spn=623,
297
+ name="Red Stop Lamp Status",
298
+ start_bit=2,
299
+ bit_length=2,
300
+ resolution=1.0,
301
+ offset=0.0,
302
+ unit="",
303
+ data_range=(0.0, 3.0),
304
+ ),
305
+ J1939SPN(
306
+ spn=624,
307
+ name="Amber Warning Lamp Status",
308
+ start_bit=4,
309
+ bit_length=2,
310
+ resolution=1.0,
311
+ offset=0.0,
312
+ unit="",
313
+ data_range=(0.0, 3.0),
314
+ ),
315
+ J1939SPN(
316
+ spn=987,
317
+ name="Protect Lamp Status",
318
+ start_bit=6,
319
+ bit_length=2,
320
+ resolution=1.0,
321
+ offset=0.0,
322
+ unit="",
323
+ data_range=(0.0, 3.0),
324
+ ),
325
+ ],
326
+ }
@@ -0,0 +1,306 @@
1
+ """J1939 Transport Protocol (TP) implementation.
2
+
3
+ This module implements J1939 transport protocol for multi-packet message
4
+ transfer, including:
5
+ - TP.CM (Connection Management): RTS, CTS, EOM_ACK, BAM, ABORT
6
+ - TP.DT (Data Transfer): Sequence-based packet delivery
7
+ - Session management and reassembly
8
+
9
+ References:
10
+ SAE J1939/21 - Data Link Layer (Transport Protocol)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from dataclasses import dataclass, field
16
+ from typing import Any
17
+
18
+ __all__ = [
19
+ "TransportProtocol",
20
+ "TransportSession",
21
+ ]
22
+
23
+
24
+ @dataclass
25
+ class TransportSession:
26
+ """Active transport protocol session.
27
+
28
+ Attributes:
29
+ source_address: Source address initiating transfer.
30
+ dest_address: Destination address (0xFF for broadcast).
31
+ data_pgn: PGN of the data being transferred.
32
+ total_size: Total message size in bytes.
33
+ total_packets: Total number of packets.
34
+ max_packets: Maximum packets per CTS (connection mode only).
35
+ packets: Received packets (sequence -> data).
36
+ started_at: Session start timestamp.
37
+ last_timestamp: Last packet timestamp.
38
+ is_broadcast: True for BAM (broadcast), False for RTS/CTS.
39
+ """
40
+
41
+ source_address: int
42
+ dest_address: int
43
+ data_pgn: int
44
+ total_size: int
45
+ total_packets: int
46
+ max_packets: int = 0xFF
47
+ packets: dict[int, bytes] = field(default_factory=dict)
48
+ started_at: float = 0.0
49
+ last_timestamp: float = 0.0
50
+ is_broadcast: bool = False
51
+
52
+ def is_complete(self) -> bool:
53
+ """Check if all packets received.
54
+
55
+ Returns:
56
+ True if all packets received.
57
+
58
+ Example:
59
+ >>> session = TransportSession(0, 0xFF, 61444, 32, 5)
60
+ >>> session.is_complete()
61
+ False
62
+ >>> for i in range(1, 6):
63
+ ... session.packets[i] = b'\\x00' * 7
64
+ >>> session.is_complete()
65
+ True
66
+ """
67
+ return len(self.packets) == self.total_packets
68
+
69
+ def reassemble(self) -> bytes:
70
+ """Reassemble complete message from packets.
71
+
72
+ Returns:
73
+ Reassembled message data.
74
+
75
+ Raises:
76
+ ValueError: If session is incomplete.
77
+
78
+ Example:
79
+ >>> session = TransportSession(0, 0xFF, 61444, 14, 2)
80
+ >>> session.packets[1] = b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06'
81
+ >>> session.packets[2] = b'\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d'
82
+ >>> data = session.reassemble()
83
+ >>> len(data)
84
+ 14
85
+ """
86
+ if not self.is_complete():
87
+ raise ValueError(f"Session incomplete: {len(self.packets)}/{self.total_packets}")
88
+
89
+ # Reassemble in sequence order
90
+ complete_data = b"".join(self.packets[i] for i in range(1, self.total_packets + 1))
91
+
92
+ # Trim to actual size (last packet may be padded)
93
+ return complete_data[: self.total_size]
94
+
95
+
96
+ class TransportProtocol:
97
+ """J1939 Transport Protocol handler.
98
+
99
+ Manages multi-packet message transfer sessions for messages
100
+ larger than 8 bytes using TP.CM and TP.DT.
101
+
102
+ Example:
103
+ >>> tp = TransportProtocol()
104
+ >>> # Parse TP.CM RTS
105
+ >>> cm_info = tp.parse_cm(b'\\x10\\x20\\x00\\x05\\xff\\xf0\\x04\\x00')
106
+ >>> cm_info['control']
107
+ 'RTS'
108
+ >>> cm_info['total_size']
109
+ 32
110
+ """
111
+
112
+ # PGN for transport protocol
113
+ PGN_TP_CM = 60160 # Connection Management
114
+ PGN_TP_DT = 60416 # Data Transfer
115
+
116
+ # Connection Management control bytes
117
+ CM_RTS = 16 # Request To Send
118
+ CM_CTS = 17 # Clear To Send
119
+ CM_EOM_ACK = 19 # End of Message Acknowledgment
120
+ CM_BAM = 32 # Broadcast Announce Message
121
+ CM_ABORT = 255 # Connection Abort
122
+
123
+ def __init__(self) -> None:
124
+ """Initialize transport protocol handler."""
125
+ # Active sessions: (source_addr, dest_addr) -> session
126
+ self.sessions: dict[tuple[int, int], TransportSession] = {}
127
+
128
+ def parse_cm(self, data: bytes) -> dict[str, Any] | None:
129
+ """Parse TP.CM (Connection Management) message.
130
+
131
+ TP.CM format (8 bytes):
132
+ - Byte 0: Control byte (RTS/CTS/EOM_ACK/BAM/ABORT)
133
+ - Byte 1-2: Total message size (little-endian)
134
+ - Byte 3: Total packets
135
+ - Byte 4: Max packets (CTS) or Reserved (RTS/BAM)
136
+ - Byte 5-7: PGN of data (little-endian, 3 bytes)
137
+
138
+ Args:
139
+ data: TP.CM message data (8 bytes).
140
+
141
+ Returns:
142
+ Parsed CM metadata or None if invalid.
143
+
144
+ Example:
145
+ >>> tp = TransportProtocol()
146
+ >>> # RTS message
147
+ >>> info = tp.parse_cm(b'\\x10\\x20\\x00\\x05\\xff\\xf0\\x04\\x00')
148
+ >>> info['control']
149
+ 'RTS'
150
+ >>> info['data_pgn']
151
+ 61680
152
+ """
153
+ if len(data) < 8:
154
+ return None
155
+
156
+ control = data[0]
157
+ total_size = int.from_bytes(data[1:3], "little")
158
+ total_packets = data[3]
159
+ max_packets = data[4]
160
+ data_pgn = int.from_bytes(data[5:8], "little")
161
+
162
+ cm_types = {
163
+ self.CM_RTS: "RTS",
164
+ self.CM_CTS: "CTS",
165
+ self.CM_EOM_ACK: "EOM_ACK",
166
+ self.CM_BAM: "BAM",
167
+ self.CM_ABORT: "ABORT",
168
+ }
169
+
170
+ return {
171
+ "control": cm_types.get(control, f"Unknown ({control})"),
172
+ "control_byte": control,
173
+ "total_size": total_size,
174
+ "total_packets": total_packets,
175
+ "max_packets": max_packets,
176
+ "data_pgn": data_pgn,
177
+ }
178
+
179
+ def parse_dt(self, data: bytes) -> dict[str, Any] | None:
180
+ """Parse TP.DT (Data Transfer) message.
181
+
182
+ TP.DT format:
183
+ - Byte 0: Sequence number (1-255)
184
+ - Byte 1-7: Data (7 bytes per packet)
185
+
186
+ Args:
187
+ data: TP.DT message data (8 bytes).
188
+
189
+ Returns:
190
+ Parsed DT metadata or None if invalid.
191
+
192
+ Example:
193
+ >>> tp = TransportProtocol()
194
+ >>> info = tp.parse_dt(b'\\x01\\x00\\x01\\x02\\x03\\x04\\x05\\x06')
195
+ >>> info['sequence']
196
+ 1
197
+ >>> info['data']
198
+ b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06'
199
+ """
200
+ if len(data) < 1:
201
+ return None
202
+
203
+ sequence = data[0]
204
+ packet_data = data[1:]
205
+
206
+ return {
207
+ "sequence": sequence,
208
+ "data": packet_data,
209
+ }
210
+
211
+ def start_session(
212
+ self,
213
+ source_address: int,
214
+ dest_address: int,
215
+ cm_info: dict[str, Any],
216
+ timestamp: float,
217
+ ) -> TransportSession | None:
218
+ """Start transport protocol session from TP.CM.
219
+
220
+ Args:
221
+ source_address: Source address.
222
+ dest_address: Destination address.
223
+ cm_info: Parsed TP.CM metadata.
224
+ timestamp: Session start timestamp.
225
+
226
+ Returns:
227
+ Created session or None if invalid.
228
+
229
+ Example:
230
+ >>> tp = TransportProtocol()
231
+ >>> cm_info = tp.parse_cm(b'\\x10\\x20\\x00\\x05\\xff\\xf0\\x04\\x00')
232
+ >>> session = tp.start_session(0, 0xFF, cm_info, 1.0)
233
+ >>> session.total_size
234
+ 32
235
+ """
236
+ control = cm_info.get("control_byte")
237
+ if control not in (self.CM_RTS, self.CM_BAM):
238
+ return None
239
+
240
+ session = TransportSession(
241
+ source_address=source_address,
242
+ dest_address=dest_address,
243
+ data_pgn=cm_info["data_pgn"],
244
+ total_size=cm_info["total_size"],
245
+ total_packets=cm_info["total_packets"],
246
+ max_packets=cm_info.get("max_packets", 0xFF),
247
+ started_at=timestamp,
248
+ last_timestamp=timestamp,
249
+ is_broadcast=(control == self.CM_BAM),
250
+ )
251
+
252
+ session_key = (source_address, dest_address)
253
+ self.sessions[session_key] = session
254
+
255
+ return session
256
+
257
+ def add_packet(
258
+ self,
259
+ source_address: int,
260
+ dest_address: int,
261
+ dt_info: dict[str, Any],
262
+ timestamp: float,
263
+ ) -> bytes | None:
264
+ """Add TP.DT packet to session.
265
+
266
+ Args:
267
+ source_address: Source address.
268
+ dest_address: Destination address.
269
+ dt_info: Parsed TP.DT metadata.
270
+ timestamp: Packet timestamp.
271
+
272
+ Returns:
273
+ Complete reassembled message if session complete, None otherwise.
274
+
275
+ Example:
276
+ >>> tp = TransportProtocol()
277
+ >>> cm = tp.parse_cm(b'\\x20\\x0e\\x00\\x02\\xff\\xf0\\x04\\x00')
278
+ >>> tp.start_session(0, 0xFF, cm, 1.0)
279
+ <...>
280
+ >>> dt1 = tp.parse_dt(b'\\x01\\x00\\x01\\x02\\x03\\x04\\x05\\x06')
281
+ >>> tp.add_packet(0, 0xFF, dt1, 1.1)
282
+ >>> dt2 = tp.parse_dt(b'\\x02\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d')
283
+ >>> data = tp.add_packet(0, 0xFF, dt2, 1.2)
284
+ >>> len(data)
285
+ 14
286
+ """
287
+ session_key = (source_address, dest_address)
288
+
289
+ if session_key not in self.sessions:
290
+ return None
291
+
292
+ session = self.sessions[session_key]
293
+ sequence = dt_info["sequence"]
294
+ packet_data = dt_info["data"]
295
+
296
+ # Add packet
297
+ session.packets[sequence] = packet_data
298
+ session.last_timestamp = timestamp
299
+
300
+ # Check if complete
301
+ if session.is_complete():
302
+ complete_data = session.reassemble()
303
+ del self.sessions[session_key]
304
+ return complete_data
305
+
306
+ return None
@@ -0,0 +1,47 @@
1
+ """LIN (Local Interconnect Network) protocol analysis.
2
+
3
+ This module provides comprehensive LIN protocol analysis capabilities including:
4
+ - LIN 2.x frame parsing with enhanced checksum support
5
+ - Protected ID calculation with parity bits
6
+ - Signal decoding and extraction
7
+ - Diagnostic services (master request/slave response)
8
+ - Schedule table inference from captured traffic
9
+ - LDF (LIN Description File) generation
10
+
11
+ Key features:
12
+ - Both classic and enhanced checksum validation
13
+ - Diagnostic frame parsing (0x3C, 0x3D)
14
+ - Event-triggered frame handling
15
+ - Signal mapping and decoding
16
+ - Automatic LDF generation from traffic
17
+
18
+ Example:
19
+ >>> from oscura.automotive.lin import LINAnalyzer, LINSignal
20
+ >>> analyzer = LINAnalyzer()
21
+ >>> # Parse captured LIN frame
22
+ >>> frame = analyzer.parse_frame(data=b'\\x55\\x80\\x01\\x02\\x03\\xFA', timestamp=1.0)
23
+ >>> print(f"Frame ID: {frame.frame_id}, Checksum: {frame.checksum_type}")
24
+ Frame ID: 0, Checksum: enhanced
25
+ >>> # Add signal definition
26
+ >>> analyzer.add_signal(LINSignal("Speed", frame_id=0, start_bit=0, bit_length=16))
27
+ >>> # Generate LDF from captured traffic
28
+ >>> analyzer.generate_ldf(Path("output.ldf"), baudrate=19200)
29
+
30
+ References:
31
+ LIN Specification 2.2A
32
+ ISO 17987 (LIN standard)
33
+ """
34
+
35
+ __all__ = [
36
+ "LINAnalyzer",
37
+ "LINFrame",
38
+ "LINScheduleEntry",
39
+ "LINSignal",
40
+ ]
41
+
42
+ from oscura.automotive.lin.analyzer import (
43
+ LINAnalyzer,
44
+ LINFrame,
45
+ LINScheduleEntry,
46
+ LINSignal,
47
+ )