Skip to content

Commit 08de0d0

Browse files
feat: add Pico SCPI transport (#286)
1 parent 2a04d4a commit 08de0d0

5 files changed

Lines changed: 710 additions & 0 deletions

File tree

pslab/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
from pslab.instrument.oscilloscope import Oscilloscope
66
from pslab.instrument.power_supply import PowerSupply
77
from pslab.instrument.waveform_generator import PWMGenerator, WaveformGenerator
8+
from pslab.pico import PicoDevice
89
from pslab.sciencelab import ScienceLab
910

1011
__all__ = (
1112
"LogicAnalyzer",
1213
"Multimeter",
1314
"Oscilloscope",
15+
"PicoDevice",
1416
"PowerSupply",
1517
"PWMGenerator",
1618
"WaveformGenerator",

pslab/pico/__init__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""PSLab Pico SCPI support."""
2+
3+
from pslab.pico.device import PicoDevice
4+
from pslab.pico.transport import (
5+
PicoTransport,
6+
PicoUsbTransport,
7+
PicoWifiTransport,
8+
ScpiClient,
9+
ScpiError,
10+
ScpiTimeoutError,
11+
)
12+
13+
__all__ = (
14+
"PicoDevice",
15+
"PicoTransport",
16+
"PicoUsbTransport",
17+
"PicoWifiTransport",
18+
"ScpiClient",
19+
"ScpiError",
20+
"ScpiTimeoutError",
21+
)

pslab/pico/device.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""High-level PSLab Pico device entry point."""
2+
3+
from __future__ import annotations
4+
5+
from typing import Optional
6+
7+
from pslab.pico.transport import PicoTransport, PicoUsbTransport, PicoWifiTransport, ScpiClient
8+
9+
10+
class PicoDevice:
11+
"""Connected PSLab Pico firmware device.
12+
13+
The Pico firmware speaks SCPI over USB CDC or over the ESP32-C3 TCP bridge.
14+
This object owns the shared SCPI client used by future Pico instruments.
15+
"""
16+
17+
def __init__(self, client: ScpiClient) -> None:
18+
self.scpi = client
19+
20+
@classmethod
21+
def usb(
22+
cls,
23+
port: Optional[str] = None,
24+
baudrate: int = 115200,
25+
timeout: Optional[float] = 2.0,
26+
) -> "PicoDevice":
27+
"""Create a Pico device using USB CDC."""
28+
29+
return cls(ScpiClient(PicoUsbTransport(port, baudrate, timeout)))
30+
31+
@classmethod
32+
def wifi(
33+
cls,
34+
host: str,
35+
port: int = PicoWifiTransport.DEFAULT_PORT,
36+
timeout: Optional[float] = 2.0,
37+
) -> "PicoDevice":
38+
"""Create a Pico device using the ESP TCP SCPI bridge."""
39+
40+
return cls(ScpiClient(PicoWifiTransport(host, port, timeout)))
41+
42+
@classmethod
43+
def from_transport(cls, transport: PicoTransport) -> "PicoDevice":
44+
"""Create a Pico device from a custom transport."""
45+
46+
return cls(ScpiClient(transport))
47+
48+
def connect(self) -> None:
49+
"""Open the underlying transport."""
50+
51+
self.scpi.connect()
52+
53+
def close(self) -> None:
54+
"""Close the underlying transport."""
55+
56+
self.scpi.close()
57+
58+
def identify(self) -> str:
59+
"""Return the firmware identification string."""
60+
61+
return self.scpi.identify()
62+
63+
def reset(self) -> None:
64+
"""Reset all instrument state in the firmware."""
65+
66+
self.scpi.reset()
67+
68+
def clear_status(self) -> None:
69+
"""Clear the SCPI status and error queues."""
70+
71+
self.scpi.clear_status()
72+
73+
def set_transport(self, mode: str) -> None:
74+
"""Select capture data transport: ``USB``, ``WIFI``, or ``AUTO``."""
75+
76+
self.scpi.set_transport(mode)
77+
78+
def get_transport(self) -> str:
79+
"""Return the selected capture data transport."""
80+
81+
return self.scpi.get_transport()
82+
83+
def wifi_status(self):
84+
"""Return Wi-Fi transport status counters."""
85+
86+
return self.scpi.wifi_status()
87+
88+
def __enter__(self) -> "PicoDevice":
89+
self.connect()
90+
return self
91+
92+
def __exit__(self, exc_type, exc, traceback) -> None:
93+
self.close()

0 commit comments

Comments
 (0)