<gh_stars>0
"""Classes for the SourceBots Arduino."""
from enum import IntEnum
from typing import Mapping, Optional, Set, Tuple, Type, Union, cast

from j5.backends import Backend
from j5.boards import Board
from j5.components import (
    LED,
    Component,
    GPIOPin,
    GPIOPinInterface,
    GPIOPinMode,
    LEDInterface,
)
from j5.components.derived import UltrasoundInterface, UltrasoundSensor


class AnaloguePin(IntEnum):
    """Analogue Pins numbering."""

    A0 = 14
    A1 = 15
    A2 = 16
    A3 = 17
    A4 = 18
    A5 = 19


PinNumber = Union[int, AnaloguePin]


class SBArduinoBoard(Board):
    """SourceBots Arduino Board."""

    _led: LED
    _digital_pins: Mapping[int, GPIOPin]
    _analogue_pins: Mapping[AnaloguePin, GPIOPin]
    name: str = "Arduino Uno"

    def __init__(self, serial: str, backend: Backend):
        self._serial = serial
        self._backend = backend

        self._led = LED(0, cast(LEDInterface, self._backend))

        # Digital Pins
        # Note that pins 0 and 1 are used for serial comms.
        self._digital_pins = {
            i: GPIOPin(
                i,
                cast(GPIOPinInterface, self._backend),
                initial_mode=GPIOPinMode.DIGITAL_INPUT,
                hardware_modes={
                    GPIOPinMode.DIGITAL_INPUT,
                    GPIOPinMode.DIGITAL_INPUT_PULLUP,
                    GPIOPinMode.DIGITAL_OUTPUT,
                },
                firmware_modes={UltrasoundSensor},
            )
            for i in range(2, 14)
        }

        self._analogue_pins = {
            i: GPIOPin(
                i,
                cast(GPIOPinInterface, self._backend),
                initial_mode=GPIOPinMode.ANALOGUE_INPUT,
                hardware_modes={
                    GPIOPinMode.ANALOGUE_INPUT,
                    GPIOPinMode.DIGITAL_INPUT,
                    GPIOPinMode.DIGITAL_INPUT_PULLUP,
                    GPIOPinMode.DIGITAL_OUTPUT,
                },
            )
            for i in AnaloguePin
        }

        self.ultrasound_sensors = UltrasoundSensors(self)

    @property
    def serial(self) -> str:
        """Get the serial number."""
        return self._serial

    @property
    def firmware_version(self) -> Optional[str]:
        """Get the firmware version of the board."""
        return self._backend.firmware_version

    @property
    def pins(self) -> Mapping[PinNumber, GPIOPin]:
        """Get the GPIO pins."""
        pins: Mapping[PinNumber, GPIOPin] = {
            **cast(Mapping[PinNumber, GPIOPin], self._analogue_pins),
            **cast(Mapping[PinNumber, GPIOPin], self._digital_pins),

        }
        return pins

    def make_safe(self) -> None:
        """Make this board safe."""
        pass

    @staticmethod
    def supported_components() -> Set[Type[Component]]:
        """List the types of components supported by this board."""
        return {
            GPIOPin,
            LED,
            UltrasoundSensor,
        }


class UltrasoundSensors:
    """
    Helper class for constructing UltrasoundSensor objects on the fly.

    This exists so that arduino.ultrasound_sensors can be accessed using square bracket
    notation like a mapping, for consistency with how other types of component are
    accessed.
    """

    def __init__(self, arduino: SBArduinoBoard):
        self._arduino = arduino

    def __getitem__(self, key: Tuple[PinNumber, PinNumber]) -> UltrasoundSensor:
        """Get an ultrasound sensor with the given pin configuration."""
        trigger_pin, echo_pin = key
        return UltrasoundSensor(
            gpio_trigger=self._arduino.pins[trigger_pin],
            gpio_echo=self._arduino.pins[echo_pin],
            backend=cast(UltrasoundInterface, self._arduino._backend),
        )

"""Classes for the SourceBots Arduino."""
from enum import IntEnum
from typing import Mapping, Optional, Set, Tuple, Type, Union, cast

from j5.backends import Backend
from j5.boards import Board
from j5.components import (
    LED,
    Component,
    GPIOPin,
    GPIOPinInterface,
    GPIOPinMode,
    LEDInterface,
)
from j5.components.derived import UltrasoundInterface, UltrasoundSensor


class AnaloguePin(IntEnum):
    """Analogue Pins numbering."""

    A0 = 14
    A1 = 15
    A2 = 16
    A3 = 17
    A4 = 18
    A5 = 19


PinNumber = Union[int, AnaloguePin]


class SBArduinoBoard(Board):
    """SourceBots Arduino Board."""

    _led: LED
    _digital_pins: Mapping[int, GPIOPin]
    _analogue_pins: Mapping[AnaloguePin, GPIOPin]
    name: str = "Arduino Uno"

    def __init__(self, serial: str, backend: Backend):
        self._serial = serial
        self._backend = backend

        self._led = LED(0, cast(LEDInterface, self._backend))

        # Digital Pins
        # Note that pins 0 and 1 are used for serial comms.
        self._digital_pins = {
            i: GPIOPin(
                i,
                cast(GPIOPinInterface, self._backend),
                initial_mode=GPIOPinMode.DIGITAL_INPUT,
                hardware_modes={
                    GPIOPinMode.DIGITAL_INPUT,
                    GPIOPinMode.DIGITAL_INPUT_PULLUP,
                    GPIOPinMode.DIGITAL_OUTPUT,
                },
                firmware_modes={UltrasoundSensor},
            )
            for i in range(2, 14)
        }

        self._analogue_pins = {
            i: GPIOPin(
                i,
                cast(GPIOPinInterface, self._backend),
                initial_mode=GPIOPinMode.ANALOGUE_INPUT,
                hardware_modes={
                    GPIOPinMode.ANALOGUE_INPUT,
                    GPIOPinMode.DIGITAL_INPUT,
                    GPIOPinMode.DIGITAL_INPUT_PULLUP,
                    GPIOPinMode.DIGITAL_OUTPUT,
                },
            )
            for i in AnaloguePin
        }

        self.ultrasound_sensors = UltrasoundSensors(self)

    @property
    def serial(self) -> str:
        """Get the serial number."""
        return self._serial

    @property
    def firmware_version(self) -> Optional[str]:
        """Get the firmware version of the board."""
        return self._backend.firmware_version

    @property
    def pins(self) -> Mapping[PinNumber, GPIOPin]:
        """Get the GPIO pins."""
        pins: Mapping[PinNumber, GPIOPin] = {
            **cast(Mapping[PinNumber, GPIOPin], self._analogue_pins),
            **cast(Mapping[PinNumber, GPIOPin], self._digital_pins),

        }
        return pins

    def make_safe(self) -> None:
        """Make this board safe."""
        pass

    @staticmethod
    def supported_components() -> Set[Type[Component]]:
        """List the types of components supported by this board."""
        return {
            GPIOPin,
            LED,
            UltrasoundSensor,
        }


class UltrasoundSensors:
    """
    Helper class for constructing UltrasoundSensor objects on the fly.

    This exists so that arduino.ultrasound_sensors can be accessed using square bracket
    notation like a mapping, for consistency with how other types of component are
    accessed.
    """

    def __init__(self, arduino: SBArduinoBoard):
        self._arduino = arduino

    def __getitem__(self, key: Tuple[PinNumber, PinNumber]) -> UltrasoundSensor:
        """Get an ultrasound sensor with the given pin configuration."""
        trigger_pin, echo_pin = key
        return UltrasoundSensor(
            gpio_trigger=self._arduino.pins[trigger_pin],
            gpio_echo=self._arduino.pins[echo_pin],
            backend=cast(UltrasoundInterface, self._arduino._backend),
        )
Classes for the SourceBots Arduino. Analogue Pins numbering. SourceBots Arduino Board. # Digital Pins # Note that pins 0 and 1 are used for serial comms. Get the serial number. Get the firmware version of the board. Get the GPIO pins. Make this board safe. List the types of components supported by this board. Helper class for constructing UltrasoundSensor objects on the fly.      This exists so that arduino.ultrasound_sensors can be accessed using square bracket     notation like a mapping, for consistency with how other types of component are     accessed. Get an ultrasound sensor with the given pin configuration.