code: async def i2c_read_request(self, address, register, number_of_bytes,
                                 read_type, cb=None, cb_type=None):
          
          if address not in self.i2c_map:
              # self.i2c_map[address] = [None, cb]
              self.i2c_map[address] = {'value': None, 'callback': cb,
                                       'callback_type': cb_type}
          data = [address, read_type, register & 0x7f, (register >> 7) & 0x7f,
                  number_of_bytes & 0x7f, (number_of_bytes >> 7) & 0x7f]
          await self._send_sysex(PrivateConstants.I2C_REQUEST, data)
docs: This method requests the read of an i2c device. Results are retrieved
          by a call to i2c_get_read_data(). or by callback.
  
          If a callback method is provided, when data is received from the
          device it will be sent to the callback method.
          Some devices require that transmission be restarted
          (e.g. MMA8452Q accelerometer).
          Use Constants.I2C_READ | Constants.I2C_END_TX_MASK for those cases.
  
          :param address: i2c device address
  
          :param register: register number (can be set to zero)
  
          :param number_of_bytes: number of bytes expected to be returned
  
          :param read_type: I2C_READ  or I2C_READ_CONTINUOUSLY. I2C_END_TX_MASK
                            may be OR'ed when required
  
          :param cb: Optional callback function to report i2c data as a
                     result of read command
  
          :param cb_type: Constants.CB_TYPE_DIRECT = direct call or
                          Constants.CB_TYPE_ASYNCIO = asyncio coroutine
  
          :returns: No return value.