/**
   * Execute a transaction with a Jaguar that sets some property.
   *
   * <p>Jaguar always acks when it receives a message. If we don't wait for an ack, the message
   * object in the Jaguar could get overwritten before it is handled.
   *
   * @param messageID The messageID to be used on the CAN bus (device number is added internally)
   * @param data The up to 8 bytes of data to be sent with the message
   * @param dataSize Specify how much of the data in "data" to send
   */
  protected byte setTransaction(int messageID, byte[] data, byte dataSize)
      throws CANTimeoutException {
    int ackMessageID = JaguarCANProtocol.LM_API_ACK | m_deviceNumber;

    // Make sure we don't have more than one transaction with the same Jaguar outstanding.
    synchronized (m_transactionMutex) {
      // Throw away any stale acks.
      try {
        receiveMessage(ackMessageID, kNoData, 0.0);
      } catch (CANTimeoutException e) {
      }
      // Send the message with the data.
      sendMessage(messageID | m_deviceNumber, data, dataSize);
      // Wait for an ack.
      dataSize = receiveMessage(ackMessageID, kNoData);
    }
    return dataSize;
  }