Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ from harp import serial
from harp.device import behavior, core

# Use "COMx" on Windows, "/dev/ttyUSBx" on Linux.
with serial.open_serial_device(behavior, port="COM3") as device:
with serial.open_device(behavior, port="COM3") as device:
print(device.read(core.WhoAmI).parsed) # a common register
print(device.read(behavior.AnalogData).parsed) # a device register
device.write(
Expand Down
2 changes: 1 addition & 1 deletion docs/api/serial.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
---

::: harp.serial.SerialTransport
::: harp.serial.open_serial_device
::: harp.serial.open_device
2 changes: 1 addition & 1 deletion docs/examples/create_device_module/create_device_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# Registers are ordinary register classes, so they work with `read` and `write` on
# any `Device` over a transport. Passing the module itself validates the device
# identity on open, against its `WHO_AM_I`, which a value of `0` skips.
with serial.open_serial_device(behavior, port=SERIAL_PORT) as device:
with serial.open_device(behavior, port=SERIAL_PORT) as device:
print("AnalogData:", device.read(AnalogData).parsed)

# The same register classes also decode a recorded binary dump into a pandas
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/get_info/get_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

# Omitting the device argument gives schema-free access, which skips the identity
# check, so this works against any device. The connection closes on exit.
with serial.open_serial_device(port=SERIAL_PORT) as device:
with serial.open_device(port=SERIAL_PORT) as device:
# Identify the device.
print("WhoAmI:", device.read(core.WhoAmI).parsed)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

SERIAL_PORT = "/dev/ttyUSB0" # or "COMx" in Windows, where "x" is the serial port number

with serial.open_serial_device(client.Device, port=SERIAL_PORT) as device:
with serial.open_device(client.Device, port=SERIAL_PORT) as device:
# Read a scalar register.
print("WhoAmI:", device.read(core.WhoAmI).parsed)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def print_any_event(msg: HarpMessage) -> None:
print(f"[{msg.address}] {msg.timestamp:.6f} {msg.message_type.name:<5s} {value}")


with serial.open_serial_device(client.Device, port=SERIAL_PORT) as device:
with serial.open_device(client.Device, port=SERIAL_PORT) as device:
# Subscribe to a single, typed register: the handler receives a parsed payload.
timestamp_subscription = device.subscribe(core.TimestampSeconds, print_timestamp)

Expand Down
2 changes: 1 addition & 1 deletion src/packages/harp-device/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ This is the same structure `create_device_module` builds from a schema, so a dev

A device module names only what its schema declares, the registers beside the enums and payload classes they are built from, so `REGISTER_MAP` is the device address space while the module namespace is what the device adds to it. The common registers and any core mask the schema reuses have a single definition, in `harp.device.core`, and are reached from there rather than through the device module. The core register set is not a device, so it carries no `WHO_AM_I`.

Pass the module to `Device`, or to `open_serial_device`, to validate identity on open:
Pass the module to `Device`, or to `open_device`, to validate identity on open:

```python
from harp.device import behavior, client, core
Expand Down
4 changes: 2 additions & 2 deletions src/packages/harp-serial/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# harp-serial

Serial transport for [`harp-device`](../harp-device). Provides `SerialTransport` and the `open_serial_device` factory, which pairs a device module or a `Device` class with a serial port. This is the package that pulls in `pyserial`.
Serial transport for [`harp-device`](../harp-device). Provides `SerialTransport` and the `open_device` factory, which pairs a device module or a `Device` class with a serial port. This is the package that pulls in `pyserial`.

## Usage

Expand All @@ -11,7 +11,7 @@ from harp import serial
from harp.device import behavior, core

# Use "COMx" on Windows, "/dev/ttyUSBx" on Linux.
with serial.open_serial_device(behavior, port="COM3") as device:
with serial.open_device(behavior, port="COM3") as device:
print(device.read(core.WhoAmI).parsed) # a common register
print(device.read(behavior.AnalogData).parsed) # a device register
```
Expand Down
4 changes: 2 additions & 2 deletions src/packages/harp-serial/src/harp/serial/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from ._serial import SerialTransport, open_serial_device
from ._serial import SerialTransport, open_device

__all__ = [
"SerialTransport",
"open_serial_device",
"open_device",
]
12 changes: 6 additions & 6 deletions src/packages/harp-serial/src/harp/serial/_serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def close(self) -> None:


@overload
def open_serial_device(
def open_device(
device_or_module: type[D],
*,
port: str,
Expand All @@ -64,7 +64,7 @@ def open_serial_device(


@overload
def open_serial_device(
def open_device(
device_or_module: M,
*,
port: str,
Expand All @@ -74,7 +74,7 @@ def open_serial_device(


@overload
def open_serial_device(
def open_device(
device_or_module: None = ...,
*,
port: str,
Expand All @@ -83,7 +83,7 @@ def open_serial_device(
) -> Device[None]: ...


def open_serial_device(
def open_device(
device_or_module: DeviceModuleLike | type[D] | None = None,
*,
port: str,
Expand All @@ -98,13 +98,13 @@ def open_serial_device(

from harp.device import behavior, core

with open_serial_device(behavior, port="COM3") as dev:
with open_device(behavior, port="COM3") as dev:
dev.read(core.WhoAmI) # a common register
dev.read(behavior.AnalogData) # declared by the schema

- **Device subclass**: instantiates the subclass directly, preserving its type::

with open_serial_device(MyBehavior, port="COM3") as dev:
with open_device(MyBehavior, port="COM3") as dev:
dev.arm() # method defined on MyBehavior

Omit the first argument for schema-free access, which skips the identity check.
Expand Down
24 changes: 12 additions & 12 deletions tests/conformance.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from harp.device.core import OperationControl, OperationControlPayload, WhoAmI
from harp.device.schema import DeviceModule, DeviceModuleLike, create_device_module
from harp.protocol import ParsedHarpMessage, RegisterBase
from harp.serial import open_serial_device
from harp.serial import open_device


def schema_built_registers(yml: str) -> None:
Expand Down Expand Up @@ -51,27 +51,27 @@ def device_without_module(transport: ITransport) -> None:
assert_type(device.module, None)


def open_serial_device_with_module(module: DeviceModule) -> None:
"""open_serial_device with a module returns Device[M]."""
device = open_serial_device(module, port="COM3")
def open_device_with_module(module: DeviceModule) -> None:
"""open_device with a module returns Device[M]."""
device = open_device(module, port="COM3")
assert_type(device, Device[DeviceModule])
assert_type(device.module, DeviceModule)


def open_serial_device_without_module() -> None:
"""open_serial_device without a module returns Device[None]."""
device = open_serial_device(port="COM3")
def open_device_without_module() -> None:
"""open_device without a module returns Device[None]."""
device = open_device(port="COM3")
assert_type(device, Device[None])
assert_type(device.module, None)


def open_serial_device_with_subclass() -> None:
"""open_serial_device with a Device subclass preserves its type."""
def open_device_with_subclass() -> None:
"""open_device with a Device subclass preserves its type."""

class MyDevice(Device[DeviceModule]):
def arm(self) -> None: ...

device = open_serial_device(MyDevice, port="COM3")
device = open_device(MyDevice, port="COM3")
assert_type(device, MyDevice)


Expand Down Expand Up @@ -115,7 +115,7 @@ def open_dataset_keeps_supplied_module_type(generated: DeviceModuleLike) -> None
assert_type(open_dataset("session.harp", generated), DatasetReader[DeviceModuleLike])


def open_serial_device_prefers_the_subclass_overload() -> None:
def open_device_prefers_the_subclass_overload() -> None:
"""A Device subclass is matched as a subclass even when it looks like a module.

type[D] is narrower than the structural module overload, so it has to come first:
Expand All @@ -129,5 +129,5 @@ class Hybrid(Device[None]):
WHO_AM_I: ClassVar[int] = 1216
REGISTER_MAP: ClassVar[dict[int, type[RegisterBase[Any]]]] = {}

device = open_serial_device(Hybrid, port="COM3")
device = open_device(Hybrid, port="COM3")
assert_type(device, Hybrid)