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')
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)
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')
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")