transferBulkFromHub method
Implementation
Future<Uint8List?> transferBulkFromHub({
required TransferType txType,
required int txSubType,
required String destination,
int maxChunkErrors = 50,
}) async {
if (!isConnected || connectedDeviceId == null) {
return null;
}
final resetOk = await bulkReset();
if (!resetOk) {
return null;
}
final setup = await setupBulkTransferSingle(
txType: txType,
txSubType: txSubType,
destination: destination,
totalSizeBytes: 0,
toHub: false,
);
if (setup == null) {
return null;
}
final expectedTotalBytes = setup.totalSizeBytes;
final assembled = BytesBuilder(copy: false);
int sequenceId = 0;
int errorCount = 0;
final pendingAcks = Queue<int>();
while (true) {
if (expectedTotalBytes > 0 && assembled.length >= expectedTotalBytes) {
break;
}
final ackBatch = pendingAcks.take(_bulkReadAckWindowSize).toList();
final chunk = await sendCommand<BulkBytesChunk>(
BulkReadBleCommandTx(
sequenceId: sequenceId,
txType: txType,
ackIds: ackBatch,
),
);
if (chunk == null) {
errorCount++;
if (errorCount > maxChunkErrors) {
return null;
}
continue;
}
_prunePendingBulkReadAcks(pendingAcks, chunk.nextExpectedAckId);
if (!pendingAcks.contains(chunk.sequenceId)) {
pendingAcks.add(chunk.sequenceId);
}
final hasEof = _hasEndOfFileError(chunk.errorCodes);
final hasInvalidSequence = chunk.errorCodes.contains(
CborHubCommandErrorKeys.invalidSequence,
);
final hasIllegalAck = chunk.errorCodes.contains(
CborHubCommandErrorKeys.illegalAck,
);
if (hasEof) {
break;
}
if (chunk.hasErrors && !hasInvalidSequence && !hasIllegalAck) {
errorCount++;
if (errorCount > maxChunkErrors) {
return null;
}
continue;
}
if (chunk.bytes.isEmpty && chunk.checksum == 0) {
errorCount++;
if (errorCount > maxChunkErrors) {
return null;
}
continue;
}
if (chunk.sequenceId != sequenceId) {
errorCount++;
if (errorCount > maxChunkErrors) {
return null;
}
continue;
}
if (_fletcher32(chunk.bytes) != chunk.checksum) {
errorCount++;
if (errorCount > maxChunkErrors) {
return null;
}
continue;
}
assembled.add(chunk.bytes);
sequenceId++;
errorCount = 0;
}
final flushedAcks = await _flushPendingBulkReadAcks(
nextSequenceId: sequenceId,
txType: txType,
pendingAcks: pendingAcks,
);
if (!flushedAcks) {
return null;
}
final bytes = assembled.toBytes();
if (setup.totalCrc32 != null && setup.totalCrc32 != _crc32(bytes)) {
return null;
}
return bytes;
}