115 lines
4.1 KiB
Python
115 lines
4.1 KiB
Python
import pytest
|
|
|
|
from line_laser_modbus.client import LineLaserClient
|
|
from line_laser_modbus.config import SerialConfig
|
|
from line_laser_modbus.constants import (
|
|
ADDR_CORRECTION,
|
|
ADDR_CURRENT_POSE,
|
|
ADDR_MODE_COMMAND,
|
|
ADDR_TARGET_POSE,
|
|
)
|
|
from line_laser_modbus.models import DeviceStatus, ModeCommand, Pose6D, TimedPose6D
|
|
from line_laser_modbus.simulator import SimulatedModbusBackend
|
|
|
|
|
|
class CountingBackend(SimulatedModbusBackend):
|
|
def __init__(self, **kwargs) -> None:
|
|
super().__init__(**kwargs)
|
|
self.read_addresses: list[int] = []
|
|
|
|
def read_holding_registers(self, address: int, *, count: int, device_id: int):
|
|
self.read_addresses.append(address)
|
|
return super().read_holding_registers(address, count=count, device_id=device_id)
|
|
|
|
|
|
def test_client_reads_seeded_status_and_pose_from_simulator() -> None:
|
|
pose = Pose6D(10.0, 20.0, 30.0, 1.0, 2.0, 3.0)
|
|
backend = SimulatedModbusBackend(
|
|
status=DeviceStatus.TRACKING_OK,
|
|
current_pose=pose,
|
|
)
|
|
|
|
with LineLaserClient(SerialConfig(port="SIM"), backend=backend) as client:
|
|
assert client.read_status() is DeviceStatus.TRACKING_OK
|
|
assert client.read_current_pose() == pose
|
|
timed_pose = client.read_current_timed_pose()
|
|
assert timed_pose.timestamp == 0
|
|
assert timed_pose.pose == pose
|
|
|
|
|
|
def test_client_writes_mode_and_correction_to_simulator() -> None:
|
|
backend = SimulatedModbusBackend()
|
|
correction = Pose6D(1.0, 2.0, 3.0, 0.0, 1.0, 2.0)
|
|
|
|
with LineLaserClient(SerialConfig(port="SIM"), backend=backend) as client:
|
|
client.write_mode(ModeCommand.ONLINE_TRACKING)
|
|
client.write_correction(correction)
|
|
|
|
assert client.read_mode() is ModeCommand.ONLINE_TRACKING
|
|
assert backend.correction() == correction
|
|
|
|
|
|
def test_client_rejects_emergency_stop_as_normal_mode_write() -> None:
|
|
backend = SimulatedModbusBackend()
|
|
|
|
with (
|
|
pytest.raises(ValueError, match="reserved for emergency stop"),
|
|
LineLaserClient(SerialConfig(port="SIM"), backend=backend) as client,
|
|
):
|
|
client.write_mode(ModeCommand.EMERGENCY_STOP)
|
|
|
|
|
|
def test_client_triggers_emergency_stop_as_special_command() -> None:
|
|
backend = SimulatedModbusBackend()
|
|
|
|
with LineLaserClient(SerialConfig(port="SIM"), backend=backend) as client:
|
|
client.trigger_emergency_stop()
|
|
|
|
assert backend.registers[ADDR_MODE_COMMAND] == ModeCommand.EMERGENCY_STOP.value
|
|
|
|
|
|
def test_snapshot_skips_pose_read_in_manual_teaching_mode() -> None:
|
|
backend = CountingBackend(mode=ModeCommand.MANUAL_TEACHING, status=DeviceStatus.IDLE)
|
|
|
|
with LineLaserClient(SerialConfig(port="SIM"), backend=backend) as client:
|
|
snapshot = client.read_snapshot()
|
|
|
|
assert snapshot.mode is ModeCommand.MANUAL_TEACHING
|
|
assert snapshot.status is DeviceStatus.IDLE
|
|
assert snapshot.pose == Pose6D.zeros()
|
|
assert ADDR_CURRENT_POSE not in backend.read_addresses
|
|
|
|
|
|
def test_client_writes_timed_target_pose_to_simulator() -> None:
|
|
backend = SimulatedModbusBackend()
|
|
target = TimedPose6D(1234, Pose6D(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
|
|
|
|
with LineLaserClient(SerialConfig(port="SIM"), backend=backend) as client:
|
|
client.write_target_timed_pose(target)
|
|
|
|
assert backend.target_pose() == target.pose
|
|
assert backend.registers[ADDR_TARGET_POSE] == 0x0000
|
|
assert backend.registers[ADDR_TARGET_POSE + 1] == 0x04D2
|
|
|
|
|
|
def test_client_writes_timed_correction_to_simulator() -> None:
|
|
backend = SimulatedModbusBackend()
|
|
correction = TimedPose6D(1000, Pose6D(1.0, 2.0, 3.0, 0.0, 1.0, 2.0))
|
|
|
|
with LineLaserClient(SerialConfig(port="SIM"), backend=backend) as client:
|
|
client.write_timed_correction(correction)
|
|
|
|
assert backend.correction() == correction.pose
|
|
assert backend.registers[ADDR_CORRECTION] == 0x0000
|
|
assert backend.registers[ADDR_CORRECTION + 1] == 0x03E8
|
|
|
|
|
|
def test_simulator_rejects_wrong_slave_id() -> None:
|
|
backend = SimulatedModbusBackend()
|
|
|
|
with (
|
|
pytest.raises(ConnectionError),
|
|
LineLaserClient(SerialConfig(port="SIM", slave_id=0x09), backend=backend) as client,
|
|
):
|
|
client.read_status()
|