diff --git a/libraries/AP_Common/AP_Var.cpp b/libraries/AP_Common/AP_Var.cpp index 01e456757b..a62ec3f7e7 100644 --- a/libraries/AP_Common/AP_Var.cpp +++ b/libraries/AP_Common/AP_Var.cpp @@ -25,14 +25,6 @@ int AP_Var::_lookup_hint_index = 0; uint16_t AP_Var::_tail_sentinel; bool AP_Var::_EEPROM_scanned; -AP_Var_group::AP_Var_group() -{ -} - -AP_Var_group::~AP_Var_group() -{ -} - // Constructor // AP_Var::AP_Var(Key key, const prog_char *name, AP_Var_group *group, Flags flags) : @@ -442,3 +434,59 @@ bool AP_Var::_EEPROM_locate(bool allocate) return true; } +size_t +AP_Var_group::serialize(void *buf, size_t buf_size) +{ + return _serialize_unserialize(buf, buf_size, true); +} + +size_t +AP_Var_group::unserialize(void *buf, size_t buf_size) +{ + return _serialize_unserialize(buf, buf_size, false); +} + +size_t +AP_Var_group::_serialize_unserialize(void *buf, size_t buf_size, bool do_serialize) +{ + AP_Var *vp; + uint8_t *bp; + size_t size, total_size, resid; + + // Traverse the list of group members, serializing each in order + // + vp = next(); + bp = (uint8_t *)buf; + resid = buf_size; + total_size = 0; + while (vp->group() == this) { + + // (un)serialise the group member + if (do_serialize) { + size = vp->serialize(bp, buf_size); + } else { + size = vp->unserialize(bp, buf_size); + } + + // Account for the space that this variable consumes in the buffer + // + // We always count the total size, and we always advance the buffer pointer + // if there was room for the variable. This does mean that in the case where + // the buffer was too small for a variable in the middle of the group, that + // a smaller variable after it in the group may still be serialised into + // the buffer. Since that's a rare case it's not worth optimising for - in + // either case this function will return a size greater than the buffer size + // and the calling function will have to treat it as an error. + // + total_size += size; + if (size <= resid) { + // there was space for this one, account for it + resid -= size; + bp += size; + } + + vp = vp->next(); + } + return total_size; +} + diff --git a/libraries/AP_Common/AP_Var.h b/libraries/AP_Common/AP_Var.h index acb058ad97..76429ef3cc 100644 --- a/libraries/AP_Common/AP_Var.h +++ b/libraries/AP_Common/AP_Var.h @@ -128,8 +128,6 @@ public: k_no_import = (1 << 1) }; - AP_Var() {} - /// Constructor /// /// @param key The storage key to be associated with this variable. @@ -140,7 +138,7 @@ public: /// by ::copy_name. /// @param flags Optional flags which control how the variable behaves. /// - AP_Var(Key key, const prog_char *name, AP_Var_group *group, Flags flags); + AP_Var(Key key = k_no_key, const prog_char *name = NULL, AP_Var_group *group = NULL, Flags flags = k_no_flags); /// Destructor /// @@ -237,11 +235,25 @@ public: return (_flags & flagval) == flagval; } + /// Returns the group that a variable belongs to + /// + /// @return The parent group, or NULL if the variable is not grouped. + /// + AP_Var_group *group(void) { return _group; } + + /// Returns the next variable in the global list + /// + /// @return The next variable, either the next group member in order or + /// the next variable in an arbitrary order, or NULL if this is + /// the last variable in the list. + /// + AP_Var *next(void) { return _link; } + private: AP_Var_group *_group; ///< Group that the variable may be a member of + AP_Var *_link; ///< linked list pointer to next variable Key _key; ///< storage key const prog_char *_name; ///< name known to external agents (GCS, etc.) - AP_Var *_link; ///< linked list pointer to next variable uint8_t _flags; ///< flag bits // static state used by ::lookup @@ -308,15 +320,12 @@ private: class AP_Var_group : public AP_Var { public: - AP_Var_group(); - virtual ~AP_Var_group(); - /// Constructor /// /// @param key Storage key for the group. /// @param name An optional name prefix for members of the group. /// - AP_Var_group(Key key, const prog_char *name = NULL) : + AP_Var_group(Key key = k_no_key, const prog_char *name = NULL) : AP_Var(key, name, NULL, k_no_flags) { } @@ -326,23 +335,39 @@ public: /// Iteratively serializes the entire group into the supplied buffer. /// /// @param buf Buffer into which serialized data should be placed. - /// @param bufSize The size of the buffer provided. + /// @param buf_size The size of the buffer provided. /// @return The size of the serialized data, even if that data would - /// have overflowed the buffer. + /// have overflowed the buffer. If the value is less than or + /// equal to buf_size, serialization was successful. /// - virtual size_t serialize(void *buf, size_t bufSize) const; + virtual size_t serialize(void *buf, size_t buf_size); /// Unserialize the group. /// /// Iteratively unserializes the group from the supplied buffer. /// /// @param buf Buffer containing serialized data. - /// @param bufSize The size of the buffer. + /// @param buf_size The size of the buffer. /// @return The number of bytes from the buffer that would be consumed /// unserializing the data. If the value is less than or equal - /// to bufSize, unserialization was successful. + /// to buf_size, unserialization was successful. /// - virtual size_t unserialize(void *buf, size_t bufSize); + virtual size_t unserialize(void *buf, size_t buf_size); + +private: + /// Common implementation of the group member traversal and accounting used + /// by serialize/unserialize. + /// + /// @param buf Buffer containing serialized data. + /// @param buf_size The size of the buffer. + /// @param do_serialize True if the operation should serialize, false if it should + /// unserialize. + /// @return The number of bytes from the buffer that would be consumed + /// operating on the data. If the value is less than or equal + /// to buf_size, the operation was successful. + /// + + size_t _serialize_unserialize(void *buf, size_t buf_size, bool do_serialize); }; @@ -390,7 +415,7 @@ public: /// AP_VarT (AP_Var_group *group, Key index, - T initial_value = 0, + T initial_value, const prog_char *name = NULL, Flags flags = k_no_flags) : AP_Var(index, name, group, flags), diff --git a/libraries/AP_Common/examples/AP_Var/AP_Var.pde b/libraries/AP_Common/examples/AP_Var/AP_Var.pde index 076c3a63b8..84c07dd3a9 100644 --- a/libraries/AP_Common/examples/AP_Var/AP_Var.pde +++ b/libraries/AP_Common/examples/AP_Var/AP_Var.pde @@ -64,9 +64,9 @@ setup(void) { TEST(meta_type_id); - AP_Float f1; - AP_Float f2; - AP_Int8 i1; + AP_Float f1(0); + AP_Float f2(0); + AP_Int8 i1(0); uint16_t m1 = f1.meta_type_id(); uint16_t m2 = f2.meta_type_id(); @@ -77,13 +77,17 @@ setup(void) REQUIRE(m1 != m3); REQUIRE(AP_Meta_class::meta_type_equivalent(&f1, &f2)); REQUIRE(!AP_Meta_class::meta_type_equivalent(&f1, &i1)); + + REQUIRE(NULL != AP_Meta_class::meta_cast(&f1)); + REQUIRE(NULL == AP_Meta_class::meta_cast(&f1)); + REQUIRE(NULL == AP_Meta_class::meta_cast(&f1)); } // MetaClass: test external handles { TEST(meta_handle); - AP_Float f; + AP_Float f(0); AP_Meta_class::Meta_handle h = f.meta_get_handle(); REQUIRE(0 != h); @@ -95,7 +99,7 @@ setup(void) { TEST(meta_cast); - AP_Float f; + AP_Float f(0); REQUIRE(NULL != AP_Meta_class::meta_cast(&f)); REQUIRE(NULL == AP_Meta_class::meta_cast(&f));