oscura 0.5.0__py3-none-any.whl → 0.5.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.
- oscura/__init__.py +1 -1
- oscura/analyzers/digital/__init__.py +0 -48
- oscura/analyzers/digital/extraction.py +0 -195
- oscura/analyzers/protocols/__init__.py +1 -22
- oscura/automotive/__init__.py +1 -1
- oscura/automotive/dtc/data.json +2763 -0
- oscura/export/__init__.py +0 -12
- oscura/export/wireshark/README.md +15 -15
- oscura/exporters/json_export.py +0 -47
- oscura/inference/active_learning/README.md +7 -7
- oscura/pipeline/composition.py +10 -2
- oscura/reporting/__init__.py +0 -7
- oscura/reporting/templates/index.md +13 -13
- oscura/schemas/bus_configuration.json +322 -0
- oscura/schemas/device_mapping.json +182 -0
- oscura/schemas/packet_format.json +418 -0
- oscura/schemas/protocol_definition.json +363 -0
- oscura/utils/autodetect.py +1 -5
- oscura-0.5.1.dist-info/METADATA +583 -0
- {oscura-0.5.0.dist-info → oscura-0.5.1.dist-info}/RECORD +23 -28
- oscura/analyzers/digital/ic_database.py +0 -498
- oscura/analyzers/digital/timing_paths.py +0 -339
- oscura/analyzers/digital/vintage.py +0 -377
- oscura/analyzers/digital/vintage_result.py +0 -148
- oscura/analyzers/protocols/parallel_bus.py +0 -449
- oscura/export/wavedrom.py +0 -430
- oscura/exporters/vintage_logic_csv.py +0 -247
- oscura/reporting/vintage_logic_report.py +0 -523
- oscura/visualization/digital_advanced.py +0 -718
- oscura/visualization/figure_manager.py +0 -156
- oscura-0.5.0.dist-info/METADATA +0 -407
- {oscura-0.5.0.dist-info → oscura-0.5.1.dist-info}/WHEEL +0 -0
- {oscura-0.5.0.dist-info → oscura-0.5.1.dist-info}/entry_points.txt +0 -0
- {oscura-0.5.0.dist-info → oscura-0.5.1.dist-info}/licenses/LICENSE +0 -0
oscura/__init__.py
CHANGED
|
@@ -52,17 +52,9 @@ from oscura.analyzers.digital.edges import (
|
|
|
52
52
|
from oscura.analyzers.digital.extraction import (
|
|
53
53
|
LOGIC_FAMILIES,
|
|
54
54
|
detect_edges,
|
|
55
|
-
detect_logic_family,
|
|
56
|
-
detect_open_collector,
|
|
57
55
|
get_logic_threshold,
|
|
58
56
|
to_digital,
|
|
59
57
|
)
|
|
60
|
-
from oscura.analyzers.digital.ic_database import (
|
|
61
|
-
IC_DATABASE,
|
|
62
|
-
ICTiming,
|
|
63
|
-
identify_ic,
|
|
64
|
-
validate_ic_timing,
|
|
65
|
-
)
|
|
66
58
|
from oscura.analyzers.digital.quality import (
|
|
67
59
|
Glitch,
|
|
68
60
|
NoiseMarginResult,
|
|
@@ -105,37 +97,13 @@ from oscura.analyzers.digital.timing import (
|
|
|
105
97
|
skew,
|
|
106
98
|
slew_rate,
|
|
107
99
|
)
|
|
108
|
-
from oscura.analyzers.digital.timing_paths import (
|
|
109
|
-
ICStage,
|
|
110
|
-
SetupHoldAnalysis,
|
|
111
|
-
TimingPathResult,
|
|
112
|
-
analyze_setup_hold,
|
|
113
|
-
analyze_timing_path,
|
|
114
|
-
calculate_timing_budget,
|
|
115
|
-
find_critical_paths,
|
|
116
|
-
)
|
|
117
|
-
from oscura.analyzers.digital.vintage import (
|
|
118
|
-
REPLACEMENT_DATABASE,
|
|
119
|
-
analyze_vintage_logic,
|
|
120
|
-
)
|
|
121
|
-
from oscura.analyzers.digital.vintage_result import (
|
|
122
|
-
BOMEntry,
|
|
123
|
-
ICIdentificationResult,
|
|
124
|
-
ModernReplacementIC,
|
|
125
|
-
VintageLogicAnalysisResult,
|
|
126
|
-
)
|
|
127
100
|
|
|
128
101
|
__all__ = [
|
|
129
|
-
# IC Database
|
|
130
|
-
"IC_DATABASE",
|
|
131
102
|
# Extraction
|
|
132
103
|
"LOGIC_FAMILIES",
|
|
133
|
-
"REPLACEMENT_DATABASE",
|
|
134
104
|
"AdaptiveThresholdResult",
|
|
135
105
|
# Adaptive Thresholds (RE-THR-001)
|
|
136
106
|
"AdaptiveThresholder",
|
|
137
|
-
# Vintage Logic Analysis
|
|
138
|
-
"BOMEntry",
|
|
139
107
|
# Clock Recovery (DSP-002)
|
|
140
108
|
"BaudRateResult",
|
|
141
109
|
# Bus Decoding (DSP-003)
|
|
@@ -157,10 +125,6 @@ __all__ = [
|
|
|
157
125
|
"EdgeTimingViolation",
|
|
158
126
|
# Quality
|
|
159
127
|
"Glitch",
|
|
160
|
-
"ICIdentificationResult",
|
|
161
|
-
"ICStage",
|
|
162
|
-
"ICTiming",
|
|
163
|
-
"ModernReplacementIC",
|
|
164
128
|
# Multi-Level Logic (RE-THR-002)
|
|
165
129
|
"MultiLevelDetector",
|
|
166
130
|
"MultiLevelResult",
|
|
@@ -168,25 +132,18 @@ __all__ = [
|
|
|
168
132
|
# Signal Quality (DSP-005)
|
|
169
133
|
"NoiseMargins",
|
|
170
134
|
"ParallelBusConfig",
|
|
171
|
-
"SetupHoldAnalysis",
|
|
172
135
|
"SignalIntegrityReport",
|
|
173
136
|
"SignalQualityAnalyzer",
|
|
174
137
|
"SimpleQualityMetrics",
|
|
175
138
|
"ThresholdConfig",
|
|
176
139
|
"TimingConstraint",
|
|
177
|
-
"TimingPathResult",
|
|
178
140
|
"TimingViolation",
|
|
179
141
|
"TransitionMetrics",
|
|
180
|
-
"VintageLogicAnalysisResult",
|
|
181
142
|
"Violation",
|
|
182
143
|
"align_by_trigger",
|
|
183
|
-
"analyze_setup_hold",
|
|
184
144
|
"analyze_signal_integrity",
|
|
185
|
-
"analyze_timing_path",
|
|
186
|
-
"analyze_vintage_logic",
|
|
187
145
|
"apply_adaptive_threshold",
|
|
188
146
|
"calculate_threshold_snr",
|
|
189
|
-
"calculate_timing_budget",
|
|
190
147
|
"check_timing_constraints",
|
|
191
148
|
"classify_edge_quality",
|
|
192
149
|
"correlate_channels",
|
|
@@ -196,14 +153,10 @@ __all__ = [
|
|
|
196
153
|
"detect_edges",
|
|
197
154
|
"detect_edges_advanced",
|
|
198
155
|
"detect_glitches",
|
|
199
|
-
"detect_logic_family",
|
|
200
156
|
"detect_multi_level",
|
|
201
|
-
"detect_open_collector",
|
|
202
157
|
"detect_violations",
|
|
203
|
-
"find_critical_paths",
|
|
204
158
|
"get_logic_threshold",
|
|
205
159
|
"hold_time",
|
|
206
|
-
"identify_ic",
|
|
207
160
|
"interpolate_edge_time",
|
|
208
161
|
"measure_clock_jitter",
|
|
209
162
|
"measure_edge_timing",
|
|
@@ -221,5 +174,4 @@ __all__ = [
|
|
|
221
174
|
"skew",
|
|
222
175
|
"slew_rate",
|
|
223
176
|
"to_digital",
|
|
224
|
-
"validate_ic_timing",
|
|
225
177
|
]
|
|
@@ -25,7 +25,6 @@ if TYPE_CHECKING:
|
|
|
25
25
|
# Standard logic family threshold constants
|
|
26
26
|
# Reference: Various IC manufacturer datasheets
|
|
27
27
|
LOGIC_FAMILIES: dict[str, dict[str, float]] = {
|
|
28
|
-
# Modern logic families (5V)
|
|
29
28
|
"TTL": {
|
|
30
29
|
"VIL_max": 0.8, # Maximum input low voltage
|
|
31
30
|
"VIH_min": 2.0, # Minimum input high voltage
|
|
@@ -75,63 +74,6 @@ LOGIC_FAMILIES: dict[str, dict[str, float]] = {
|
|
|
75
74
|
"VOH_min": 1.1,
|
|
76
75
|
"VCC": 1.2,
|
|
77
76
|
},
|
|
78
|
-
# Vintage logic families (1960s-1970s)
|
|
79
|
-
"ECL": {
|
|
80
|
-
"VIL_max": -1.475, # ECL 10K series
|
|
81
|
-
"VIH_min": -1.105,
|
|
82
|
-
"VOL_max": -1.630, # Typical -1.63V
|
|
83
|
-
"VOH_min": -0.980, # Typical -0.98V
|
|
84
|
-
"VCC": 0.0, # Ground-referenced
|
|
85
|
-
"VEE": -5.2, # Negative supply
|
|
86
|
-
"differential": True, # Differential signaling
|
|
87
|
-
},
|
|
88
|
-
"ECL_100K": {
|
|
89
|
-
"VIL_max": -1.810, # ECL 100K series (faster)
|
|
90
|
-
"VIH_min": -1.620,
|
|
91
|
-
"VOL_max": -1.950,
|
|
92
|
-
"VOH_min": -1.650,
|
|
93
|
-
"VCC": 0.0,
|
|
94
|
-
"VEE": -5.2,
|
|
95
|
-
"differential": True,
|
|
96
|
-
},
|
|
97
|
-
"RTL": {
|
|
98
|
-
"VIL_max": 0.4, # Resistor-Transistor Logic
|
|
99
|
-
"VIH_min": 0.9,
|
|
100
|
-
"VOL_max": 0.2,
|
|
101
|
-
"VOH_min": 3.6, # Typical 3.6V high output
|
|
102
|
-
"VCC": 3.6, # 3.6V supply common
|
|
103
|
-
},
|
|
104
|
-
"DTL": {
|
|
105
|
-
"VIL_max": 0.5, # Diode-Transistor Logic
|
|
106
|
-
"VIH_min": 2.0,
|
|
107
|
-
"VOL_max": 0.4,
|
|
108
|
-
"VOH_min": 4.0, # Typical 4V high output
|
|
109
|
-
"VCC": 5.0,
|
|
110
|
-
},
|
|
111
|
-
"MOS": {
|
|
112
|
-
"VIL_max": -3.0, # P-channel MOS (negative logic)
|
|
113
|
-
"VIH_min": -10.0,
|
|
114
|
-
"VOL_max": -0.5,
|
|
115
|
-
"VOH_min": -11.5,
|
|
116
|
-
"VCC": 0.0, # Ground
|
|
117
|
-
"VDD": -12.0, # Negative supply
|
|
118
|
-
},
|
|
119
|
-
"PMOS": {
|
|
120
|
-
"VIL_max": -3.0, # PMOS (4000 series at -12V)
|
|
121
|
-
"VIH_min": -9.0,
|
|
122
|
-
"VOL_max": -0.5,
|
|
123
|
-
"VOH_min": -11.5,
|
|
124
|
-
"VCC": 0.0,
|
|
125
|
-
"VDD": -12.0,
|
|
126
|
-
},
|
|
127
|
-
"NMOS": {
|
|
128
|
-
"VIL_max": 1.5, # NMOS (positive logic, 12V)
|
|
129
|
-
"VIH_min": 8.0,
|
|
130
|
-
"VOL_max": 0.5,
|
|
131
|
-
"VOH_min": 11.5,
|
|
132
|
-
"VCC": 12.0,
|
|
133
|
-
"VSS": 0.0,
|
|
134
|
-
},
|
|
135
77
|
}
|
|
136
78
|
|
|
137
79
|
|
|
@@ -463,146 +405,9 @@ def get_logic_threshold(
|
|
|
463
405
|
raise ValueError(f"Unknown threshold_type: {threshold_type}")
|
|
464
406
|
|
|
465
407
|
|
|
466
|
-
def detect_logic_family(
|
|
467
|
-
trace: WaveformTrace,
|
|
468
|
-
*,
|
|
469
|
-
confidence_threshold: float = 0.8,
|
|
470
|
-
) -> tuple[str, float]:
|
|
471
|
-
"""Auto-detect logic family from signal voltage levels.
|
|
472
|
-
|
|
473
|
-
Analyzes the signal to determine which logic family it most likely represents
|
|
474
|
-
based on voltage levels.
|
|
475
|
-
|
|
476
|
-
Args:
|
|
477
|
-
trace: Input analog waveform trace.
|
|
478
|
-
confidence_threshold: Minimum confidence (0-1) to return a match.
|
|
479
|
-
|
|
480
|
-
Returns:
|
|
481
|
-
Tuple of (family_name, confidence_score).
|
|
482
|
-
Returns ("unknown", 0.0) if no match above threshold.
|
|
483
|
-
|
|
484
|
-
Example:
|
|
485
|
-
>>> family, conf = detect_logic_family(trace)
|
|
486
|
-
>>> print(f"Detected: {family} ({conf*100:.1f}% confidence)")
|
|
487
|
-
"""
|
|
488
|
-
if len(trace.data) < 10:
|
|
489
|
-
return ("unknown", 0.0)
|
|
490
|
-
|
|
491
|
-
data = np.asarray(trace.data)
|
|
492
|
-
|
|
493
|
-
# Find voltage levels using percentiles
|
|
494
|
-
p10, p90 = np.percentile(data, [10, 90])
|
|
495
|
-
vlow = p10
|
|
496
|
-
vhigh = p90
|
|
497
|
-
|
|
498
|
-
# Calculate midpoint and swing
|
|
499
|
-
vmid = (vlow + vhigh) / 2.0
|
|
500
|
-
vswing = vhigh - vlow
|
|
501
|
-
|
|
502
|
-
if vswing < 0.1: # Insufficient signal
|
|
503
|
-
return ("unknown", 0.0)
|
|
504
|
-
|
|
505
|
-
# Score each logic family
|
|
506
|
-
scores: dict[str, float] = {}
|
|
507
|
-
|
|
508
|
-
for family_name, levels in LOGIC_FAMILIES.items():
|
|
509
|
-
# Check if voltage levels match this family
|
|
510
|
-
vil_max = levels["VIL_max"]
|
|
511
|
-
vih_min = levels["VIH_min"]
|
|
512
|
-
vcc = levels.get("VCC", 5.0)
|
|
513
|
-
|
|
514
|
-
# Expected midpoint for this family
|
|
515
|
-
expected_mid = (vil_max + vih_min) / 2.0
|
|
516
|
-
|
|
517
|
-
# Score based on:
|
|
518
|
-
# 1. Midpoint proximity
|
|
519
|
-
# 2. High level proximity to VOH
|
|
520
|
-
# 3. Low level proximity to VOL
|
|
521
|
-
|
|
522
|
-
mid_error = abs(vmid - expected_mid)
|
|
523
|
-
high_error = abs(vhigh - levels.get("VOH_min", vih_min))
|
|
524
|
-
low_error = abs(vlow - levels.get("VOL_max", vil_max))
|
|
525
|
-
|
|
526
|
-
# Normalize errors (handle VCC=0 for ECL/PMOS)
|
|
527
|
-
if vcc != 0:
|
|
528
|
-
mid_score = max(0, 1.0 - mid_error / abs(vcc))
|
|
529
|
-
high_score = max(0, 1.0 - high_error / abs(vcc))
|
|
530
|
-
low_score = max(0, 1.0 - low_error / abs(vcc))
|
|
531
|
-
else:
|
|
532
|
-
# For VCC=0 families (ECL), use voltage range instead
|
|
533
|
-
voltage_range = abs(vih_min - vil_max)
|
|
534
|
-
if voltage_range > 0:
|
|
535
|
-
mid_score = max(0, 1.0 - mid_error / voltage_range)
|
|
536
|
-
high_score = max(0, 1.0 - high_error / voltage_range)
|
|
537
|
-
low_score = max(0, 1.0 - low_error / voltage_range)
|
|
538
|
-
else:
|
|
539
|
-
mid_score = high_score = low_score = 0.0
|
|
540
|
-
|
|
541
|
-
# Combined score (weighted average)
|
|
542
|
-
total_score = mid_score * 0.5 + high_score * 0.25 + low_score * 0.25
|
|
543
|
-
scores[family_name] = total_score
|
|
544
|
-
|
|
545
|
-
# Find best match
|
|
546
|
-
if not scores:
|
|
547
|
-
return ("unknown", 0.0)
|
|
548
|
-
|
|
549
|
-
best_family = max(scores.items(), key=lambda x: x[1])
|
|
550
|
-
|
|
551
|
-
if best_family[1] < confidence_threshold:
|
|
552
|
-
return ("unknown", best_family[1])
|
|
553
|
-
|
|
554
|
-
return best_family
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
def detect_open_collector(
|
|
558
|
-
trace: WaveformTrace,
|
|
559
|
-
*,
|
|
560
|
-
asymmetry_threshold: float = 3.0,
|
|
561
|
-
) -> tuple[bool, float]:
|
|
562
|
-
"""Detect open-collector or open-drain output.
|
|
563
|
-
|
|
564
|
-
Open-collector outputs have slow rise times (limited by pull-up resistor)
|
|
565
|
-
and fast fall times (active transistor).
|
|
566
|
-
|
|
567
|
-
Args:
|
|
568
|
-
trace: Input analog waveform trace.
|
|
569
|
-
asymmetry_threshold: Minimum rise/fall ratio to indicate open-collector.
|
|
570
|
-
|
|
571
|
-
Returns:
|
|
572
|
-
Tuple of (is_open_collector, asymmetry_ratio).
|
|
573
|
-
|
|
574
|
-
Example:
|
|
575
|
-
>>> is_oc, ratio = detect_open_collector(trace)
|
|
576
|
-
>>> if is_oc:
|
|
577
|
-
... print(f"Open-collector detected (rise/fall = {ratio:.1f})")
|
|
578
|
-
"""
|
|
579
|
-
from oscura.analyzers.waveform.measurements import fall_time, rise_time
|
|
580
|
-
|
|
581
|
-
if len(trace.data) < 10:
|
|
582
|
-
return (False, 1.0)
|
|
583
|
-
|
|
584
|
-
# Measure rise and fall times
|
|
585
|
-
tr = rise_time(trace, ref_levels=(0.1, 0.9))
|
|
586
|
-
tf = fall_time(trace, ref_levels=(0.9, 0.1))
|
|
587
|
-
|
|
588
|
-
# Check for valid measurements
|
|
589
|
-
if np.isnan(tr) or np.isnan(tf) or tf == 0:
|
|
590
|
-
return (False, 1.0)
|
|
591
|
-
|
|
592
|
-
# Calculate asymmetry ratio
|
|
593
|
-
asymmetry = tr / tf
|
|
594
|
-
|
|
595
|
-
# Open-collector has slow rise, fast fall
|
|
596
|
-
is_oc = bool(asymmetry >= asymmetry_threshold)
|
|
597
|
-
|
|
598
|
-
return (is_oc, float(asymmetry))
|
|
599
|
-
|
|
600
|
-
|
|
601
408
|
__all__ = [
|
|
602
409
|
"LOGIC_FAMILIES",
|
|
603
410
|
"detect_edges",
|
|
604
|
-
"detect_logic_family",
|
|
605
|
-
"detect_open_collector",
|
|
606
411
|
"get_logic_threshold",
|
|
607
412
|
"to_digital",
|
|
608
413
|
]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Provides protocol decoders for common serial and automotive protocols including
|
|
4
4
|
UART, SPI, I2C, CAN, LIN, FlexRay, JTAG, SWD, I2S, USB, HDLC, Manchester, CAN-FD,
|
|
5
|
-
1-Wire
|
|
5
|
+
and 1-Wire.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from oscura.analyzers.protocols.base import (
|
|
@@ -60,18 +60,6 @@ from oscura.analyzers.protocols.onewire import (
|
|
|
60
60
|
OneWireTimings,
|
|
61
61
|
decode_onewire,
|
|
62
62
|
)
|
|
63
|
-
|
|
64
|
-
# Parallel bus protocols
|
|
65
|
-
from oscura.analyzers.protocols.parallel_bus import (
|
|
66
|
-
CentronicsFrame,
|
|
67
|
-
GPIBFrame,
|
|
68
|
-
GPIBMessageType,
|
|
69
|
-
ISACycleType,
|
|
70
|
-
ISATransaction,
|
|
71
|
-
decode_centronics,
|
|
72
|
-
decode_gpib,
|
|
73
|
-
decode_isa_bus,
|
|
74
|
-
)
|
|
75
63
|
from oscura.analyzers.protocols.spi import SPIDecoder, decode_spi
|
|
76
64
|
from oscura.analyzers.protocols.swd import SWDDecoder, SWDResponse, decode_swd
|
|
77
65
|
from oscura.analyzers.protocols.uart import UARTDecoder, decode_uart
|
|
@@ -103,16 +91,12 @@ __all__ = [
|
|
|
103
91
|
"CANFDFrameType",
|
|
104
92
|
"CANFrame",
|
|
105
93
|
"CANFrameType",
|
|
106
|
-
# Parallel bus protocols
|
|
107
|
-
"CentronicsFrame",
|
|
108
94
|
"ChannelDef",
|
|
109
95
|
"DecoderState",
|
|
110
96
|
# FlexRay (PRO-016)
|
|
111
97
|
"FlexRayDecoder",
|
|
112
98
|
"FlexRayFrame",
|
|
113
99
|
"FlexRaySegment",
|
|
114
|
-
"GPIBFrame",
|
|
115
|
-
"GPIBMessageType",
|
|
116
100
|
# HDLC (PRO-013)
|
|
117
101
|
"HDLCDecoder",
|
|
118
102
|
# I2C (PRO-004)
|
|
@@ -120,8 +104,6 @@ __all__ = [
|
|
|
120
104
|
# I2S (PRO-011)
|
|
121
105
|
"I2SDecoder",
|
|
122
106
|
"I2SMode",
|
|
123
|
-
"ISACycleType",
|
|
124
|
-
"ISATransaction",
|
|
125
107
|
# JTAG (PRO-009)
|
|
126
108
|
"JTAGDecoder",
|
|
127
109
|
# LIN (PRO-008)
|
|
@@ -153,13 +135,10 @@ __all__ = [
|
|
|
153
135
|
"USBSpeed",
|
|
154
136
|
"decode_can",
|
|
155
137
|
"decode_can_fd",
|
|
156
|
-
"decode_centronics",
|
|
157
138
|
"decode_flexray",
|
|
158
|
-
"decode_gpib",
|
|
159
139
|
"decode_hdlc",
|
|
160
140
|
"decode_i2c",
|
|
161
141
|
"decode_i2s",
|
|
162
|
-
"decode_isa_bus",
|
|
163
142
|
"decode_jtag",
|
|
164
143
|
"decode_lin",
|
|
165
144
|
"decode_manchester",
|