sendMessage method

Future<void> sendMessage(
  1. TxMsg message
)

Sends a typed message as a series of messages to Frame as chunks marked by 0x01 (dataFlag), messageFlag & 0xFF, {first packet: length(Uint16)}, payload(chunked) until all data in the payload is sent. Payload data cannot exceed 65535 bytes in length. Can be received by a corresponding Lua function on Frame.

Implementation

Future<void> sendMessage(TxMsg message) async {
  Uint8List payload = message.pack();

  if (payload.length > 65535) {
    return Future.error(const BrilliantBluetoothException(
        'Payload length exceeds 65535 bytes'));
  }

  int lengthMsb = payload.length >> 8;
  int lengthLsb = payload.length & 0xFF;
  int sentBytes = 0;
  bool firstPacket = true;
  int bytesRemaining = payload.length;
  int chunksize = maxDataLength! - 1;

  // the full sized packet buffer to prepare. If we are sending a full sized packet,
  // set packetToSend to point to packetBuffer. If we are sending a smaller (final) packet,
  // instead point packetToSend to a range within packetBuffer
  Uint8List packetBuffer = Uint8List(maxDataLength! + 1);
  Uint8List packetToSend = packetBuffer;
  _log.fine(() => 'sendMessage: payload size: ${payload.length}');

  while (sentBytes < payload.length) {
    if (firstPacket) {
      _log.finer('sendMessage: first packet');
      firstPacket = false;

      if (bytesRemaining < chunksize - 2) {
        // first and final chunk - small payload
        _log.finer('sendMessage: first and final packet');
        packetBuffer[0] = 0x01;
        packetBuffer[1] = message.msgCode & 0xFF;
        packetBuffer[2] = lengthMsb;
        packetBuffer[3] = lengthLsb;
        packetBuffer.setAll(
            4, payload.getRange(sentBytes, sentBytes + bytesRemaining));
        sentBytes += bytesRemaining;
        packetToSend =
            Uint8List.sublistView(packetBuffer, 0, bytesRemaining + 4);
      } else if (bytesRemaining == chunksize - 2) {
        // first and final chunk - small payload, exact packet size match
        _log.finer('sendMessage: first and final packet, exact match');
        packetBuffer[0] = 0x01;
        packetBuffer[1] = message.msgCode & 0xFF;
        packetBuffer[2] = lengthMsb;
        packetBuffer[3] = lengthLsb;
        packetBuffer.setAll(
            4, payload.getRange(sentBytes, sentBytes + bytesRemaining));
        sentBytes += bytesRemaining;
        packetToSend = packetBuffer;
      } else {
        // first of many chunks
        _log.finer('sendMessage: first of many packets');
        packetBuffer[0] = 0x01;
        packetBuffer[1] = message.msgCode & 0xFF;
        packetBuffer[2] = lengthMsb;
        packetBuffer[3] = lengthLsb;
        packetBuffer.setAll(
            4, payload.getRange(sentBytes, sentBytes + chunksize - 2));
        sentBytes += chunksize - 2;
        packetToSend = packetBuffer;
      }
    } else {
      // not the first packet
      if (bytesRemaining < chunksize) {
        _log.finer('sendMessage: not the first packet, final packet');
        // final data chunk, smaller than chunksize
        packetBuffer[0] = 0x01;
        packetBuffer[1] = message.msgCode & 0xFF;
        packetBuffer.setAll(
            2, payload.getRange(sentBytes, sentBytes + bytesRemaining));
        sentBytes += bytesRemaining;
        packetToSend =
            Uint8List.sublistView(packetBuffer, 0, bytesRemaining + 2);
      } else {
        _log.finer(
            'sendMessage: not the first packet, non-final packet or exact match final packet');
        // non-final data chunk or final chunk with exact packet size match
        packetBuffer[0] = 0x01;
        packetBuffer[1] = message.msgCode & 0xFF;
        packetBuffer.setAll(
            2, payload.getRange(sentBytes, sentBytes + chunksize));
        sentBytes += chunksize;
        packetToSend = packetBuffer;
      }
    }

    // send the chunk
    await sendDataRaw(packetToSend);

    bytesRemaining = payload.length - sentBytes;
    _log.finer(() => 'Bytes remaining: $bytesRemaining');
  }
}