Source code for sensirion_shdlc_driver.command

# -*- coding: utf-8 -*-
# (c) Copyright 2019 Sensirion AG, Switzerland

from __future__ import absolute_import, division, print_function
from .errors import ShdlcResponseError

import logging
log = logging.getLogger(__name__)


class ShdlcCommand(object):
    """
    Base class for all SHDLC commands.
    """

    def __init__(self, id, data, max_response_time,
                 min_response_length=0, max_response_length=255,
                 post_processing_time=0.0):
        """
        Constructor.

        :param byte id:  Command ID (0..255).
        :param bytes-like/list data: MOSI data (0..255 bytes).
        :param float max_response_time: Maximum time the device needs to
                                        response (used as timeout).
        :param byte min_response_length: Minimum expected response length.
        :param byte max_response_length: Maximum expected response length.
        :param float post_processing_time: Maximum time in seconds the device
                                           needs for post processing
                                           (typically 0.0s).
        """
        super(ShdlcCommand, self).__init__()
        self._id = id
        self._data = bytes(bytearray(data))  # Allow arbitrary iterables
        self._max_response_time = max_response_time
        self._min_rx_len = min_response_length
        self._max_rx_len = max_response_length
        self._post_processing_time = post_processing_time

    @property
    def id(self):
        """
        Get the command ID.

        :return: Command ID (0..255).
        :rtype: byte
        """
        return self._id

    @property
    def data(self):
        """
        Get the command data (payload).

        :return: Command data (length 0..255).
        :rtype: bytes
        """
        return self._data

    @property
    def max_response_time(self):
        """
        Get the maximum response time for this command.

        :return: Maximum response time in seconds.
        :rtype: float
        """
        return self._max_response_time

    @property
    def post_processing_time(self):
        """
        Get the post processing time for this command. The post processing time
        defines how long a device needs to execute a command *after* responding
        to the SHDLC command. Most devices don't need post processing (command
        is executed *before* the response is sent). Only special commands (e.g.
        a device reset) are executed after the response is sent.

        :return: Maximum response time in seconds.
        :rtype: float
        """
        return self._post_processing_time

    def check_response_length(self, data):
        """
        Check if the response length is correct.

        :param bytes data: Raw data (payload) received from the device.
        :raise ~sensirion_shdlc_driver.errors.ShdlcResponseError:
            If length is wrong.
        """
        if not (self._min_rx_len <= len(data) <= self._max_rx_len):
            raise ShdlcResponseError(
                "Wrong response length (expected {}..{} bytes, got {})."
                .format(self._min_rx_len, self._max_rx_len, len(data)), data)

    def interpret_response(self, data):
        """
        Interpret the response to this command received from the device. This
        converts the raw byte array to the actual data type(s) depending on the
        sent command.

        :param bytes data: Raw data (payload) received from the device.
        :return: Interpreted response. Data type and meaning depends on the
                 sent command. None for commands without response data. See the
                 actual command implementation for details.
        """
        return data if len(data) > 0 else None