sendMessage method
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');
}
}