docs: def _communicate(self, request, number_of_bytes_to_read):
          """Talk to the slave via a serial port.
  
          Args:
              request (str): The raw request that is to be sent to the slave.
              number_of_bytes_to_read (int): number of bytes to read
  
          Returns:
              The raw data (string) returned from the slave.
  
          Raises:
              TypeError, ValueError, IOError
  
          Note that the answer might have strange ASCII control signs, which
          makes it difficult to print it in the promt (messes up a bit).
          Use repr() to make the string printable (shows ASCII values for control signs.)
  
          Will block until reaching *number_of_bytes_to_read* or timeout.
  
          If the attribute :attr:`Instrument.debug` is :const:`True`, the communication details are printed.
  
          If the attribute :attr:`Instrument.close_port_after_each_call` is :const:`True` the
          serial port is closed after each call.
  
          Timing::
  
                                                    Request from master (Master is writing)
                                                    |
                                                    |       Response from slave (Master is reading)
                                                    |       |
              ----W----R----------------------------W-------R----------------------------------------
                       |                            |       |
                       |<----- Silent period ------>|       |
                                                    |       |
                               Roundtrip time  ---->|-------|<--
  
          The resolution for Python's time.time() is lower on Windows than on Linux.
          It is about 16 ms on Windows according to
          http://stackoverflow.com/questions/157359/accurate-timestamping-in-python
  
          For Python3, the information sent to and from pySerial should be of the type bytes.
          This is taken care of automatically by MinimalModbus.
          
          
  
          """
  
          _checkString(request, minlength=1, description='request')
          _checkInt(number_of_bytes_to_read)
  
          if self.debug:
              _print_out('\nMinimalModbus debug mode. Writing to instrument (expecting {} bytes back): {!r} ({})'. \
                  format(number_of_bytes_to_read, request, _hexlify(request)))
  
          if self.close_port_after_each_call:
              self.serial.open()
  
          #self.serial.flushInput() TODO
  
          if sys.version_info[0] > 2:
              request = bytes(request, encoding='latin1')  # Convert types to make it Python3 compatible
  
          # Sleep to make sure 3.5 character times have passed
          minimum_silent_period   = _calculate_minimum_silent_period(self.serial.baudrate)
          time_since_read         = time.time() - _LATEST_READ_TIMES.get(self.serial.port, 0)
  
          if time_since_read < minimum_silent_period:
              sleep_time = minimum_silent_period - time_since_read
  
              if self.debug:
                  template = 'MinimalModbus debug mode. Sleeping for {:.1f} ms. ' + \
                          'Minimum silent period: {:.1f} ms, time since read: {:.1f} ms.'
                  text = template.format(
                      sleep_time * _SECONDS_TO_MILLISECONDS,
                      minimum_silent_period * _SECONDS_TO_MILLISECONDS,
                      time_since_read * _SECONDS_TO_MILLISECONDS)
                  _print_out(text)
  
              time.sleep(sleep_time)
  
          elif self.debug:
              template = 'MinimalModbus debug mode. No sleep required before write. ' + \
                  'Time since previous read: {:.1f} ms, minimum silent period: {:.2f} ms.'
              text = template.format(
                  time_since_read * _SECONDS_TO_MILLISECONDS,
                  minimum_silent_period * _SECONDS_TO_MILLISECONDS)
              _print_out(text)
  
          # Write request
          latest_write_time = time.time()
          
          self.serial.write(request)
  
          # Read and discard local echo
          if self.handle_local_echo:
              localEchoToDiscard = self.serial.read(len(request))
              if self.debug:
                  template = 'MinimalModbus debug mode. Discarding this local echo: {!r} ({} bytes).' 
                  text = template.format(localEchoToDiscard, len(localEchoToDiscard))
                  _print_out(text)
              if localEchoToDiscard != request:
                  template = 'Local echo handling is enabled, but the local echo does not match the sent request. ' + \
                      'Request: {!r} ({} bytes), local echo: {!r} ({} bytes).' 
                  text = template.format(request, len(request), localEchoToDiscard, len(localEchoToDiscard))
                  raise IOError(text)
  
          # Read response
          answer = self.serial.read(number_of_bytes_to_read)
          _LATEST_READ_TIMES[self.serial.port] = time.time()
  
          if self.close_port_after_each_call:
              self.serial.close()
  
          if sys.version_info[0] > 2:
              answer = str(answer, encoding='latin1')  # Convert types to make it Python3 compatible
  
          if self.debug:
              template = 'MinimalModbus debug mode. Response from instrument: {!r} ({}) ({} bytes), ' + \
                  'roundtrip time: {:.1f} ms. Timeout setting: {:.1f} ms.\n'
              text = template.format(
                  answer,
                  _hexlify(answer),
                  len(answer),
                  (_LATEST_READ_TIMES.get(self.serial.port, 0) - latest_write_time) * _SECONDS_TO_MILLISECONDS,
                  self.serial.timeout * _SECONDS_TO_MILLISECONDS)
              _print_out(text)
  
          if len(answer) == 0:
              raise IOError('No communication with the instrument (no answer)')
  
          return answer