68 return MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
75 #ifdef MAVLINK_FTP_UNIT_TEST 87 #ifdef MAVLINK_FTP_UNIT_TEST 99 #ifdef MAVLINK_FTP_UNIT_TEST 111 #ifdef MAVLINK_FTP_UNIT_TEST 125 if (msg->msgid == MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL) {
126 mavlink_file_transfer_protocol_t ftp_request;
127 mavlink_msg_file_transfer_protocol_decode(msg, &ftp_request);
129 #ifdef MAVLINK_FTP_DEBUG 130 PX4_INFO(
"FTP: received ftp protocol message target_system: %d target_component: %d",
131 ftp_request.target_system, ftp_request.target_component);
134 if ((ftp_request.target_system ==
_getServerSystemId() || ftp_request.target_system == 0) &&
144 mavlink_file_transfer_protocol_t *ftp_req,
145 uint8_t target_system_id,
146 uint8_t target_comp_id)
148 bool stream_send =
false;
149 PayloadHeader *payload =
reinterpret_cast<PayloadHeader *
>(&ftp_req->payload[0]);
154 PX4_ERR(
"Failed to allocate buffers");
168 mavlink_file_transfer_protocol_t *last_reply =
reinterpret_cast<mavlink_file_transfer_protocol_t *
>(
_last_reply);
169 PayloadHeader *last_payload =
reinterpret_cast<PayloadHeader *
>(&last_reply->payload[0]);
171 if (payload->seq_number + 1 == last_payload->seq_number) {
181 #ifdef MAVLINK_FTP_DEBUG 182 PX4_INFO(
"ftp: channel %u opc %u size %u offset %u",
_getServerChannel(), payload->opcode, payload->size,
186 switch (payload->opcode) {
203 errorCode =
_workOpen(payload, O_RDONLY);
207 errorCode =
_workOpen(payload, O_CREAT | O_EXCL | O_WRONLY);
211 errorCode =
_workOpen(payload, O_CREAT | O_WRONLY);
219 errorCode =
_workBurst(payload, target_system_id, target_comp_id);
257 payload->seq_number++;
261 payload->req_opcode = payload->opcode;
266 payload->req_opcode = payload->opcode;
270 if (r_errno == EEXIST) {
274 payload->data[0] = errorCode;
278 payload->data[1] = r_errno;
285 if (!stream_send || errorCode !=
kErrNone) {
287 ftp_req->target_system = target_system_id;
288 ftp_req->target_network = 0;
289 ftp_req->target_component = target_comp_id;
313 PayloadHeader *payload =
reinterpret_cast<PayloadHeader *
>(&ftp_req->payload[0]);
319 if (payload->size <=
sizeof(uint32_t)) {
324 #ifdef MAVLINK_FTP_DEBUG 325 PX4_INFO(
"FTP: %s seq_number: %d", payload->opcode ==
kRspAck ?
"Ack" :
"Nak", payload->seq_number);
328 #ifdef MAVLINK_FTP_UNIT_TEST 358 #ifdef MAVLINK_FTP_DEBUG 359 PX4_INFO(
"FTP: list %s offset %d",
_work_buffer1, payload->offset);
362 struct dirent *result =
nullptr;
365 int requested_offset = payload->offset;
367 while (requested_offset-- > 0 && readdir(dp)) {}
371 result = readdir(dp);
374 if (result ==
nullptr) {
376 PX4_WARN(
"readdir failed");
378 *((
char *)&payload->data[offset]) =
'\0';
380 payload->size = offset;
387 if (payload->offset != 0 && offset == 0) {
397 uint32_t fileSize = 0;
401 switch (result->d_type) {
418 fileSize = st.st_size;
427 case DTYPE_DIRECTORY:
431 if ((!list_hidden && (strncmp(result->d_name,
".", 1) == 0)) ||
432 strcmp(result->d_name,
".") == 0 || strcmp(result->d_name,
"..") == 0) {
474 payload->data[offset++] = direntType;
476 #ifdef MAVLINK_FTP_DEBUG 477 PX4_INFO(
"FTP: list %s %s",
_work_buffer1, (
char *)&payload->data[offset - 1]);
479 offset += nameLen + 1;
483 payload->size = offset;
493 PX4_ERR(
"FTP: Open failed - out of sessions\n");
500 #ifdef MAVLINK_FTP_DEBUG 504 uint32_t fileSize = 0;
509 if (oflag & O_RDONLY) {
517 fileSize = st.st_size;
530 payload->session = 0;
531 payload->size =
sizeof(uint32_t);
532 std::memcpy(payload->data, &fileSize, payload->size);
545 #ifdef MAVLINK_FTP_DEBUG 546 PX4_INFO(
"FTP: read offset:%d", payload->offset);
551 PX4_ERR(
"request past EOF");
555 if (lseek(
_session_info.fd, payload->offset, SEEK_SET) < 0) {
556 PX4_ERR(
"seek fail");
562 if (bytes_read < 0) {
564 PX4_ERR(
"read fail %d", bytes_read);
568 payload->size = bytes_read;
581 #ifdef MAVLINK_FTP_DEBUG 582 PX4_INFO(
"FTP: burst offset:%d", payload->offset);
590 _session_info.stream_target_component_id = target_component_id;
603 if (lseek(
_session_info.fd, payload->offset, SEEK_SET) < 0) {
605 PX4_ERR(
"seek fail");
611 if (bytes_written < 0) {
613 PX4_ERR(
"write fail %d", bytes_written);
617 payload->size =
sizeof(uint32_t);
618 std::memcpy(payload->data, &bytes_written, payload->size);
655 const char temp_file[] = PX4_STORAGEDIR
"/.trunc.tmp";
663 if (!S_ISREG(st.st_mode)) {
669 if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) {
674 if (payload->offset == (
unsigned)st.st_size) {
678 }
else if (payload->offset == 0) {
689 }
else if (payload->offset > (
unsigned)st.st_size) {
697 if (lseek(fd, payload->offset - 1, SEEK_SET) < 0) {
702 bool ok = 1 ==
::write(fd,
"", 1);
717 if (::unlink(temp_file) != 0) {
772 size_t oldpath_sz = strlen(ptr);
774 if (oldpath_sz == payload->size) {
824 if (mkdir(
_work_buffer1, S_IRWXU | S_IRWXG | S_IRWXO) == 0) {
837 uint32_t checksum = 0;
853 if (bytes_read < 0) {
860 checksum = crc32part((uint8_t *)
_work_buffer2, bytes_read, checksum);
865 payload->size =
sizeof(uint32_t);
866 std::memcpy(payload->data, &checksum, payload->size);
877 payload->data[payload->size] =
'\0';
884 return (
char *) & (payload->data[0]);
891 int src_fd = -1, dst_fd = -1;
894 src_fd = ::open(src_path, O_RDONLY);
900 dst_fd = ::open(dst_path, O_CREAT | O_TRUNC | O_WRONLY
915 ssize_t bytes_read, bytes_written;
920 if (bytes_read == 0) {
924 }
else if (bytes_read < 0) {
932 if (bytes_written != bytes_read) {
933 PX4_ERR(
"cp: short write");
938 length -= bytes_written;
945 return (length > 0) ? -1 : 0;
971 #ifndef MAVLINK_FTP_UNIT_TEST 974 #ifdef MAVLINK_FTP_DEBUG 975 PX4_INFO(
"MavlinkFTP::send max_bytes_to_send(%d) get_free_tx_buf(%d)", max_bytes_to_send,
_mavlink->
get_free_tx_buf());
978 if (max_bytes_to_send <
get_size()) {
993 mavlink_file_transfer_protocol_t ftp_msg;
994 PayloadHeader *payload =
reinterpret_cast<PayloadHeader *
>(&ftp_msg.payload[0]);
997 payload->session = 0;
1003 #ifdef MAVLINK_FTP_DEBUG 1004 PX4_INFO(
"stream send: offset %d",
_session_info.stream_offset);
1010 #ifdef MAVLINK_FTP_DEBUG 1011 PX4_INFO(
"stream download: sending Nak EOF");
1016 if (lseek(
_session_info.fd, payload->offset, SEEK_SET) < 0) {
1018 #ifdef MAVLINK_FTP_DEBUG 1019 PX4_WARN(
"stream download: seek fail");
1027 if (bytes_read < 0) {
1030 #ifdef MAVLINK_FTP_DEBUG 1031 PX4_WARN(
"stream download: read fail");
1035 payload->size = bytes_read;
1044 uint8_t *pData = &payload->data[0];
1045 *pData = error_code;
1048 int r_errno = errno;
1050 payload->data[1] = r_errno;
1056 #ifndef MAVLINK_FTP_UNIT_TEST 1058 if (max_bytes_to_send < (
get_size() * 2)) {
1063 payload->burst_complete =
true;
1071 payload->burst_complete =
false;
1072 #ifndef MAVLINK_FTP_UNIT_TEST 1079 ftp_msg.target_system =
_session_info.stream_target_system_id;
1080 ftp_msg.target_network = 0;
1081 ftp_msg.target_component =
_session_info.stream_target_component_id;
1083 }
while (more_data);
Creates file at <path> for writing, returns <session>
Session is not currently open.
static constexpr int _work_buffer1_len
Writes <size> bytes to <offset> in <session>
Removes Directory at <path>, must be empty.
ErrorCode _workWrite(PayloadHeader *payload)
Responds to a Write command.
static constexpr const int _root_dir_len
All available Sessions in use.
ErrorCode _workTruncateFile(PayloadHeader *payload)
Responds to a TruncateFile command.
ErrorCode _workRemoveDirectory(PayloadHeader *payload)
Responds to a RemoveDirectory command.
static const char kDirentSkip
Identifies Skipped entry from List command.
void send(const hrt_abstime t)
Handle sending of messages.
ReceiveMessageFunc_t _utRcvMsgFunc
Unit test override for mavlink message sending.
ErrorCode _workRename(PayloadHeader *payload)
Responds to a Rename command.
ErrorCode _workReset(PayloadHeader *payload)
Responds to a Reset command.
Opens file at <path> for writing, returns <session>
uint8_t _last_reply[MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN - MAVLINK_MSG_FILE_TRANSFER_PROTOCOL_FIELD_PAYLOAD_LEN+sizeof(PayloadHeader)+sizeof(uint32_t)]
MAVLink 2.0 protocol interface definition.
Calculate CRC32 for file at <path>
void(* ReceiveMessageFunc_t)(const mavlink_file_transfer_protocol_t *ftp_req, void *worker_data)
Terminates open Read session.
void _reply(mavlink_file_transfer_protocol_t *ftp_req)
Sends the specified FTP response message out through mavlink.
ErrorCode
Error codes returned in Nak response PayloadHeader.data[0].
uint8_t _getServerChannel(void)
Reads <size> bytes from <offset> in <session>
unsigned get_free_tx_buf()
Get the free space in the transmit buffer.
char * _data_as_cstring(PayloadHeader *payload)
Guarantees that the payload data is null terminated.
Rename <path1> to <path2>
ErrorCode _workList(PayloadHeader *payload, bool list_hidden=false)
Responds to a List command.
PayloadHeader.size is invalid.
Terminates all open Read sessions.
int _copy_file(const char *src_path, const char *dst_path, size_t length)
Copy file (with limited space)
static char msg[NUM_MSG][CONFIG_USART1_TXBUFSIZE]
static void read(bootloader_app_shared_t *pshared)
Command failed, errno sent back in PayloadHeader.data[1].
ErrorCode _workRead(PayloadHeader *payload)
Responds to a Read command.
Truncate file at <path> to <offset> length.
void _process_request(mavlink_file_transfer_protocol_t *ftp_req, uint8_t target_system_id, uint8_t target_comp_id)
Processes an FTP message.
bool _ensure_buffers_exist()
make sure that the working buffers _work_buffer* are allocated
static hrt_abstime hrt_elapsed_time(const hrt_abstime *then)
Compute the delta between a timestamp taken in the past and now.
ErrorCode _workCalcFileCRC32(PayloadHeader *payload)
Responds to a CalcFileCRC32 command.
static constexpr const char _root_dir[]
ErrorCode _workTerminate(PayloadHeader *payload)
Responds to a Terminate command.
List files in <path> from <offset>
uint8_t _getServerComponentId(void)
mavlink_channel_t get_channel() const
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
MavlinkFTP(Mavlink *mavlink)
uint8_t _getServerSystemId(void)
hrt_abstime _last_work_buffer_access
timestamp when the buffers were last accessed
void handle_message(const mavlink_message_t *msg)
Handle possible FTP message.
ErrorCode _workCreateDirectory(PayloadHeader *payload)
Responds to a CreateDirectory command.
void * _worker_data
Additional parameter to _utRcvMsgFunc;.
Creates directory at <path>
static void write(bootloader_app_shared_t *pshared)
static const uint8_t kMaxDataLength
Maximum data size in RequestHeader::data.
void set_unittest_worker(ReceiveMessageFunc_t rcvMsgFunc, void *worker_data)
Sets up the server to run in unit test mode.
ErrorCode _workRemoveFile(PayloadHeader *payload)
Responds to a RemoveFile command.
static const char kDirentFile
Identifies File returned from List command.
static const char kDirentDir
Identifies Directory returned from List command.
ErrorCode _workBurst(PayloadHeader *payload, uint8_t target_system_id, uint8_t target_component_id)
Responds to a Stream command.
int get_system_id() const
Get the MAVLink system id.
static constexpr int _work_buffer2_len
Offset past end of file for List and Read commands.
Session info, fd=-1 for no active session.
ErrorCode _workOpen(PayloadHeader *payload, int oflag)
Responds to an Open command.
int get_component_id() const
Get the MAVLink component id.
static const uint8_t serverChannel
Channel to send to.
Opens file at <path> for reading, returns <session>
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
Burst download session file.
static const uint8_t serverSystemId
System ID for server.
static const uint8_t serverComponentId
Component ID for server.