Skip to content

Port type verification #425

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

Draft
wants to merge 17 commits into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions pitop/core/mixins/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .componentable import Componentable
from .digital_component_checks import DigitalComponentChecks
from .recreatable import Recreatable
from .stateful import Stateful
from .supports_battery import SupportsBattery
Expand Down
20 changes: 20 additions & 0 deletions pitop/core/mixins/digital_component_checks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import re


class DigitalComponentChecks:
"""Performs basic checks on validity of user-specified port."""

def __init__(self, port_name):
self.port_name = port_name

# For the sake of a helpful error message, first check if the port is actually a valid port of any kind
if not re.search("^D[0-7]$|^A[0-3]$", self.port_name):
raise ValueError(
f"{self.port_name} is not a valid port name. An example of a valid port name is D0"
)

# Then, in this case, verify the port is digital not analog
if re.search("^A[0-3]$", self.port_name):
raise ValueError(
f"Can't use analog port {self.port_name} for digital component. Try using a digital port, such as D0"
)
2 changes: 1 addition & 1 deletion pitop/core/mixins/recreatable.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class Recreatable:
"""Represents an object that keeps track of a set of parameters that will
allow to be recreate it in the future.
allow it to be recreated in the future.

The values for each key provided in the :param:`config_dict`
parameter can be a constant value or a reference to a function,
Expand Down
13 changes: 13 additions & 0 deletions pitop/pma/adc_base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
import time

from pitop.core.mixins import Recreatable, Stateful
Expand All @@ -22,6 +23,18 @@ def __init__(self, port_name, pin_number=1, name="adcbase"):
self._pma_port = port_name
self.name = name

# For the sake of a helpful error message, first check if the port is actually a valid port of any kind
if not re.search("^D[0-7]$|^A[0-3]$", self._pma_port):
raise ValueError(
f"{self._pma_port} is not a valid port name. An example of a valid port name is A0"
)

# Then, in this case, verify the port is analog not digital
if re.search("^D[0-7]$", self._pma_port):
raise ValueError(
f"Can't use digital port {self._pma_port} for analog component. Try using an analog port, such as A0"
)

self.is_current = False
self.channel = get_pin_for_port(self._pma_port, pin_number)
self.__adc_device = PlateInterface().get_device_mcu()
Expand Down
5 changes: 3 additions & 2 deletions pitop/pma/button.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from gpiozero import Button as gpiozero_Button

from pitop.core.mixins import Recreatable, Stateful
from pitop.core.mixins import DigitalComponentChecks, Recreatable, Stateful
from pitop.pma.common import get_pin_for_port


class Button(Stateful, Recreatable, gpiozero_Button):
class Button(Stateful, Recreatable, DigitalComponentChecks, gpiozero_Button):
"""Encapsulates the behaviour of a push-button.

A push-button is a simple switch mechanism for controlling some aspect of a circuit.
Expand All @@ -18,6 +18,7 @@ def __init__(self, port_name, name="button"):

Stateful.__init__(self)
Recreatable.__init__(self, {"port_name": port_name, "name": self.name})
DigitalComponentChecks.__init__(self, self._pma_port)
gpiozero_Button.__init__(self, get_pin_for_port(self._pma_port))

@property
Expand Down
5 changes: 3 additions & 2 deletions pitop/pma/buzzer.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from gpiozero import Buzzer as gpiozero_Buzzer

from pitop.core.mixins import Recreatable, Stateful
from pitop.core.mixins import DigitalComponentChecks, Recreatable, Stateful
from pitop.pma.common import get_pin_for_port


class Buzzer(Stateful, Recreatable, gpiozero_Buzzer):
class Buzzer(Stateful, Recreatable, DigitalComponentChecks, gpiozero_Buzzer):
"""Encapsulates the behaviour of a simple buzzer that can be turned on and
off.

Expand All @@ -17,6 +17,7 @@ def __init__(self, port_name, name="buzzer"):

Stateful.__init__(self)
Recreatable.__init__(self, {"port_name": port_name, "name": self.name})
DigitalComponentChecks.__init__(self, self._pma_port)
gpiozero_Buzzer.__init__(self, get_pin_for_port(self._pma_port))

@property
Expand Down
2 changes: 1 addition & 1 deletion pitop/pma/encoder_motor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class EncoderMotor(Stateful, Recreatable):

The conversions between angle, rotations and RPM used by the motor to meters and meters/second are performed considering
the :data:`wheel_diameter` parameter. This parameter defaults to the diameter of the wheel included with MMK.
If a wheel of different dimmensions is attached to the motor, you'll need to measure it's diameter, in order for these
If a wheel of different dimensions is attached to the motor, you'll need to measure it's diameter, in order for these
methods to work properly.

:type port_name: str
Expand Down
5 changes: 3 additions & 2 deletions pitop/pma/led.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from gpiozero import LED as gpiozero_LED

from pitop.core.mixins import Recreatable, Stateful
from pitop.core.mixins import DigitalComponentChecks, Recreatable, Stateful
from pitop.pma.common import get_pin_for_port


class LED(Stateful, Recreatable, gpiozero_LED):
class LED(Stateful, Recreatable, DigitalComponentChecks, gpiozero_LED):
"""Encapsulates the behaviour of an LED.

An LED (Light Emitting Diode) is a simple light source that can be controlled directly.
Expand All @@ -18,6 +18,7 @@ def __init__(self, port_name, name="led"):

Stateful.__init__(self)
Recreatable.__init__(self, {"port_name": port_name, "name": self.name})
DigitalComponentChecks.__init__(self, self._pma_port)
gpiozero_LED.__init__(self, get_pin_for_port(self._pma_port))

@property
Expand Down
22 changes: 17 additions & 5 deletions pitop/pma/ultrasonic_sensor.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import re

from pitop.core.mixins import Recreatable, Stateful
from pitop.pma.common.utils import Port

from .ultrasonic_sensor_base import UltrasonicSensorMCU, UltrasonicSensorRPI

valid_analog_ports = ["A1", "A3"]


class UltrasonicSensor(Stateful, Recreatable):
def __init__(
Expand All @@ -17,11 +16,24 @@ def __init__(
name="ultrasonic",
):

assert port_name in Port
self._pma_port = port_name
self.name = name

if port_name in valid_analog_ports:
# For the sake of a helpful error message, first check if the port is actually a valid port of any kind
if not re.search("^D[0-7]$|^A[0-3]$", self._pma_port):
raise ValueError(
f"{self._pma_port} is not a valid port name. An example of a valid port name is D0"
)

# Then, verify it's a valid port for the Ultrasonic sensor specifically
if not re.search("^D[0-7]$|^A1$|^A3$", self._pma_port):
raise ValueError(
f"Can't use port {self._pma_port} for ultrasonic sensor. Try A1, A3 or a digital port "
f"such as D0"
)

# If port name is a valid analog port
if re.search("^A[0-3]$", self._pma_port):
self.__ultrasonic_device = UltrasonicSensorMCU(
port_name=port_name,
queue_len=queue_len,
Expand Down