Exemple #1
0
def _checkTimeValue( timevalue, maxvalue ):   
    """Check that the given timevalue is valid.
    
    Args:
        * timevalue (numerical): The time value to be checked. Must be positive.
        * maxvalue (numerical): Upper limit for time value. Must be positive.
        
    Raises:
        TypeError, ValueError
    
    """
    if maxvalue is None:
        raise TypeError('The maxvalue (for the time value) must not be None!')
    minimalmodbus._checkNumerical(timevalue, minvalue=0, maxvalue=maxvalue, description='time value')     
Exemple #2
0
def _checkValue(value, minvalue, maxvalue, description):
    """Check that the given value is valid.
    
    Args:
        * value (numerical): The value value to be checked. Must be positive.
        * maxvalue (numerical): Upper limit for value value. Must be positive.
        
    Raises:
        TypeError, ValueError
    
    """
    if maxvalue is None:
        raise TypeError(
            'The maxvalue (for the {}) must not be None!'.format(description))
    minimalmodbus._checkNumerical(value, minvalue, maxvalue, description)
Exemple #3
0
def _checkTimeValue(timevalue, maxvalue):
    """Check that the given timevalue is valid.
    
    Args:
        * timevalue (numerical): The time value to be checked. Must be positive.
        * maxvalue (numerical): Upper limit for time value. Must be positive.
        
    Raises:
        TypeError, ValueError
    
    """
    if maxvalue is None:
        raise TypeError('The maxvalue (for the time value) must not be None!')
    minimalmodbus._checkNumerical(timevalue,
                                  minvalue=0,
                                  maxvalue=maxvalue,
                                  description='time value')
Exemple #4
0
    def _genericCommand(self, functioncode, registeraddress, value=None, \
            numberOfDecimals=0, numberOfRegisters=1, signed=False, payloadformat=None):
        """Generic command for reading and writing registers and bits.
        Args:
            * functioncode (int): Modbus function code.
            * registeraddress (int): The register address  (use decimal numbers, not hex).
            * value (numerical or string or None or list of int): The value to store in the register. Depends on payloadformat.
            * numberOfDecimals (int): The number of decimals for content conversion. Only for a single register.
            * numberOfRegisters (int): The number of registers to read/write. Only certain values allowed, depends on payloadformat.
            * signed (bool): Whether the data should be interpreted as unsigned or signed. Only for a single register or for payloadformat='long'.
            * payloadformat (None or string): None, 'long', 'float', 'string', 'register', 'registers'. Not necessary for single registers or bits.
        If a value of 77.0 is stored internally in the slave register as 770,
        then use ``numberOfDecimals=1`` which will divide the received data from the slave by 10
        before returning the value. Similarly ``numberOfDecimals=2`` will divide
        the received data by 100 before returning the value. Same functionality is also used
        when writing data to the slave.
        Returns:
            The register data in numerical value (int or float), or the bit value 0 or 1 (int), or ``None``.
        Raises:
            ValueError, TypeError, IOError
        """
        NUMBER_OF_BITS = 1
        NUMBER_OF_BYTES_FOR_ONE_BIT = 1
        NUMBER_OF_BYTES_BEFORE_REGISTERDATA = 1
        ALL_ALLOWED_FUNCTIONCODES = list(range(
            1, 7)) + [15, 16] + [22]  # To comply with both Python2 and Python3
        MAX_NUMBER_OF_REGISTERS = 255

        # Payload format constants, so datatypes can be told apart.
        # Note that bit datatype not is included, because it uses other functioncodes.
        PAYLOADFORMAT_LONG = 'long'
        PAYLOADFORMAT_FLOAT = 'float'
        PAYLOADFORMAT_STRING = 'string'
        PAYLOADFORMAT_REGISTER = 'register'
        PAYLOADFORMAT_REGISTERS = 'registers'

        ALL_PAYLOADFORMATS = [PAYLOADFORMAT_LONG, PAYLOADFORMAT_FLOAT, \
            PAYLOADFORMAT_STRING, PAYLOADFORMAT_REGISTER, PAYLOADFORMAT_REGISTERS]

        ## Check input values ##
        minimalmodbus._checkFunctioncode(
            functioncode, ALL_ALLOWED_FUNCTIONCODES
        )  # Note: The calling facade functions should validate this
        minimalmodbus._checkRegisteraddress(registeraddress)
        minimalmodbus._checkInt(numberOfDecimals,
                                minvalue=0,
                                description='number of decimals')
        minimalmodbus._checkInt(numberOfRegisters,
                                minvalue=1,
                                maxvalue=MAX_NUMBER_OF_REGISTERS,
                                description='number of registers')
        minimalmodbus._checkBool(signed, description='signed')

        if payloadformat is not None:
            if payloadformat not in ALL_PAYLOADFORMATS:
                raise ValueError(
                    'Wrong payload format variable. Given: {0!r}'.format(
                        payloadformat))

        ## Check combinations of input parameters ##
        numberOfRegisterBytes = numberOfRegisters * _NUMBER_OF_BYTES_PER_REGISTER

        # Payload format
        if functioncode in [3, 4, 6, 16] and payloadformat is None:
            payloadformat = PAYLOADFORMAT_REGISTER

        if functioncode in [3, 4, 6, 16]:
            if payloadformat not in ALL_PAYLOADFORMATS:
                raise ValueError('The payload format is unknown. Given format: {0!r}, functioncode: {1!r}.'.\
                    format(payloadformat, functioncode))
        else:
            if payloadformat is not None:
                raise ValueError('The payload format given is not allowed for this function code. ' + \
                    'Given format: {0!r}, functioncode: {1!r}.'.format(payloadformat, functioncode))

                # Signed and numberOfDecimals
        if signed:
            if payloadformat not in [
                    PAYLOADFORMAT_REGISTER, PAYLOADFORMAT_LONG
            ]:
                raise ValueError('The "signed" parameter can not be used for this data format. ' + \
                    'Given format: {0!r}.'.format(payloadformat))

        if numberOfDecimals > 0 and payloadformat != PAYLOADFORMAT_REGISTER:
            raise ValueError('The "numberOfDecimals" parameter can not be used for this data format. ' + \
                'Given format: {0!r}.'.format(payloadformat))

            # Number of registers
        if functioncode not in [3, 4, 16] and numberOfRegisters != 1:
            raise ValueError('The numberOfRegisters is not valid for this function code. ' + \
                'NumberOfRegisters: {0!r}, functioncode {1}.'.format(numberOfRegisters, functioncode))

        if functioncode == 16 and payloadformat == PAYLOADFORMAT_REGISTER and numberOfRegisters != 1:
            raise ValueError('Wrong numberOfRegisters when writing to a ' + \
                'single register. Given {0!r}.'.format(numberOfRegisters))
            # Note: For function code 16 there is checking also in the content conversion functions.

            # Value
        if functioncode in [5, 6, 15, 16, 22] and value is None:
            raise ValueError('The input value is not valid for this function code. ' + \
                'Given {0!r} and {1}.'.format(value, functioncode))

        if functioncode == 16 and payloadformat in [
                PAYLOADFORMAT_REGISTER, PAYLOADFORMAT_FLOAT, PAYLOADFORMAT_LONG
        ]:
            minimalmodbus._checkNumerical(value, description='input value')

        if functioncode == 6 and payloadformat == PAYLOADFORMAT_REGISTER:
            minimalmodbus._checkNumerical(value, description='input value')

            # Value for string
        if functioncode == 16 and payloadformat == PAYLOADFORMAT_STRING:
            minimalmodbus._checkString(value,
                                       'input string',
                                       minlength=1,
                                       maxlength=numberOfRegisterBytes)
            # Note: The string might be padded later, so the length might be shorter than numberOfRegisterBytes.

            # Value for registers
        if functioncode == 16 and payloadformat == PAYLOADFORMAT_REGISTERS:
            if not isinstance(value, list):
                raise TypeError(
                    'The value parameter must be a list. Given {0!r}.'.format(
                        value))

            if len(value) != numberOfRegisters:
                raise ValueError('The list length does not match number of registers. ' + \
                    'List: {0!r},  Number of registers: {1!r}.'.format(value, numberOfRegisters))

        ## Build payload to slave ##
        if functioncode in [1, 2]:
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._numToTwoByteString(NUMBER_OF_BITS)

        elif functioncode in [3, 4]:
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._numToTwoByteString(numberOfRegisters)

        elif functioncode == 5:
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._createBitpattern(functioncode, value)

        elif functioncode == 6:
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._numToTwoByteString(value, numberOfDecimals, signed=signed)

        elif functioncode == 15:
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._numToTwoByteString(NUMBER_OF_BITS) + \
                            minimalmodbus._numToOneByteString(NUMBER_OF_BYTES_FOR_ONE_BIT) + \
                            minimalmodbus._createBitpattern(functioncode, value)

        elif functioncode == 16:
            if payloadformat == PAYLOADFORMAT_REGISTER:
                registerdata = minimalmodbus._numToTwoByteString(
                    value, numberOfDecimals, signed=signed)

            elif payloadformat == PAYLOADFORMAT_STRING:
                registerdata = minimalmodbus._textstringToBytestring(
                    value, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_LONG:
                registerdata = minimalmodbus._longToBytestring(
                    value, signed, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_FLOAT:
                registerdata = minimalmodbus._floatToBytestring(
                    value, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_REGISTERS:
                registerdata = minimalmodbus._valuelistToBytestring(
                    value, numberOfRegisters)

            assert len(registerdata) == numberOfRegisterBytes
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            minimalmodbus._numToTwoByteString(numberOfRegisters) + \
                            minimalmodbus._numToOneByteString(numberOfRegisterBytes) + \
                            registerdata
        elif functioncode == 22:
            registerdata = minimalmodbus._valuelistToBytestring(value, 2)
            payloadToSlave = minimalmodbus._numToTwoByteString(registeraddress) + \
                            registerdata
        ## Communicate ##
        payloadFromSlave = self._performCommand(functioncode, payloadToSlave)

        ## Check the contents in the response payload ##
        if functioncode in [1, 2, 3, 4]:
            minimalmodbus._checkResponseByteCount(
                payloadFromSlave)  # response byte count

        if functioncode in [5, 6, 15, 16]:
            minimalmodbus._checkResponseRegisterAddress(
                payloadFromSlave, registeraddress)  # response register address

        if functioncode == 5:
            minimalmodbus._checkResponseWriteData(
                payloadFromSlave,
                minimalmodbus._createBitpattern(functioncode,
                                                value))  # response write data

        if functioncode == 6:
            minimalmodbus._checkResponseWriteData(payloadFromSlave, \
                minimalmodbus._numToTwoByteString(value, numberOfDecimals, signed=signed))  # response write data

        if functioncode == 15:
            minimalmodbus._checkResponseNumberOfRegisters(
                payloadFromSlave, NUMBER_OF_BITS)  # response number of bits

        if functioncode == 16:
            minimalmodbus._checkResponseNumberOfRegisters(
                payloadFromSlave,
                numberOfRegisters)  # response number of registers

        ## Calculate return value ##
        if functioncode in [1, 2]:
            registerdata = payloadFromSlave[
                NUMBER_OF_BYTES_BEFORE_REGISTERDATA:]
            if len(registerdata) != NUMBER_OF_BYTES_FOR_ONE_BIT:
                raise ValueError('The registerdata length does not match NUMBER_OF_BYTES_FOR_ONE_BIT. ' + \
                    'Given {0}.'.format(len(registerdata)))

            return minimalmodbus._bitResponseToValue(registerdata)

        if functioncode in [3, 4]:
            registerdata = payloadFromSlave[
                NUMBER_OF_BYTES_BEFORE_REGISTERDATA:]
            if len(registerdata) != numberOfRegisterBytes:
                raise ValueError('The registerdata length does not match number of register bytes. ' + \
                    'Given {0!r} and {1!r}.'.format(len(registerdata), numberOfRegisterBytes))

            if payloadformat == PAYLOADFORMAT_STRING:
                return minimalmodbus._bytestringToTextstring(
                    registerdata, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_LONG:
                return minimalmodbus._bytestringToLong(registerdata, signed,
                                                       numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_FLOAT:
                return minimalmodbus._bytestringToFloat(
                    registerdata, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_REGISTERS:
                return minimalmodbus._bytestringToValuelist(
                    registerdata, numberOfRegisters)

            elif payloadformat == PAYLOADFORMAT_REGISTER:
                return minimalmodbus._twoByteStringToNum(registerdata,
                                                         numberOfDecimals,
                                                         signed=signed)

            raise ValueError('Wrong payloadformat for return value generation. ' + \
                'Given {0}'.format(payloadformat))

        if functioncode == 22:
            registerdata = payloadFromSlave[
                NUMBER_OF_BYTES_BEFORE_REGISTERDATA:]
            return ("OK")