Skip to content

File encoder.py#

File List > build > lib.linux-armv7l-cpython-311 > pypisoundmicro > encoder.py

Go to the documentation of this file

from ._utils import copy_doc
from .swig import pypisoundmicro as psm
from typing import Self, Type, Tuple, Optional, Literal, Union, overload
from .types import Pin, Range, PinPull, ValueMode
from . import Element, ElementName

class EncoderOpts:
    """
    Wrapper for encoder options.

    This class provides an interface for working with encoder
    options for configuring input and value ranges and value mode.
    """

    def __init__(self, input_range: Range=None, value_range: Range=None, value_mode: int=ValueMode.WRAP) -> None:
        """
        Initialize EncoderOpts with input range, value range, and value mode.

        Args:
            input_range: Range object for input values
            value_range: Range object for output values
            value_mode: Mode for handling values out of range (CLAMP or WRAP)
        """
        self._opts = psm.upisnd_encoder_opts_t()
        if input_range is None:
            input_range = Range(0, 100)
        if value_range is None:
            value_range = Range(0, 100)
        self.input_rangeinput_rangeinput_rangeinput_rangeinput_range = input_range
        self.value_rangevalue_rangevalue_rangevalue_rangevalue_range = value_range
        self.value_modevalue_modevalue_modevalue_modevalue_mode = value_mode

    @property
    def input_range(self) -> Range:
        """Get the current input range."""
        return Range(self._opts.input_range.low, self._opts.input_range.high)

    @input_range.setter
    def input_range(self, value: Range) -> None:
        """Set the input range."""
        self._opts.input_range.low = value.low
        self._opts.input_range.high = value.high

    @property
    def value_range(self) -> Range:
        """Get the current value range."""
        return Range(self._opts.value_range.low, self._opts.value_range.high)

    @value_range.setter
    def value_range(self, value: Range) -> None:
        """Set the value range."""
        self._opts.value_range.low = value.low
        self._opts.value_range.high = value.high

    @property
    def value_mode(self) -> int:
        """Get the current value mode."""
        return self._opts.value_mode

    @value_mode.setter
    def value_mode(self, mode: int) -> None:
        """Set the value mode."""
        self._opts.value_mode = mode

    @classmethod
    def from_c_opts(cls, opts: psm.upisnd_encoder_opts_t) -> Self:
        """Create EncoderOpts from a C struct."""
        result = cls()
        result._opts = opts
        return result

    def to_c_opts(self) -> psm.upisnd_encoder_opts_t:
        """Convert to C struct."""
        return self._opts

@copy_doc(psm.Encoder)
class Encoder(Element):

    @classmethod
    def setup(cls: Type[Self], name: Union[str, ElementName, psm.ElementName], pin_a: Pin, pull_a: PinPull, pin_b: Pin, pull_b: PinPull) -> Self:
        """
        Set up an encoder element.
        See also: ::upisnd_setup_encoder
        """
        if isinstance(name, str):
            name = psm.ElementName.regular(name)
        elif isinstance(name, ElementName):
            name = name._name
        native_obj = psm.Encoder.setup(name, pin_a, pull_a, pin_b, pull_b)
        return cls(native_obj)

    def get_value(self) -> int:
        """
        This is for quick access to the value, otherwise, it's recommended to keep the

        ValueFd returned by Element::openValueFd, to avoid file open and close overhead.
        Inspect the `errno` to check for errors.
        """
        return self._native_obj.get()

    def set_opts(self, opts: EncoderOpts) -> int:
        """ Sets the Encoder options. See also: ::upisnd_element_encoder_set_opts"""
        return self._native_obj.setOpts(opts.to_c_opts())

    def get_opts(self) -> EncoderOpts:
        """ Retrieves the Encoder options. See also: ::upisnd_element_encoder_get_opts"""
        c_opts = psm.upisnd_encoder_opts_t()
        result = self._native_obj.getOpts(c_opts)
        if result != 0:
            raise IOError(f'Failed to get encoder options: {result}')
        return EncoderOpts.from_c_opts(c_opts)

    def get_pin_b(self) -> Pin:
        """ Retrieves the 2nd pin of the Encoder. See also: ::upisnd_element_encoder_get_pin_b"""
        return self._native_obj.getPinB()

    def get_pin_pull(self) -> PinPull:
        """ Retrieves the pull-up/pull-down configuration of the 1st pin of the Encoder. See also: ::upisnd_element_gpio_get_pull"""
        return self._native_obj.getPinPull()

    def get_pin_b_pull(self) -> PinPull:
        """ Retrieves the pull-up/pull-down configuration of the 2nd pin of the Encoder. See also: ::upisnd_element_encoder_get_pin_b_pull"""
        return self._native_obj.getPinBPull()