Skip to content

Commit

Permalink
[TC]: Add a helper for getting implement geometry from a DDOP
Browse files Browse the repository at this point in the history
  • Loading branch information
ad3154 committed Feb 10, 2024
1 parent b48c262 commit 552e515
Show file tree
Hide file tree
Showing 8 changed files with 618 additions and 10 deletions.
2 changes: 2 additions & 0 deletions isobus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ set(ISOBUS_SRC
"isobus_task_controller_server_options.cpp"
"nmea2000_message_definitions.cpp"
"nmea2000_message_interface.cpp"
"isobus_device_descriptor_object_pool_helpers.cpp"
"can_message_data.cpp")

# Prepend the source directory path to all the source files
Expand Down Expand Up @@ -96,6 +97,7 @@ set(ISOBUS_INCLUDE
"nmea2000_message_definitions.hpp"
"nmea2000_message_interface.hpp"
"isobus_preferred_addresses.hpp"
"isobus_device_descriptor_object_pool_helpers.hpp"
"can_message_data.hpp")
# Prepend the include directory path to all the include files
prepend(ISOBUS_INCLUDE ${ISOBUS_INCLUDE_DIR} ${ISOBUS_INCLUDE})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,10 @@ namespace isobus
/// @brief Clears the DDOP back to an empty state
void clear();

/// @brief Returns the number of objects in the DDOP
/// @brief Returns the number of objects in the DDOP.
/// @note The number of objects in the DDOP is limited to 65535.
/// @returns The number of objects in the DDOP
std::size_t size() const;
std::uint16_t size() const;

private:
/// @brief Checks to see that all parent object IDs correspond to an object in this DDOP
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
//================================================================================================
/// @file isobus_device_descriptor_object_pool_helpers.hpp
///
/// @brief Defines helpers for getting commonly needed information out of a DDOP.
/// These are provided so that you don't have to do quite as much manual parsing of
/// the DDOP.
/// @author Adrian Del Grosso
///
/// @copyright 2024 The Open-Agriculture Developers
//================================================================================================

#ifndef ISOBUS_DEVICE_DESCRIPTOR_OBJECT_POOL_HELPERS_HPP
#define ISOBUS_DEVICE_DESCRIPTOR_OBJECT_POOL_HELPERS_HPP

#include "isobus/isobus/isobus_device_descriptor_object_pool.hpp"
#include "isobus_standard_data_description_indices.hpp"

namespace isobus
{
/// @brief Helper object for parsing DDOPs
/// @attention Getting this data from the DDOP requires traversing the
/// entire DDOP several times, so you should treat these as O(n^2) and try
/// not to call them too many times.
class DeviceDescriptorObjectPoolHelper
{
public:
/// @brief A wrapper for a DDOP value which tells you if the value
/// was actually supplied by the DDOP.
class ObjectPoolValue
{
public:
/// @brief Default constructor for ObjectPoolValue which
/// defaults the value to being non-existant and not settable
ObjectPoolValue() = default;

/// @brief overloads the bool operator so that you can check for
/// this value's existence by doing if(thisObject)
/// @returns true if the value was in the DDOP or has been manually set, otherwise false
explicit operator bool() const;

/// @brief Returns if this variable exists.
/// A variable exists if it was either provided in the DDOP, or has been set manually
/// as part of a DPD value command.
/// @returns true if the value has ever been set, otherwise false
bool exists() const;

/// @brief Returns if this value is editable. DPDs are editable. DPTs are not.
/// @returns true if the value can be set/edited
bool editable() const;

/// @brief Returns the value. If the value doesn't exist this will return 0.
/// @returns The value if it exists, otherwise 0.
std::int32_t get() const;

private:
friend class DeviceDescriptorObjectPoolHelper; ///< Allow our helper to change the values

std::int32_t value = 0; ///< The value being wrapped by this object
bool isValuePresent = false; ///< Stores if the value has ever been set
bool isSettable = false; ///< Stores if the value can be set, such as on a DPD's value
};

/// @brief A helper class that describes an individual section of a boom.
/// This is used to describe the sections of a boom. Units are defined in mm as specified
/// in the ISO 11783-10 standard. X offsets are fore/aft. Y offsets are left/right again as
/// defined in the ISO 11783-10 standard.
class Section
{
public:
/// @brief Default constructor for a helper class that describes an individual section of a boom
Section();

ObjectPoolValue xOffset_mm; ///< The x offset of the section in mm. X offsets are fore+/aft-.
ObjectPoolValue yOffset_mm; ///< The y offset of the section in mm. Y offsets are left-/right+.
ObjectPoolValue zOffset_mm; ///< The z offset of the section in mm. Z offsets are up+/down-.
ObjectPoolValue width_mm; ///< The width of the section in mm.
};

/// @brief A helper class that describes a sub boom (not all devices support this)
class SubBoom
{
public:
/// @brief Default constructor for a helper class that describes a sub boom
SubBoom();

std::vector<Section> sections; ///< The sections of the sub boom
ObjectPoolValue xOffset_mm; ///< The x offset of the sub boom in mm. X offsets are fore+/aft-.
ObjectPoolValue yOffset_mm; ///< The y offset of the sub boom in mm. Y offsets are left-/right+.
ObjectPoolValue zOffset_mm; ///< The z offset of the sub boom in mm. Z offsets are up+/down-.
ObjectPoolValue width_mm; ///< The width of the sub boom in mm
};

/// @brief A helper class that describes a boom
/// This is used to describe a boom, or more generally, an ISO11783-10 function element.
class Boom
{
public:
std::vector<Section> sections; ///< The sections of the boom
std::vector<SubBoom> subBooms; ///< The sub booms of the boom
ObjectPoolValue xOffset_mm; ///< The x offset of the sub boom in mm. X offsets are fore+/aft-.
ObjectPoolValue yOffset_mm; ///< The y offset of the sub boom in mm. Y offsets are left-/right+.
ObjectPoolValue zOffset_mm; ///< The z offset of the sub boom in mm. Z offsets are up+/down-.
};

/// @brief A helper class that describes an implement based on its DDOP.
class Implement
{
public:
std::vector<Boom> booms; ///< The booms of the implement
};

/// @brief Get the implement description from the DDOP
/// @param[in] ddop The DDOP to get the implement geometry and info from
/// @returns The implement geometry and info
static Implement get_implement_geometry(DeviceDescriptorObjectPool &ddop);

private:
/// @brief Parse an element of the DDOP
/// @param[in] ddop The DDOP to get the implement geometry and info from
/// @param[in] elementObject The object to parse
/// @param[out] implementToPopulate The implement to populate with the parsed data
static void parse_element(DeviceDescriptorObjectPool &ddop,
std::shared_ptr<task_controller_object::DeviceElementObject> elementObject,
Implement &implementToPopulate);

/// @brief Parse a section element of the DDOP
/// @param[in] ddop The DDOP to get the implement geometry and info from
/// @param[in] elementObject The element to parse
/// @returns The parsed section, or a default section if the elementObject is invalid
static Section parse_section(DeviceDescriptorObjectPool &ddop,
std::shared_ptr<task_controller_object::DeviceElementObject> elementObject);

/// @brief Parse a sub boom element of the DDOP
/// @param[in] ddop The DDOP to get the implement geometry and info from
/// @param[in] elementObject The element to parse
/// @returns The parsed sub boom, or a default sub boom if the elementObject is invalid
static SubBoom parse_sub_boom(DeviceDescriptorObjectPool &ddop,
std::shared_ptr<task_controller_object::DeviceElementObject> elementObject);

/// @brief Sets the value and presence based on a DDI match.
/// @param[in,out] objectPoolValue The object pool value to set.
/// @param[in] property The device property object.
/// @param[in] ddi The DDI to check against.
static void setValueFromProperty(ObjectPoolValue &objectPoolValue,
const std::shared_ptr<task_controller_object::DevicePropertyObject> &property,
DataDescriptionIndex ddi);

/// @brief Sets the settable flag based on a DDI match for process data.
/// @param[in,out] objectPoolValue The object pool value to update.
/// @param[in] processData The device process data object.
/// @param[in] ddi The DDI to check against.
static void setEditableFromProcessData(ObjectPoolValue &objectPoolValue,
const std::shared_ptr<task_controller_object::DeviceProcessDataObject> &processData,
DataDescriptionIndex ddi);
};
} // namespace isobus

#endif // ISOBUS_DEVICE_DESCRIPTOR_OBJECT_POOL_HELPERS_HPP
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,11 @@ namespace isobus
/// @returns true if the child object ID was found and removed, otherwise false
bool remove_reference_to_child_object(std::uint16_t childID);

/// @brief Returns the number of child objects added with `add_reference_to_child_object`
/// @brief Returns the number of child objects added with `add_reference_to_child_object`.
/// @note The maximum number of child objects is technically 65535 because the serialized
/// form of the value uses a 16-bit integer to store the count.
/// @returns The number of child objects added with `add_reference_to_child_object`
std::size_t get_number_child_objects() const;
std::uint16_t get_number_child_objects() const;

/// @brief Returns a child object ID by index
/// @param[in] index The index of the child object ID to return
Expand Down
8 changes: 4 additions & 4 deletions isobus/src/isobus_device_descriptor_object_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ namespace isobus
xmlOutput << "\">" << std::endl;

// Process a list of all device object references
for (std::size_t k = 0; k < deviceElement->get_number_child_objects(); k++)
for (std::uint16_t k = 0; k < deviceElement->get_number_child_objects(); k++)
{
xmlOutput << "\t\t<DOR A=\"" << static_cast<int>(deviceElement->get_child_object_id(k)) << "\"/>" << std::endl;
}
Expand Down Expand Up @@ -1053,9 +1053,9 @@ namespace isobus
objectList.clear();
}

std::size_t DeviceDescriptorObjectPool::size() const
std::uint16_t DeviceDescriptorObjectPool::size() const
{
return objectList.size();
return static_cast<std::uint16_t>(objectList.size());
}

bool DeviceDescriptorObjectPool::resolve_parent_ids_to_objects()
Expand Down Expand Up @@ -1114,7 +1114,7 @@ namespace isobus
if (retVal)
{
// Process children now that parent has been validated
for (std::size_t i = 0; i < currentDeviceElement->get_number_child_objects(); i++)
for (std::uint16_t i = 0; i < currentDeviceElement->get_number_child_objects(); i++)
{
auto child = get_object_by_id(currentDeviceElement->get_child_object_id(i));
if (nullptr == child.get())
Expand Down
Loading

0 comments on commit 552e515

Please sign in to comment.