MAVLink FTP: BurstReadFile ignores requested chunk size, always streams 239-byte packets

Author: DonLakeFlyerCreated Sep 16, 2026Updated Sep 16, 2026
Labelsstatus:needs-triage

Describe the bug

MavlinkFTP::_workBurst ignores the size field of a BurstReadFile request. The streaming loop always reads and sends kMaxDataLength (239) bytes per packet regardless of what the client asked for.

The MAVLink FTP spec (https://mavlink.io/en/services/ftp.html, "Reading a File (BurstReadFile)") says the client request "must specify ... size = default length of payload in burst responses" and the server stream "must specify ... size = size of data to read per burst message (max equal to payload size = 239)". ArduPilot honors the requested size (GCS_FTP.cpp, max_read = request.size == 0 ? sizeof(reply.data) : request.size), so the two servers currently behave differently for the same request.

The single-shot ReadFile path (_workRead) does honor payload->size, so only burst mode is affected.

Why it matters

A client that wants smaller FTP packets can't get them from PX4 in burst mode. The concrete case: SiK / RFD900 telemetry radios have an air frame of ~252 bytes, so a full 239-byte FTP payload (266 bytes on the wire with MAVLink v2 framing) is split across two air frames and is lost if either is dropped. Requesting ~110-byte chunks keeps each FTP packet inside one frame and noticeably reduces loss and ReadFile gap-filling on lossy links. This works against ArduPilot today; against PX4 the request is silently ignored and the burst still arrives in 239-byte packets.

Nobody has hit this before because QGroundControl has always sent size = 239 for bursts (see mavlink/qgroundcontrol FTPManager::_burstReadFileWorker). QGC is now looking at using smaller chunks on radio links (discussion in mavlink/qgroundcontrol), which is how this surfaced.

Expected behavior

_workBurst should record the requested size (clamped to kMaxDataLength; 0 treated as "full payload" to match ArduPilot) in _session_info, and the stream loop should ::read() that many bytes per packet instead of kMaxDataLength. Clients already tolerate any per-packet size because each burst ACK carries its own offset/size, so this is backwards compatible with existing GCS behavior.

To Reproduce

Send BurstReadFile with size = 110 for any file. Observe that every streamed packet still has size = 239.

Verified against main at 83c4f4e5.