<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def send_rpc(self, address, rpc_id, call_payload, timeout=3.0):
 """Send an rpc to our connected device. The device must already be connected and the rpc interface open. This method will synchronously send an RPC and wait for the response. Any RPC errors will be raised as exceptions and if there were no errors, the RPC's response payload will be returned as a binary bytearray. See :meth:`AbstractDeviceAdapter.send_rpc` for documentation of the possible exceptions that can be raised here. Args: address (int):
 The tile address containing the RPC rpc_id (int):
 The ID of the RPC that we wish to call. call_payload (bytes):
 The payload containing encoded arguments for the RPC. timeout (float):
 The maximum number of seconds to wait for the RPC to finish. Defaults to 3s. Returns: bytearray: The RPC's response payload. """


        if not self.connected:
            raise HardwareError("Cannot send an RPC if we are not in a connected state")

        if timeout is None:
            timeout = 3.0

        status = -1
        payload = b''
        recording = None

        if self.connection_interrupted:
            self._try_reconnect()

        if self._record is not None:
            recording = _RecordedRPC(self.connection_string, address, rpc_id, call_payload)
            recording.start()

        try:
            payload = self._loop.run_coroutine(self.adapter.send_rpc(0, address, rpc_id, call_payload, timeout))
            status, payload = pack_rpc_response(payload, None)
        except VALID_RPC_EXCEPTIONS as exc:
            status, payload = pack_rpc_response(payload, exc)

        if self._record is not None:
            recording.finish(status, payload)
            self._recording.append(recording)

        if self.connection_interrupted:
            self._try_reconnect()

        return unpack_rpc_response(status, payload, rpc_id, address)