docs: 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]  # 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 ##
          _checkFunctioncode(functioncode, ALL_ALLOWED_FUNCTIONCODES)  # Note: The calling facade functions should validate this
          _checkRegisteraddress(registeraddress)
          _checkInt(numberOfDecimals, minvalue=0, description='number of decimals')
          _checkInt(numberOfRegisters, minvalue=1, maxvalue=MAX_NUMBER_OF_REGISTERS, description='number of registers')
          _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] 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]:
              _checkNumerical(value, description='input value')
  
          if functioncode == 6 and payloadformat == PAYLOADFORMAT_REGISTER:
              _checkNumerical(value, description='input value')
  
                      # Value for string
          if functioncode == 16 and payloadformat == PAYLOADFORMAT_STRING:
              _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 = _numToTwoByteString(registeraddress) + \
                              _numToTwoByteString(NUMBER_OF_BITS)
  
          elif functioncode in [3, 4]:
              payloadToSlave = _numToTwoByteString(registeraddress) + \
                              _numToTwoByteString(numberOfRegisters)
  
          elif functioncode == 5:
              payloadToSlave = _numToTwoByteString(registeraddress) + \
                              _createBitpattern(functioncode, value)
  
          elif functioncode == 6:
              payloadToSlave = _numToTwoByteString(registeraddress) + \
                              _numToTwoByteString(value, numberOfDecimals, signed=signed)
  
          elif functioncode == 15:
              payloadToSlave = _numToTwoByteString(registeraddress) + \
                              _numToTwoByteString(NUMBER_OF_BITS) + \
                              _numToOneByteString(NUMBER_OF_BYTES_FOR_ONE_BIT) + \
                              _createBitpattern(functioncode, value)
  
          elif functioncode == 16:
              if payloadformat == PAYLOADFORMAT_REGISTER:
                  registerdata = _numToTwoByteString(value, numberOfDecimals, signed=signed)
  
              elif payloadformat == PAYLOADFORMAT_STRING:
                  registerdata = _textstringToBytestring(value, numberOfRegisters)
  
              elif payloadformat == PAYLOADFORMAT_LONG:
                  registerdata = _longToBytestring(value, signed, numberOfRegisters)
  
              elif payloadformat == PAYLOADFORMAT_FLOAT:
                  registerdata = _floatToBytestring(value, numberOfRegisters)
  
              elif payloadformat == PAYLOADFORMAT_REGISTERS:
                  registerdata = _valuelistToBytestring(value, numberOfRegisters)
  
              assert len(registerdata) == numberOfRegisterBytes
              payloadToSlave = _numToTwoByteString(registeraddress) + \
                              _numToTwoByteString(numberOfRegisters) + \
                              _numToOneByteString(numberOfRegisterBytes) + \
                              registerdata
  
          ## Communicate ##
          payloadFromSlave = self._performCommand(functioncode, payloadToSlave)
  
          ## Check the contents in the response payload ##
          if functioncode in [1, 2, 3, 4]:
              _checkResponseByteCount(payloadFromSlave)  # response byte count
  
          if functioncode in [5, 6, 15, 16]:
              _checkResponseRegisterAddress(payloadFromSlave, registeraddress)  # response register address
  
          if functioncode == 5:
              _checkResponseWriteData(payloadFromSlave, _createBitpattern(functioncode, value))  # response write data
  
          if functioncode == 6:
              _checkResponseWriteData(payloadFromSlave, \
                  _numToTwoByteString(value, numberOfDecimals, signed=signed))  # response write data
  
          if functioncode == 15:
              _checkResponseNumberOfRegisters(payloadFromSlave, NUMBER_OF_BITS)  # response number of bits
  
          if functioncode == 16:
              _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 _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 _bytestringToTextstring(registerdata, numberOfRegisters)
  
              elif payloadformat == PAYLOADFORMAT_LONG:
                  return _bytestringToLong(registerdata, signed, numberOfRegisters)
  
              elif payloadformat == PAYLOADFORMAT_FLOAT:
                  return _bytestringToFloat(registerdata, numberOfRegisters)
  
              elif payloadformat == PAYLOADFORMAT_REGISTERS:
                  return _bytestringToValuelist(registerdata, numberOfRegisters)
  
              elif payloadformat == PAYLOADFORMAT_REGISTER:
                  return _twoByteStringToNum(registerdata, numberOfDecimals, signed=signed)
  
              raise ValueError('Wrong payloadformat for return value generation. ' + \
                  'Given {0}'.format(payloadformat))