LCOV - code coverage report
Current view: top level - AP_Filesystem - AP_Filesystem_Param.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 250 379 66.0 %
Date: 2026-09-09 11:02:08 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /*
       2             :    This program is free software: you can redistribute it and/or modify
       3             :    it under the terms of the GNU General Public License as published by
       4             :    the Free Software Foundation, either version 3 of the License, or
       5             :    (at your option) any later version.
       6             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : /*
      16             :   ArduPilot filesystem interface for parameters
      17             :  */
      18             : 
      19             : #include "AP_Filesystem_config.h"
      20             : 
      21             : #if AP_FILESYSTEM_PARAM_ENABLED
      22             : 
      23             : #include "AP_Filesystem.h"
      24             : #include "AP_Filesystem_Param.h"
      25             : #include <AP_Param/AP_Param.h>
      26             : #include <AP_Math/AP_Math.h>
      27             : #include <ctype.h>
      28             : 
      29             : #define PACKED_NAME "param.pck"
      30             : 
      31             : extern const AP_HAL::HAL& hal;
      32             : 
      33             : // QURT HAL already has a declaration of errno in errno.h
      34             : #if CONFIG_HAL_BOARD != HAL_BOARD_QURT
      35             : extern int errno;
      36             : #endif
      37             : 
      38           3 : int AP_Filesystem_Param::open(const char *fname, int flags, bool allow_absolute_path)
      39             : {
      40           3 :     if (!check_file_name(fname)) {
      41           0 :         errno = ENOENT;
      42           0 :         return -1;
      43             :     }
      44           3 :     bool read_only = ((flags & O_ACCMODE) == O_RDONLY);
      45             :     uint8_t idx;
      46           3 :     for (idx=0; idx<max_open_file; idx++) {
      47           3 :         if (!file[idx].open) {
      48           3 :             break;
      49             :         }
      50             :     }
      51           3 :     if (idx == max_open_file) {
      52           0 :         errno = ENFILE;
      53           0 :         return -1;
      54             :     }
      55           3 :     struct rfile &r = file[idx];
      56           3 :     if (read_only) {
      57           2 :         r.cursors = NEW_NOTHROW cursor[num_cursors];
      58           2 :         if (r.cursors == nullptr) {
      59           0 :             errno = ENOMEM;
      60           0 :             return -1;
      61             :         }
      62             :     }
      63           3 :     r.file_ofs = 0;
      64           3 :     r.open = true;
      65           3 :     r.with_defaults = false;
      66           3 :     r.start = 0;
      67           3 :     r.count = 0;
      68           3 :     r.read_size = 0;
      69           3 :     r.file_size = 0;
      70           3 :     r.writebuf = nullptr;
      71           3 :     if (!read_only) {
      72             :         // setup for upload
      73           1 :         r.writebuf = NEW_NOTHROW ExpandingString();
      74           1 :         if (r.writebuf == nullptr) {
      75           0 :             close(idx);
      76           0 :             errno = ENOMEM;
      77           0 :             return -1;
      78             :         }
      79             :     }
      80             : 
      81             :     /*
      82             :       allow for URI style arguments param.pck?start=N&count=C
      83             :      */
      84           3 :     const char *c = strchr(fname, '?');
      85           4 :     while (c && *c) {
      86           1 :         c++;
      87           1 :         if (strncmp(c, "start=", 6) == 0) {
      88           0 :             uint32_t v = strtoul(c+6, nullptr, 10);
      89           0 :             if (v >= UINT16_MAX) {
      90           0 :                 goto failed;
      91             :             }
      92           0 :             r.start = v;
      93           0 :             c += 6;
      94           0 :             c = strchr(c, '&');
      95           0 :             continue;
      96           0 :         }
      97           1 :         if (strncmp(c, "count=", 6) == 0) {
      98           0 :             uint32_t v = strtoul(c+6, nullptr, 10);
      99           0 :             if (v >= UINT16_MAX) {
     100           0 :                 goto failed;
     101             :             }
     102           0 :             r.count = v;
     103           0 :             c += 6;
     104           0 :             c = strchr(c, '&');
     105           0 :             continue;
     106           0 :         }
     107             : #if AP_PARAM_DEFAULTS_ENABLED
     108           1 :         if (strncmp(c, "withdefaults=", 13) == 0) {
     109           1 :             uint32_t v = strtoul(c+13, nullptr, 10);
     110           1 :             if (v > 1) {
     111           0 :                 goto failed;
     112             :             }
     113           1 :             r.with_defaults = v == 1;
     114           1 :             c += 13;
     115           1 :             c = strchr(c, '&');
     116           1 :             continue;
     117           1 :         }
     118             : #endif
     119             :     }
     120             : 
     121           3 :     return idx;
     122             : 
     123           0 : failed:
     124           0 :     delete [] r.cursors;
     125           0 :     r.open = false;
     126           0 :     errno = EINVAL;
     127           0 :     return -1;
     128             : }
     129             : 
     130           3 : int AP_Filesystem_Param::close(int fd)
     131             : {
     132           3 :     if (fd < 0 || fd >= max_open_file || !file[fd].open) {
     133           0 :         errno = EBADF;
     134           0 :         return -1;
     135             :     }
     136           3 :     struct rfile &r = file[fd];
     137           3 :     int ret = 0;
     138           3 :     if (r.writebuf != nullptr && !finish_upload(r)) {
     139           0 :         errno = EINVAL;
     140           0 :         ret = -1;
     141             :     }
     142           3 :     r.open = false;
     143           3 :     delete [] r.cursors;
     144           3 :     r.cursors = nullptr;
     145           3 :     delete r.writebuf;
     146           3 :     r.writebuf = nullptr;
     147           3 :     return ret;
     148             : }
     149             : 
     150             : /*
     151             :   packed format:
     152             :     file header:
     153             :       uint16_t magic = 0x671b or  0x671c for included default values
     154             :       uint16_t num_params
     155             :       uint16_t total_params
     156             : 
     157             :     per-parameter:
     158             : 
     159             :     uint8_t type:4;         // AP_Param type NONE=0, INT8=1, INT16=2, INT32=3, FLOAT=4
     160             :     uint8_t flags:4;        // bit 0: includes default value for this param
     161             :     uint8_t common_len:4;   // number of name bytes in common with previous entry, 0..15
     162             :     uint8_t name_len:4;     // non-common length of param name -1 (0..15)
     163             :     uint8_t name[name_len]; // name
     164             :     uint8_t data[];         // value, length given by variable type, data length doubled if default is included
     165             : 
     166             :     Any leading zero bytes after the header should be discarded as pad
     167             :     bytes. Pad bytes are used to ensure that a parameter data[] field
     168             :     does not cross a read packet boundary
     169             :  */
     170             : 
     171             : /*
     172             :   pack a single parameter. The buffer must be at least of size max_pack_len
     173             :  */
     174        3144 : uint8_t AP_Filesystem_Param::pack_param(const struct rfile &r, struct cursor &c, uint8_t *buf)
     175             : {
     176             :     char name[AP_MAX_NAME_SIZE+1];
     177        3144 :     name[AP_MAX_NAME_SIZE] = 0;
     178             :     enum ap_var_type ptype;
     179             :     AP_Param *ap;
     180             :     float default_val;
     181             : 
     182        3144 :     if (c.token_ofs == 0) {
     183           2 :         c.idx = 0;
     184           2 :         ap = AP_Param::first(&c.token, &ptype, &default_val);
     185           2 :         uint16_t idx = 0;
     186           2 :         while (idx < r.start && ap) {
     187           0 :             ap = AP_Param::next_scalar(&c.token, &ptype, &default_val);
     188           0 :             idx++;
     189             :         }
     190             :     } else {
     191        3142 :         c.idx++;
     192        3142 :         ap = AP_Param::next_scalar(&c.token, &ptype, &default_val);
     193             :     }
     194        3144 :     if (ap == nullptr || (r.count && c.idx >= r.count)) {
     195           2 :         if (r.count == 0 && c.idx != AP_Param::count_parameters()) {
     196             :             // the parameter count is incorrect, invalidate so a
     197             :             // repeated param download avoids an error
     198           0 :             AP_Param::invalidate_count();
     199             :         }
     200           2 :         return 0;
     201             :     }
     202        3142 :     ap->copy_name_token(c.token, name, AP_MAX_NAME_SIZE, true);
     203             : 
     204        3142 :     uint8_t common_len = 0;
     205        3142 :     const char *last_name = c.last_name;
     206        3142 :     const char *pname = name;
     207       24226 :     while (*pname == *last_name && *pname) {
     208       21084 :         common_len++;
     209       21084 :         pname++;
     210       21084 :         last_name++;
     211             :     }
     212        3142 :     uint8_t name_len = strlen(pname);
     213        3142 :     if (name_len == 0) {
     214           0 :         name_len = 1;
     215           0 :         common_len--;
     216           0 :         pname--;
     217             :     }
     218             : #if AP_PARAM_DEFAULTS_ENABLED
     219        3142 :     const bool add_default = r.with_defaults && !is_equal(ap->cast_to_float(ptype), default_val);
     220             : #else
     221             :     const bool add_default = false;
     222             : #endif
     223        3142 :     const uint8_t type_len = AP_Param::type_size(ptype);
     224        3142 :     uint8_t packed_len = type_len + name_len + 2 + (add_default ? type_len : 0);
     225        3142 :     const uint8_t flags = add_default;
     226             : 
     227             :     /*
     228             :       see if we need to add padding to ensure that a data field never
     229             :       crosses a block boundary. This ensures that re-reading a block
     230             :       won't get a corrupt value for a parameter
     231             :      */
     232        3142 :     if (type_len > 1) {
     233        2151 :         const uint32_t ofs = c.token_ofs + sizeof(struct header) + packed_len;
     234        2151 :         const uint32_t ofs_mod = ofs % r.read_size;
     235        2151 :         if (ofs_mod > 0 && ofs_mod < type_len) {
     236          24 :             const uint8_t pad = type_len - ofs_mod;
     237          24 :             memset(buf, 0, pad);
     238          24 :             buf += pad;
     239          24 :             packed_len += pad;
     240             :         }
     241             :     }
     242             : 
     243        3142 :     buf[0] = uint8_t(ptype) | (flags<<4);
     244        3142 :     buf[1] = common_len | ((name_len-1)<<4);
     245        3142 :     memcpy(&buf[2], pname, name_len);
     246        3142 :     memcpy(&buf[2+name_len], ap, type_len);
     247             : #if AP_PARAM_DEFAULTS_ENABLED
     248        3142 :     if (add_default) {
     249          47 :         switch (ptype) {
     250           0 :             case AP_PARAM_NONE:
     251             :             case AP_PARAM_GROUP:
     252             :                 // should never happen...
     253           0 :                 break;
     254           3 :             case AP_PARAM_INT8: {
     255           3 :                 const int32_t int8_default = default_val;
     256           3 :                 memcpy(&buf[2+name_len+type_len], &int8_default, type_len);
     257           3 :                 break;
     258             :             }
     259          12 :             case AP_PARAM_INT16: {
     260          12 :                 const int16_t int16_default = default_val;
     261          12 :                 memcpy(&buf[2+name_len+type_len], &int16_default, type_len);
     262          12 :                 break;
     263             :             }
     264          19 :             case AP_PARAM_INT32: {
     265          19 :                 const int32_t int32_default = default_val;
     266          19 :                 memcpy(&buf[2+name_len+type_len], &int32_default, type_len);
     267          19 :                 break;
     268             :             }
     269          13 :             case AP_PARAM_FLOAT:
     270             :             case AP_PARAM_VECTOR3F: {
     271          13 :                 memcpy(&buf[2+name_len+type_len], &default_val, type_len);
     272          13 :                 break;
     273             :             }
     274             :         }
     275             :     }
     276             : #endif
     277             : 
     278        3142 :     strcpy(c.last_name, name);
     279             : 
     280        3142 :     return packed_len;
     281             : }
     282             : 
     283             : /*
     284             :   seek the token to match file offset
     285             :  */
     286           0 : bool AP_Filesystem_Param::token_seek(const struct rfile &r, const uint32_t data_ofs, struct cursor &c)
     287             : {
     288           0 :     if (data_ofs == 0) {
     289           0 :         memset(&c, 0, sizeof(c));
     290           0 :         return true;
     291             :     }
     292           0 :     if (c.token_ofs > data_ofs) {
     293           0 :         memset(&c, 0, sizeof(c));
     294             :     }
     295             : 
     296           0 :     if (c.trailer_len > 0) {
     297           0 :         uint8_t n = MIN(c.trailer_len, data_ofs - c.token_ofs);
     298           0 :         if (n != c.trailer_len) {
     299           0 :             memmove(&c.trailer[0], &c.trailer[n], c.trailer_len - n);
     300             :         }
     301           0 :         c.trailer_len -= n;
     302           0 :         c.token_ofs += n;
     303             :     }
     304             :     
     305           0 :     while (data_ofs != c.token_ofs) {
     306           0 :         uint32_t available = data_ofs - c.token_ofs;
     307             :         uint8_t tbuf[max_pack_len];
     308           0 :         uint8_t len = pack_param(r, c, tbuf);
     309           0 :         if (len == 0) {
     310             :             // no more parameters
     311           0 :             break;
     312             :         }
     313           0 :         uint8_t n = MIN(len, available);
     314           0 :         if (len > available) {
     315           0 :             c.trailer_len = len - available;
     316           0 :             memcpy(c.trailer, &tbuf[n], c.trailer_len);
     317             :         }
     318           0 :         c.token_ofs += n;
     319             :     }
     320           0 :     return data_ofs == c.token_ofs;
     321             : }
     322             : 
     323         150 : int32_t AP_Filesystem_Param::read(int fd, void *buf, uint32_t count)
     324             : {
     325         150 :     if (fd < 0 || fd >= max_open_file || !file[fd].open) {
     326           0 :         errno = EBADF;
     327           0 :         return -1;
     328             :     }
     329             : 
     330         150 :     struct rfile &r = file[fd];
     331         150 :     if (r.writebuf != nullptr) {
     332             :         // no read on upload
     333           0 :         errno = EINVAL;
     334           0 :         return -1;
     335             :     }
     336         150 :     size_t header_total = 0;
     337             : 
     338             :     /*
     339             :       we only allow for a single read size. This ensures that pad
     340             :       bytes placed to avoid a data value crossing a block boundary in
     341             :       the ftp protocol do not change when filling in lost packets
     342             :      */
     343         150 :     if (r.read_size == 0 && count > 0) {
     344           2 :         r.read_size = count;
     345             :     }
     346         150 :     if (r.read_size != 0 && r.read_size != count) {
     347           0 :         errno = EINVAL;
     348           0 :         return -1;
     349             :     }
     350             : 
     351         150 :     if (r.file_size != 0) {
     352             :         // ensure we don't try to read past EOF
     353           2 :         if (r.file_ofs > r.file_size) {
     354           0 :             count = 0;
     355             :         } else {
     356           2 :             count = MIN(count, r.file_size - r.file_ofs);
     357             :         }
     358             :     }
     359             : 
     360         150 :     if (r.file_ofs < sizeof(struct header)) {
     361           2 :         struct header hdr;
     362           2 :         hdr.total_params = AP_Param::count_parameters();
     363           2 :         if (hdr.total_params <= r.start) {
     364           0 :             errno = EINVAL;
     365           0 :             return -1;
     366             :         }
     367           2 :         hdr.num_params = hdr.total_params - r.start;
     368           2 :         if (r.count > 0 && hdr.num_params > r.count) {
     369           0 :             hdr.num_params = r.count;
     370             :         }
     371           2 :         uint8_t n = MIN(sizeof(hdr) - r.file_ofs, count);
     372           2 :         if (r.with_defaults) {
     373           1 :             hdr.magic = pmagic_with_default;
     374             :         }
     375           2 :         const uint8_t *b = (const uint8_t *)&hdr;
     376           2 :         memcpy(buf, &b[r.file_ofs], n);
     377           2 :         count -= n;
     378           2 :         header_total += n;
     379           2 :         r.file_ofs += n;
     380           2 :         buf = (void *)(n + (const uint8_t *)buf);
     381           2 :         if (count == 0) {
     382           0 :             return header_total;
     383             :         }
     384             :     }
     385             : 
     386         150 :     uint32_t data_ofs = r.file_ofs - sizeof(struct header);
     387         150 :     uint8_t best_i = 0;
     388         150 :     uint32_t best_ofs = r.cursors[0].token_ofs;
     389         150 :     size_t total = 0;
     390             : 
     391             :     // find the first cursor that is positioned after the file offset
     392         300 :     for (uint8_t i=1; i<num_cursors; i++) {
     393         150 :         struct cursor &c = r.cursors[i];
     394         150 :         if (c.token_ofs >= data_ofs && c.token_ofs < best_ofs) {
     395           0 :             best_i = i;
     396           0 :             best_ofs = c.token_ofs;
     397             :         }
     398             :     }
     399         150 :     struct cursor &c = r.cursors[best_i];
     400             : 
     401         150 :     if (data_ofs != c.token_ofs) {
     402           0 :         if (!token_seek(r, data_ofs, c)) {
     403             :             // must be EOF
     404           0 :             return header_total;
     405             :         }
     406             :     }
     407         150 :     if (count == 0) {
     408           2 :         return header_total;
     409             :     }
     410         148 :     uint8_t *ubuf = (uint8_t *)buf;
     411             : 
     412         148 :     if (c.trailer_len > 0) {
     413         134 :         uint8_t n = MIN(c.trailer_len, count);
     414         134 :         memcpy(ubuf, c.trailer, n);
     415         134 :         count -= n;
     416         134 :         ubuf += n;
     417         134 :         if (n != c.trailer_len) {
     418           0 :             memmove(&c.trailer[0], &c.trailer[n], c.trailer_len - n);
     419             :         }
     420         134 :         c.trailer_len -= n;
     421         134 :         total += n;
     422         134 :         c.token_ofs += n;
     423             :     }
     424             : 
     425        3290 :     while (count > 0) {
     426             :         uint8_t tbuf[max_pack_len];
     427        3144 :         uint8_t len = pack_param(r, c, tbuf);
     428        3144 :         if (len == 0) {
     429             :             // no more params, use this to trigger EOF in later reads
     430           2 :             const uint32_t size = r.file_ofs + total;
     431           2 :             if (r.file_size == 0) {
     432           2 :                 r.file_size = size;
     433             :             } else {
     434           0 :                 r.file_size = MIN(size, r.file_size);
     435             :             }
     436           2 :             break;
     437             :         }
     438        3142 :         uint8_t n = MIN(len, count);
     439        3142 :         if (len > count) {
     440         134 :             c.trailer_len = len - count;
     441         134 :             memcpy(c.trailer, &tbuf[count], c.trailer_len);
     442             :         }
     443        3142 :         memcpy(ubuf, tbuf, n);
     444        3142 :         count -= n;
     445        3142 :         ubuf += n;
     446        3142 :         total += n;
     447        3142 :         c.token_ofs += n;
     448             :     }
     449         148 :     r.file_ofs += total;
     450         148 :     return total + header_total;
     451             : }
     452             : 
     453           5 : int32_t AP_Filesystem_Param::lseek(int fd, int32_t offset, int seek_from)
     454             : {
     455           5 :     if (fd < 0 || fd >= max_open_file || !file[fd].open) {
     456           0 :         errno = EBADF;
     457           0 :         return -1;
     458             :     }
     459           5 :     struct rfile &r = file[fd];
     460           5 :     switch (seek_from) {
     461           5 :     case SEEK_SET:
     462           5 :         r.file_ofs = offset;
     463           5 :         break;
     464           0 :     case SEEK_CUR:
     465           0 :         r.file_ofs += offset;
     466           0 :         break;
     467           0 :     case SEEK_END:
     468           0 :         errno = EINVAL;
     469           0 :         return -1;
     470             :     }
     471           5 :     return r.file_ofs;
     472             : }
     473             : 
     474           2 : int AP_Filesystem_Param::stat(const char *name, struct stat *stbuf)
     475             : {
     476           2 :     if (!check_file_name(name)) {
     477           0 :         errno = ENOENT;
     478           0 :         return -1;
     479             :     }
     480           2 :     memset(stbuf, 0, sizeof(*stbuf));
     481             :     // give size estimation to avoid needing to scan entire file
     482           2 :     stbuf->st_size = AP_Param::count_parameters() * 12;
     483           2 :     return 0;
     484             : }
     485             : 
     486             : /*
     487             :   check for the right file name
     488             :  */
     489           5 : bool AP_Filesystem_Param::check_file_name(const char *name)
     490             : {
     491           5 :     const uint8_t packed_len = strlen(PACKED_NAME);
     492           5 :     if (strncmp(name, PACKED_NAME, packed_len) == 0 &&
     493           5 :         (name[packed_len] == 0 || name[packed_len] == '?')) {
     494           5 :         return true;
     495             :     }
     496           0 :     return false;
     497             : }
     498             : 
     499             : /*
     500             :   support param upload
     501             :  */
     502           3 : int32_t AP_Filesystem_Param::write(int fd, const void *buf, uint32_t count)
     503             : {
     504           3 :     if (fd < 0 || fd >= max_open_file || !file[fd].open) {
     505           0 :         errno = EBADF;
     506           0 :         return -1;
     507             :     }
     508           3 :     struct rfile &r = file[fd];
     509           3 :     if (r.writebuf == nullptr) {
     510           0 :         errno = EBADF;
     511           0 :         return -1;
     512             :     }
     513           3 :     struct header hdr;
     514           3 :     if (r.file_ofs == 0 && count >= sizeof(hdr)) {
     515             :         // pre-expand the buffer to the full size when we get the header
     516           3 :         memcpy(&hdr, buf, sizeof(hdr));
     517           3 :         if (hdr.magic == pmagic) {
     518           3 :             const uint32_t flen = hdr.total_params;
     519           3 :             if (flen > r.writebuf->get_length()) {
     520           1 :                 if (!r.writebuf->append(nullptr, flen - r.writebuf->get_length())) {
     521             :                     // not enough memory
     522           0 :                     return -1;
     523             :                 }
     524             :             }
     525             :         }
     526             :     }
     527           3 :     if (r.file_ofs + count > r.writebuf->get_length()) {
     528           0 :         if (!r.writebuf->append(nullptr, r.file_ofs + count - r.writebuf->get_length())) {
     529           0 :             return -1;
     530             :         }
     531             :     }
     532           3 :     uint8_t *b = (uint8_t *)r.writebuf->get_writeable_string();
     533           3 :     memcpy(&b[r.file_ofs], buf, count);
     534           3 :     r.file_ofs += count;
     535           3 :     return count;
     536             : }
     537             : 
     538             : /*
     539             :   parse incoming parameters
     540             :  */
     541           1 : bool AP_Filesystem_Param::param_upload_parse(const rfile &r, bool &need_retry)
     542             : {
     543           1 :     need_retry = false;
     544             : 
     545           1 :     const uint8_t *b = (const uint8_t *)r.writebuf->get_string();
     546           1 :     uint32_t length = r.writebuf->get_length();
     547           1 :     struct header hdr;
     548           1 :     if (length < sizeof(hdr)) {
     549           0 :         return false;
     550             :     }
     551           1 :     memcpy(&hdr, b, sizeof(hdr));
     552           1 :     if (hdr.magic != pmagic) {
     553           0 :         return false;
     554             :     }
     555           1 :     if (length != hdr.total_params) {
     556           0 :         return false;
     557             :     }
     558           1 :     b += sizeof(hdr);
     559             : 
     560           1 :     char last_name[17] {};
     561             : 
     562           3 :     for (uint16_t i=0; i<hdr.num_params; i++) {
     563           2 :         enum ap_var_type ptype = (enum ap_var_type)(b[0]&0x0F);
     564           2 :         uint8_t flags = (enum ap_var_type)(b[0]>>4);
     565           2 :         if (flags != 0) {
     566           0 :             return false;
     567             :         }
     568           2 :         uint8_t common_len = b[1]&0xF;
     569           2 :         uint8_t name_len = (b[1]>>4)+1;
     570           2 :         if (common_len + name_len > 16) {
     571           0 :             return false;
     572             :         }
     573             :         char name[17];
     574           2 :         memcpy(name, last_name, common_len);
     575           2 :         memcpy(&name[common_len], &b[2], name_len);
     576           2 :         name[common_len+name_len] = 0;
     577             : 
     578           2 :         memcpy(last_name, name, sizeof(name));
     579           2 :         enum ap_var_type ptype2 = AP_PARAM_NONE;
     580             :         uint16_t flags2;
     581             : 
     582           2 :         b += 2 + name_len;
     583             : 
     584             :         // assume that this write to the Param filesystem is coming
     585             :         // via mavftp:
     586           2 :         AP_Param *p = AP_Param::find(name, &ptype2, &flags2);
     587           2 :         if (p == nullptr || !p->allow_set_via_mavlink(flags2)) {
     588           1 :             if (ptype == AP_PARAM_INT8) {
     589           1 :                 b++;
     590           0 :             } else if (ptype == AP_PARAM_INT16) {
     591           0 :                 b += 2;
     592             :             } else {
     593           0 :                 b += 4;
     594             :             }
     595           1 :             continue;
     596             :         }
     597             : 
     598             :         /*
     599             :           if we are enabling a subsystem we need a small delay between
     600             :           parameters to allow main thread to perform any allocation of
     601             :           backends
     602             :         */
     603           1 :         bool need_delay = ((flags2 & AP_PARAM_FLAG_ENABLE) != 0 &&
     604           1 :                            ptype2 == AP_PARAM_INT8 &&
     605           0 :                            ((AP_Int8 *)p)->get() == 0);
     606             : 
     607           1 :         if (ptype == ptype2 && ptype == AP_PARAM_INT32) {
     608             :             // special handling of int32_t to preserve all bits
     609             :             int32_t v;
     610           0 :             memcpy(&v, b, sizeof(v));
     611           0 :             ((AP_Int32 *)p)->set(v);
     612           0 :             b += 4;
     613           1 :         } else if (ptype == AP_PARAM_INT8) {
     614           1 :             if (need_delay && b[0] == 0) {
     615           0 :                 need_delay = false;
     616             :             }
     617           1 :             p->set_float((int8_t)b[0], ptype2);
     618           1 :             b += 1;
     619           0 :         } else if (ptype == AP_PARAM_INT16) {
     620             :             int16_t v;
     621           0 :             memcpy(&v, b, sizeof(v));
     622           0 :             p->set_float(float(v), ptype2);
     623           0 :             b += 2;
     624           0 :         } else if (ptype == AP_PARAM_INT32) {
     625             :             int32_t v;
     626           0 :             memcpy(&v, b, sizeof(v));
     627           0 :             p->set_float(float(v), ptype2);
     628           0 :             b += 4;
     629           0 :         } else if (ptype == AP_PARAM_FLOAT) {
     630             :             float v;
     631           0 :             memcpy(&v, b, sizeof(v));
     632           0 :             p->set_float(v, ptype2);
     633           0 :             b += 4;
     634             :         }
     635             : 
     636           1 :         p->save_sync(false, false);
     637             : 
     638           1 :         if (need_delay) {
     639             :             // let main thread have some time to init backends
     640           0 :             need_retry = true;
     641           0 :             hal.scheduler->delay(100);
     642             :         }
     643             :     }
     644           1 :     return true;
     645             : }
     646             : 
     647             : 
     648             : /*
     649             :   parse incoming parameters
     650             :  */
     651           1 : bool AP_Filesystem_Param::finish_upload(const rfile &r)
     652             : {
     653           1 :     uint8_t loops = 0;
     654           1 :     while (loops++ < 4) {
     655             :         bool need_retry;
     656           1 :         if (!param_upload_parse(r, need_retry)) {
     657           0 :             return false;
     658             :         }
     659           1 :         if (!need_retry) {
     660           1 :             break;
     661             :         }
     662             :     }
     663           1 :     return true;
     664             : }
     665             : 
     666             : #endif  // AP_FILESYSTEM_PARAM_ENABLED

Generated by: LCOV version 1.14