Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit 953cc5c

Browse files
committed
sigrok: initial sigrok driver
1 parent fa0a3b5 commit 953cc5c

12 files changed

Lines changed: 774 additions & 0 deletions

File tree

docs/source/reference/package-apis/drivers/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ Drivers for debugging and programming devices:
7171
* **[QEMU](qemu.md)** (`jumpstarter-driver-qemu`) - QEMU virtualization platform
7272
* **[Corellium](corellium.md)** (`jumpstarter-driver-corellium`) - Corellium
7373
virtualization platform
74+
* **[Sigrok](sigrok.md)** (`jumpstarter-driver-sigrok`) - Logic analyzer and
75+
oscilloscope support via sigrok-cli
7476
* **[U-Boot](uboot.md)** (`jumpstarter-driver-uboot`) - Universal Bootloader
7577
interface
7678
* **[RideSX](ridesx.md)** (`jumpstarter-driver-ridesx`) - Flashing and power management for Qualcomm RideSX devices
@@ -104,6 +106,7 @@ gpiod.md
104106
ridesx.md
105107
sdwire.md
106108
shell.md
109+
sigrok.md
107110
ssh.md
108111
snmp.md
109112
tasmota.md
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../../packages/jumpstarter-driver-sigrok/README.md
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ����������������������������������������ݾ�������������������ٶ�������������������������������������
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__pycache__/
2+
.coverage
3+
coverage.xml
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Sigrok Driver
2+
3+
`jumpstarter-driver-sigrok` wraps `sigrok-cli` to provide logic analyzer and oscilloscope capture from Jumpstarter exporters. It supports:
4+
- **Logic analyzers** (digital channels) - with protocol decoding (SPI, I2C, UART, etc.)
5+
- **Oscilloscopes** (analog channels) - voltage waveform capture
6+
- One-shot and streaming capture
7+
- Decoder-friendly channel mappings
8+
- Real-time protocol decoding
9+
10+
## Installation
11+
12+
```shell
13+
pip3 install --extra-index-url https://pkg.jumpstarter.dev/simple/ jumpstarter-driver-sigrok
14+
```
15+
16+
## Configuration (exporter)
17+
18+
```yaml
19+
export:
20+
sigrok:
21+
type: jumpstarter_driver_sigrok.driver.Sigrok
22+
driver: demo # sigrok driver (demo, fx2lafw, etc.)
23+
conn: null # optional: USB VID.PID or serial path
24+
executable: null # optional: path to sigrok-cli (auto-detected)
25+
channels: # channel mappings (device_name: semantic_name)
26+
D0: vcc
27+
D1: cs
28+
D2: miso
29+
D3: mosi
30+
D4: clk
31+
D5: sda
32+
D6: scl
33+
```
34+
35+
## CaptureConfig (client-side)
36+
37+
```python
38+
from jumpstarter_driver_sigrok.common import CaptureConfig, DecoderConfig
39+
40+
config = CaptureConfig(
41+
sample_rate="8MHz",
42+
samples=20000,
43+
pretrigger=5000,
44+
triggers={"cs": "falling"},
45+
decoders=[
46+
DecoderConfig(
47+
name="spi",
48+
channels={"clk": "clk", "mosi": "mosi", "miso": "miso", "cs": "cs"},
49+
annotations=["mosi-data"],
50+
)
51+
],
52+
)
53+
```
54+
55+
This maps to:
56+
```bash
57+
sigrok-cli -d fx2lafw -c samplerate=8MHz,samples=20000,pretrigger=5000 --triggers D1=falling \
58+
-P spi:clk=D4:mosi=D3:miso=D2:cs=D1 -A spi=mosi-data
59+
```
60+
61+
## Client API
62+
63+
- `scan()` — list devices for the configured driver
64+
- `capture(config)` — one-shot capture, returns `CaptureResult` with base64 data
65+
- `capture_stream(config)` — streaming capture via `--continuous`
66+
- `get_driver_info()` — driver, conn, channel map
67+
- `get_channel_map()` — device-to-semantic name mappings
68+
- `list_output_formats()` — supported formats (csv, srzip, vcd, binary, bits, ascii)
69+
70+
## Examples
71+
72+
### Logic Analyzer (Digital Channels)
73+
74+
One-shot with trigger:
75+
```bash
76+
sigrok-cli -d fx2lafw -c samplerate=8MHz,samples=20000,pretrigger=5000 --triggers D0=rising -o out.sr
77+
```
78+
79+
Real-time decode (SPI):
80+
```bash
81+
sigrok-cli -d fx2lafw -c samplerate=1M --continuous \
82+
-P spi:clk=D4:mosi=D3:miso=D2:cs=D1 -A spi=mosi-data
83+
```
84+
85+
### Oscilloscope (Analog Channels)
86+
87+
```yaml
88+
export:
89+
oscilloscope:
90+
type: jumpstarter_driver_sigrok.driver.Sigrok
91+
driver: rigol-ds # or demo for testing
92+
conn: usb # or serial path
93+
channels:
94+
A0: CH1
95+
A1: CH2
96+
```
97+
98+
```python
99+
from jumpstarter_driver_sigrok.common import CaptureConfig
100+
101+
# Capture analog waveforms
102+
config = CaptureConfig(
103+
sample_rate="1MHz",
104+
samples=10000,
105+
channels=["CH1", "CH2"], # Analog channels
106+
output_format="csv", # or "vcd" for waveform viewers
107+
)
108+
result = client.capture(config)
109+
waveform_data = result.data # bytes with voltage measurements
110+
```
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: jumpstarter.dev/v1alpha1
2+
kind: ExporterConfig
3+
metadata:
4+
namespace: default
5+
name: demo
6+
endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082
7+
token: "<token>"
8+
export:
9+
sigrok:
10+
type: jumpstarter_driver_sigrok.driver.Sigrok
11+
driver: demo
12+
conn: null
13+
channels:
14+
D0: vcc
15+
D1: cs
16+
D2: miso
17+
D3: mosi
18+
D4: clk
19+
D5: sda
20+
D6: scl
21+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from jumpstarter_driver_sigrok.common import CaptureConfig, CaptureResult, DecoderConfig
2+
from jumpstarter_driver_sigrok.driver import Sigrok
3+
4+
__all__ = ["Sigrok", "CaptureConfig", "CaptureResult", "DecoderConfig"]
5+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from dataclasses import dataclass
2+
3+
from .common import CaptureConfig, CaptureResult
4+
from jumpstarter.client import DriverClient
5+
6+
7+
@dataclass(kw_only=True)
8+
class SigrokClient(DriverClient):
9+
"""Client methods for the Sigrok driver."""
10+
11+
def scan(self) -> str:
12+
return self.call("scan")
13+
14+
def capture(self, config: CaptureConfig | dict) -> CaptureResult:
15+
return CaptureResult.model_validate(self.call("capture", config))
16+
17+
def capture_stream(self, config: CaptureConfig | dict):
18+
"""Stream capture data from sigrok-cli.
19+
20+
Args:
21+
config: CaptureConfig or dict with capture parameters
22+
23+
Yields:
24+
bytes: Chunks of captured data
25+
"""
26+
for chunk in self.streamingcall("capture_stream", config):
27+
yield chunk
28+
29+
def get_driver_info(self) -> dict:
30+
return self.call("get_driver_info")
31+
32+
def get_channel_map(self) -> dict:
33+
return self.call("get_channel_map")
34+
35+
def list_output_formats(self) -> list[str]:
36+
return self.call("list_output_formats")
37+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from __future__ import annotations
2+
3+
from typing import Any
4+
5+
from pydantic import BaseModel, Field
6+
7+
8+
class DecoderConfig(BaseModel):
9+
"""Protocol decoder configuration (real-time during capture)."""
10+
11+
name: str
12+
channels: dict[str, str] | None = None
13+
options: dict[str, Any] | None = None
14+
annotations: list[str] | None = None
15+
stack: list["DecoderConfig"] | None = None
16+
17+
18+
class CaptureConfig(BaseModel):
19+
sample_rate: str = Field(default="1M", description="e.g., 8MHz, 1M, 24000000")
20+
samples: int | None = Field(default=None, description="number of samples; None for continuous")
21+
pretrigger: int | None = Field(default=None, description="samples before trigger")
22+
triggers: dict[str, str] | None = Field(default=None, description="e.g., {'D0': 'rising'}")
23+
channels: list[str] | None = Field(default=None, description="override default channels by name")
24+
output_format: str = Field(
25+
default="srzip",
26+
description="csv, srzip, vcd, binary, bits, ascii",
27+
)
28+
decoders: list[DecoderConfig] | None = Field(default=None, description="real-time protocol decoding")
29+
30+
31+
class CaptureResult(BaseModel):
32+
"""Result from a capture operation.
33+
34+
Note: data is base64-encoded for reliable JSON transport. Client methods
35+
automatically decode it to bytes for you.
36+
"""
37+
data_b64: str # Base64-encoded binary data
38+
output_format: str
39+
sample_rate: str
40+
channel_map: dict[str, str]
41+
triggers: dict[str, str] | None = None
42+
decoders: list[DecoderConfig] | None = None
43+
44+
@property
45+
def data(self) -> bytes:
46+
"""Get the captured data as bytes (auto-decodes from base64)."""
47+
from base64 import b64decode
48+
return b64decode(self.data_b64)
49+

0 commit comments

Comments
 (0)