Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hardware): Added a driver to read and write data from the Flex eeprom #12847

Merged
merged 18 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from 17 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
41 changes: 35 additions & 6 deletions api/src/opentrons/hardware_control/backends/ot3controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
except (OSError, ModuleNotFoundError):
aionotify = None


from opentrons_hardware.drivers import SystemDrivers
from opentrons_hardware.drivers.can_bus import CanMessenger, DriverSettings
from opentrons_hardware.drivers.can_bus.abstract_driver import AbstractCanDriver
from opentrons_hardware.drivers.can_bus.build import build_driver
Expand All @@ -58,6 +60,7 @@
SerialUsbDriver,
build_rear_panel_driver,
)
from opentrons_hardware.drivers.eeprom import EEPROMDriver, EEPROMData
from opentrons_hardware.hardware_control.move_group_runner import MoveGroupRunner
from opentrons_hardware.hardware_control.motion_planning import (
Move,
Expand Down Expand Up @@ -220,6 +223,7 @@ def __init__(
config: OT3Config,
driver: AbstractCanDriver,
usb_driver: Optional[SerialUsbDriver] = None,
eeprom_driver: Optional[EEPROMDriver] = None,
check_updates: bool = True,
) -> None:
"""Construct.
Expand All @@ -232,7 +236,11 @@ def __init__(
self._module_controls: Optional[AttachedModulesControl] = None
self._messenger = CanMessenger(driver=driver)
self._messenger.start()
self._gpio_dev, self._usb_messenger = self._build_system_hardware(usb_driver)
self._drivers = self._build_system_hardware(
self._messenger, usb_driver, eeprom_driver
)
self._usb_messenger = self._drivers.usb_messenger
self._gpio_dev = self._drivers.gpio_dev
self._subsystem_manager = SubsystemManager(
self._messenger,
self._usb_messenger,
Expand Down Expand Up @@ -276,20 +284,41 @@ def fw_version(self) -> Dict[SubSystem, int]:
for subsystem, info in self.subsystems.items()
}

@property
def eeprom_driver(self) -> EEPROMDriver:
"""The eeprom driver interface."""
return self._drivers.eeprom

@property
def eeprom_data(self) -> EEPROMData:
"""Get the data on the eeprom."""
return self._drivers.eeprom.data

@property
def update_required(self) -> bool:
return self._subsystem_manager.update_required and self._check_updates

@staticmethod
def _build_system_hardware(
can_messenger: CanMessenger,
usb_driver: Optional[SerialUsbDriver],
) -> Tuple[Union[OT3GPIO, RemoteOT3GPIO], Optional[BinaryMessenger]]:
if usb_driver is None:
return OT3GPIO("hardware_control"), None
else:
eeprom_driver: Optional[EEPROMDriver],
) -> SystemDrivers:
gpio = OT3GPIO("hardware_control")
eeprom_driver = eeprom_driver or EEPROMDriver(gpio)
eeprom_driver.setup()
gpio_dev: Union[OT3GPIO, RemoteOT3GPIO] = gpio
usb_messenger: Optional[BinaryMessenger] = None
if usb_driver:
usb_messenger = BinaryMessenger(usb_driver)
usb_messenger.start()
return RemoteOT3GPIO(usb_messenger), usb_messenger
gpio_dev = RemoteOT3GPIO(usb_messenger)
return SystemDrivers(
can_messenger,
gpio_dev,
eeprom_driver,
usb_messenger=usb_messenger,
)

def _motor_nodes(self) -> Set[NodeId]:
"""Get a list of the motor controller nodes of all attached and ok devices."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
Move,
Coordinates,
)

from opentrons_hardware.drivers.eeprom import EEPROMData
from opentrons.hardware_control.module_control import AttachedModulesControl
from opentrons.hardware_control import modules
from opentrons.hardware_control.types import (
Expand Down Expand Up @@ -197,6 +197,10 @@ def initialized(self) -> bool:
def initialized(self, value: bool) -> None:
self._initialized = value

@property
def eeprom_data(self) -> EEPROMData:
return EEPROMData()

@property
def board_revision(self) -> BoardRevision:
"""Get the board revision"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
target_to_subsystem,
)
from opentrons.hardware_control.backends.subsystem_manager import SubsystemManager
from opentrons_hardware.drivers.eeprom import EEPROMDriver
from opentrons_hardware.drivers.can_bus.can_messenger import (
MessageListenerCallback,
MessageListenerCallbackFilter,
Expand Down Expand Up @@ -128,12 +129,22 @@ def mock_usb_driver() -> SerialUsbDriver:
return mock.AsyncMock(spec=SerialUsbDriver)


@pytest.fixture
def mock_eeprom_driver() -> EEPROMDriver:
"""Mock eeprom driver."""
return mock.Mock(spec=EEPROMDriver)


@pytest.fixture
def controller(
mock_config: OT3Config, mock_can_driver: AbstractCanDriver
mock_config: OT3Config,
mock_can_driver: AbstractCanDriver,
mock_eeprom_driver: EEPROMDriver,
) -> Iterator[OT3Controller]:
with mock.patch("opentrons.hardware_control.backends.ot3controller.OT3GPIO"):
yield OT3Controller(mock_config, mock_can_driver)
with (mock.patch("opentrons.hardware_control.backends.ot3controller.OT3GPIO")):
yield OT3Controller(
mock_config, mock_can_driver, eeprom_driver=mock_eeprom_driver
)


@pytest.fixture
Expand Down
34 changes: 34 additions & 0 deletions hardware/opentrons_hardware/drivers/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,35 @@
"""Drivers package."""

from typing import Optional, Union

from .can_bus import CanMessenger
from .binary_usb import BinaryMessenger
from .gpio import OT3GPIO, RemoteOT3GPIO
from .eeprom import EEPROMDriver


class SystemDrivers:
"""Holder class for hardware drivers."""

def __init__(
self,
can_messenger: CanMessenger,
gpio_dev: Union[OT3GPIO, RemoteOT3GPIO],
eeprom: EEPROMDriver,
usb_messenger: Optional[BinaryMessenger] = None,
) -> None:
"""Constructor"""
self.can_messenger: CanMessenger = can_messenger
self.usb_messenger: Optional[BinaryMessenger] = usb_messenger
self.gpio_dev: Union[OT3GPIO, RemoteOT3GPIO] = gpio_dev
self.eeprom: EEPROMDriver = eeprom


__all__ = [
"SystemDrivers",
"CanMessenger",
"BinaryMessenger",
"EEPROMDriver",
"OT3GPIO",
"RemoteOT3GPIO",
]
29 changes: 29 additions & 0 deletions hardware/opentrons_hardware/drivers/eeprom/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""The eeprom interface package."""

from .eeprom import (
EEPROMDriver,
DEFAULT_BUS,
DEFAULT_ADDRESS,
DEFAULT_READ_SIZE,
)

from .types import (
PropId,
PropType,
Property,
EEPROMData,
FORMAT_VERSION,
)


__all__ = [
"PropId",
"PropType",
"Property",
"EEPROMData",
"EEPROMDriver",
"DEFAULT_BUS",
"DEFAULT_ADDRESS",
"DEFAULT_READ_SIZE",
"FORMAT_VERSION",
]
34 changes: 34 additions & 0 deletions hardware/opentrons_hardware/drivers/eeprom/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Factory for building the eeprom driver."""

from typing import Optional, Iterator
from pathlib import Path
from contextlib import contextmanager

from ..gpio import OT3GPIO
from .eeprom import (
EEPROMDriver,
)


DEFAULT_EEPROM_PATH = Path("/sys/bus/i2c/devices/3-0050/eeprom")


def build_eeprom_driver(
gpio: Optional[OT3GPIO] = None, eeprom_path: Optional[Path] = None
) -> EEPROMDriver:
"""Create an instance of the eeprom driver"""
gpio = gpio or OT3GPIO("eeprom_hardware_controller")
eeprom_path = eeprom_path or DEFAULT_EEPROM_PATH
eeprom_driver = EEPROMDriver(gpio, eeprom_path=eeprom_path)
eeprom_driver.setup()
return eeprom_driver


@contextmanager
def eeprom_driver() -> Iterator[EEPROMDriver]:
"""Context manager creating an eeprom driver."""
d = build_eeprom_driver()
try:
yield d
finally:
d.__exit__()
Loading