diff --git a/examples/seeder_example/vt_application.cpp b/examples/seeder_example/vt_application.cpp index 946763fc..b8d7898f 100644 --- a/examples/seeder_example/vt_application.cpp +++ b/examples/seeder_example/vt_application.cpp @@ -76,7 +76,7 @@ bool SeederVtApplication::initialize() VTClientUpdateHelper.add_tracked_numeric_value(currentAlarms2_ObjPtr); // Track the attribute values we want to update - VTClientUpdateHelper.add_tracked_attribute(speed_OutNum, 8, 0.0036f); + VTClientUpdateHelper.add_tracked_attribute_float(speed_OutNum, 8, 0.0036f); VTClientUpdateHelper.add_tracked_attribute(section1Status_OutRect, 5, solidGreen_FillAttr); VTClientUpdateHelper.add_tracked_attribute(section2Status_OutRect, 5, solidYellow_FillAttr); VTClientUpdateHelper.add_tracked_attribute(section3Status_OutRect, 5, solidRed_FillAttr); diff --git a/isobus/include/isobus/isobus/isobus_virtual_terminal_client_state_tracker.hpp b/isobus/include/isobus/isobus/isobus_virtual_terminal_client_state_tracker.hpp index e58f11c4..85b6afab 100644 --- a/isobus/include/isobus/isobus/isobus_virtual_terminal_client_state_tracker.hpp +++ b/isobus/include/isobus/isobus/isobus_virtual_terminal_client_state_tracker.hpp @@ -99,6 +99,12 @@ namespace isobus /// @param[in] initialValue The initial value of the attribute to track. void add_tracked_attribute(std::uint16_t objectId, std::uint8_t attribute, std::uint32_t initialValue = 0); + /// @brief Adds a float attribute to track. + /// @param[in] objectId The object id of the attribute to track. + /// @param[in] attribute The attribute to track. Make sure it's a float attribute! + /// @param[in] initialValue The initial value of the attribute to track. + void add_tracked_attribute_float(std::uint16_t objectId, std::uint8_t attribute, float initialValue = 0.0f); + /// @brief Removes an attribute from tracking. /// @param[in] objectId The object id of the attribute to remove from tracking. /// @param[in] attribute The attribute to remove from tracking. @@ -110,6 +116,12 @@ namespace isobus /// @return The value of the attribute of the tracked object. std::uint32_t get_attribute(std::uint16_t objectId, std::uint8_t attribute) const; + /// @brief Get the value of an attribute of a tracked object, if you tracked it with add_tracked_attribute_float. + /// @param[in] objectId The object id of the attribute to get. + /// @param[in] attribute The attribute to get. + /// @return The value of the attribute of the tracked object. + float get_attribute_float(std::uint16_t objectId, std::uint8_t attribute) const; + protected: std::shared_ptr client; ///< The control function of the virtual terminal client to track. std::shared_ptr server; ///< The control function of the server the client is connected to. @@ -134,6 +146,7 @@ namespace isobus std::uint8_t activeWorkingSetAddress = NULL_CAN_ADDRESS; ///< Holds the address of the control function that currently has std::map softKeyMasks; ///< Holds the data/alarms masks with their associated soft keys masks for tracked objects. std::map> attributeStates; ///< Holds the 'attribute' state of tracked objects. + std::map> floatAttributeStates; ///< Holds the 'attribute' state of tracked objects, for attributes that use floats (scale, for example). //! TODO: std::map alarmMaskPrioritiesStates; ///< Holds the 'alarm mask priority' state of tracked objects. //! TODO: std::map> listItemStates; ///< Holds the 'list item' state of tracked objects. //! TODO: add lock/unlock mask state diff --git a/isobus/include/isobus/isobus/isobus_virtual_terminal_client_update_helper.hpp b/isobus/include/isobus/isobus/isobus_virtual_terminal_client_update_helper.hpp index e3cf81f8..b53d45c2 100644 --- a/isobus/include/isobus/isobus/isobus_virtual_terminal_client_update_helper.hpp +++ b/isobus/include/isobus/isobus/isobus_virtual_terminal_client_update_helper.hpp @@ -74,6 +74,18 @@ namespace isobus /// @return True if the attribute was set successfully, false otherwise. bool set_attribute(std::uint16_t objectId, std::uint8_t attribute, std::uint32_t value); + /// @brief Sets the value of a float attribute of a tracked object. + /// @attention ONLY use this function for float attributes defined in ISO11783-6, + /// otherwise you will get incorrect results. Scale on output numbers, for example, is a float. + /// @note If the to be tracked working set consists of more than the master, + /// this function is incompatible with a VT prior to version 4. For working sets consisting + /// of only the master, this function is compatible with any VT version. + /// @param[in] objectId The object id of the attribute to set. + /// @param[in] attribute The attribute to set. + /// @param[in] value The value to set the attribute to. + /// @return True if the attribute was set successfully, false otherwise. + bool set_attribute(std::uint16_t objectId, std::uint8_t attribute, float value); + private: /// @brief Processes a numeric value change event /// @param[in] event The numeric value change event to process. diff --git a/isobus/src/isobus_virtual_terminal_client_state_tracker.cpp b/isobus/src/isobus_virtual_terminal_client_state_tracker.cpp index 39b6ff45..974509ef 100644 --- a/isobus/src/isobus_virtual_terminal_client_state_tracker.cpp +++ b/isobus/src/isobus_virtual_terminal_client_state_tracker.cpp @@ -160,6 +160,24 @@ namespace isobus attributeMap[attribute] = initialValue; } + void VirtualTerminalClientStateTracker::add_tracked_attribute_float(std::uint16_t objectId, std::uint8_t attribute, float initialValue) + { + if (floatAttributeStates.find(objectId) == floatAttributeStates.end()) + { + floatAttributeStates[objectId] = {}; + } + + auto &attributeMap = floatAttributeStates.at(objectId); + if ((attributeMap.find(attribute) != attributeMap.end()) || + (floatAttributeStates.find(attribute) != floatAttributeStates.end())) + { + LOG_WARNING("[VTStateHelper] add_tracked_attribute: attribute '%lu' of objectId '%lu' already tracked", attribute, objectId); + return; + } + + attributeMap[attribute] = initialValue; + } + void VirtualTerminalClientStateTracker::remove_tracked_attribute(std::uint16_t objectId, std::uint8_t attribute) { if (attributeStates.find(objectId) == attributeStates.end()) @@ -196,6 +214,37 @@ namespace isobus return attributeMap.at(attribute); } + float VirtualTerminalClientStateTracker::get_attribute_float(std::uint16_t objectId, std::uint8_t attribute) const + { + if (attributeStates.find(objectId) == attributeStates.end()) + { + if (floatAttributeStates.find(objectId) == floatAttributeStates.end()) + { + LOG_WARNING("[VTStateHelper] get_attribute_float: objectId '%lu' has no tracked float attributes", objectId); + return 0.0f; + } + + const auto &floatAttributeMap = floatAttributeStates.at(objectId); + if (floatAttributeStates.find(attribute) == floatAttributeStates.end()) + { + LOG_WARNING("[VTStateHelper] get_attribute_float: float attribute '%lu' of objectId '%lu' not tracked", attribute, objectId); + return 0; + } + return floatAttributeMap.at(attribute); + } + else + { + const auto &attributeMap = attributeStates.at(objectId); + + if (attributeMap.find(attribute) != attributeMap.end()) + { + LOG_WARNING("[VTStateHelper] get_attribute_float: attribute '%lu' of objectId '%lu' was tracked as an integer. You are calling the wrong function to get its value!", attribute, objectId); + return static_cast(attributeMap.at(attribute)); + } + } + return 0.0f; + } + void VirtualTerminalClientStateTracker::cache_active_mask(std::uint16_t maskId) { if (activeDataOrAlarmMask != maskId) diff --git a/isobus/src/isobus_virtual_terminal_client_update_helper.cpp b/isobus/src/isobus_virtual_terminal_client_update_helper.cpp index 73a95877..34842cf4 100644 --- a/isobus/src/isobus_virtual_terminal_client_update_helper.cpp +++ b/isobus/src/isobus_virtual_terminal_client_update_helper.cpp @@ -172,4 +172,34 @@ namespace isobus return success; } + bool VirtualTerminalClientUpdateHelper::set_attribute(std::uint16_t objectId, std::uint8_t attribute, float value) + { + if (nullptr == client) + { + LOG_ERROR("[VTStateHelper] set_attribute: client is nullptr"); + return false; + } + if (floatAttributeStates.find(objectId) == floatAttributeStates.end()) + { + LOG_ERROR("[VTStateHelper] set_attribute: objectId %lu has no float attributes tracked", objectId); + return false; + } + if (floatAttributeStates.at(objectId).find(attribute) == floatAttributeStates.at(objectId).end()) + { + LOG_WARNING("[VTStateHelper] set_attribute: float attribute %lu of objectId %lu not tracked", attribute, objectId); + return false; + } + if (floatAttributeStates.at(objectId).at(attribute) == value) + { + return true; + } + + bool success = vtClient->send_change_attribute(objectId, attribute, value); + if (success) + { + floatAttributeStates[objectId][attribute] = value; + } + return success; + } + } // namespace isobus