docs: def _extractPayload(response, slaveaddress, mode, functioncode):
      """Extract the payload data part from the slave's response.
  
      Args:
          * response (str): The raw response byte string from the slave.
          * slaveaddress (int): The adress of the slave. Used here for error checking only.
          * mode (str): The modbus protcol mode (MODE_RTU or MODE_ASCII)
          * functioncode (int): Used here for error checking only.
  
      Returns:
          The payload part of the *response* string.
  
      Raises:
          ValueError, TypeError. Raises an exception if there is any problem with the received address, the functioncode or the CRC.
  
      The received response should have the format:
      * RTU Mode: slaveaddress byte + functioncode byte + payloaddata + CRC (which is two bytes)
      * ASCII Mode: header (:) + slaveaddress byte + functioncode byte + payloaddata + LRC (which is two characters) + footer (CRLF)
  
      For development purposes, this function can also be used to extract the payload from the request sent TO the slave.
  
      """
      BYTEPOSITION_FOR_ASCII_HEADER          = 0  # Relative to plain response
  
      BYTEPOSITION_FOR_SLAVEADDRESS          = 0  # Relative to (stripped) response
      BYTEPOSITION_FOR_FUNCTIONCODE          = 1
  
      NUMBER_OF_RESPONSE_STARTBYTES          = 2  # Number of bytes before the response payload (in stripped response)
      NUMBER_OF_CRC_BYTES                    = 2
      NUMBER_OF_LRC_BYTES                    = 1
      BITNUMBER_FUNCTIONCODE_ERRORINDICATION = 7
  
      MINIMAL_RESPONSE_LENGTH_RTU            = NUMBER_OF_RESPONSE_STARTBYTES + NUMBER_OF_CRC_BYTES
      MINIMAL_RESPONSE_LENGTH_ASCII          = 9
  
      # Argument validity testing
      _checkString(response, description='response')
      _checkSlaveaddress(slaveaddress)
      _checkMode(mode)
      _checkFunctioncode(functioncode, None)
  
      plainresponse = response
  
      # Validate response length
      if mode == MODE_ASCII:
          if len(response) < MINIMAL_RESPONSE_LENGTH_ASCII:
              raise ValueError('Too short Modbus ASCII response (minimum length {} bytes). Response: {!r}'.format( \
                  MINIMAL_RESPONSE_LENGTH_ASCII,
                  response))
      elif len(response) < MINIMAL_RESPONSE_LENGTH_RTU:
              raise ValueError('Too short Modbus RTU response (minimum length {} bytes). Response: {!r}'.format( \
                  MINIMAL_RESPONSE_LENGTH_RTU,
                  response))
  
      # Validate the ASCII header and footer.
      if mode == MODE_ASCII:
          if response[BYTEPOSITION_FOR_ASCII_HEADER] != _ASCII_HEADER:
              raise ValueError('Did not find header ({!r}) as start of ASCII response. The plain response is: {!r}'.format( \
                  _ASCII_HEADER,
                  response))
          elif response[-len(_ASCII_FOOTER):] != _ASCII_FOOTER:
              raise ValueError('Did not find footer ({!r}) as end of ASCII response. The plain response is: {!r}'.format( \
                  _ASCII_FOOTER,
                  response))
  
          # Strip ASCII header and footer
          response = response[1:-2]
  
          if len(response) % 2 != 0:
              template = 'Stripped ASCII frames should have an even number of bytes, but is {} bytes. ' + \
                      'The stripped response is: {!r} (plain response: {!r})'
              raise ValueError(template.format(len(response), response, plainresponse))
  
          # Convert the ASCII (stripped) response string to RTU-like response string
          response = _hexdecode(response)
  
      # Validate response checksum
      if mode == MODE_ASCII:
          calculateChecksum = _calculateLrcString
          numberOfChecksumBytes = NUMBER_OF_LRC_BYTES
      else:
          calculateChecksum = _calculateCrcString
          numberOfChecksumBytes = NUMBER_OF_CRC_BYTES
  
      receivedChecksum = response[-numberOfChecksumBytes:]
      responseWithoutChecksum = response[0 : len(response) - numberOfChecksumBytes]
      calculatedChecksum = calculateChecksum(responseWithoutChecksum)
  
      if receivedChecksum != calculatedChecksum:
          template = 'Checksum error in {} mode: {!r} instead of {!r} . The response is: {!r} (plain response: {!r})'
          text = template.format(
                  mode,
                  receivedChecksum,
                  calculatedChecksum,
                  response, plainresponse)
          raise ValueError(text)
  
      # Check slave address
      responseaddress = ord(response[BYTEPOSITION_FOR_SLAVEADDRESS])
  
      if responseaddress != slaveaddress:
          raise ValueError('Wrong return slave address: {} instead of {}. The response is: {!r}'.format( \
              responseaddress, slaveaddress, response))
  
      # Check function code
      receivedFunctioncode = ord(response[BYTEPOSITION_FOR_FUNCTIONCODE])
  
      if receivedFunctioncode == _setBitOn(functioncode, BITNUMBER_FUNCTIONCODE_ERRORINDICATION):
          raise ValueError('The slave is indicating an error. The response is: {!r}'.format(response))
  
      elif receivedFunctioncode != functioncode:
          raise ValueError('Wrong functioncode: {} instead of {}. The response is: {!r}'.format( \
              receivedFunctioncode, functioncode, response))
  
      # Read data payload
      firstDatabyteNumber = NUMBER_OF_RESPONSE_STARTBYTES
  
      if mode == MODE_ASCII:
          lastDatabyteNumber = len(response) - NUMBER_OF_LRC_BYTES
      else:
          lastDatabyteNumber = len(response) - NUMBER_OF_CRC_BYTES
  
      payload = response[firstDatabyteNumber:lastDatabyteNumber]
      return payload