diff --git a/examples/task_controller_client/section_control_implement_sim.cpp b/examples/task_controller_client/section_control_implement_sim.cpp index b9378892..a564ba34 100644 --- a/examples/task_controller_client/section_control_implement_sim.cpp +++ b/examples/task_controller_client/section_control_implement_sim.cpp @@ -1,4 +1,5 @@ #include "section_control_implement_sim.hpp" +#include "isobus/isobus/can_constants.hpp" #include "isobus/isobus/isobus_standard_data_description_indices.hpp" #include "isobus/utility/to_string.hpp" @@ -84,13 +85,13 @@ bool SectionControlImplementSimulator::create_ddop(std::shared_ptradd_device("AgIsoStack++ UnitTest", "1.0.0", "123", "A++1.0", localizationData, std::vector(), clientName.get_full_name()); retVal &= poolToPopulate->add_device_element("Sprayer", elementCounter++, 0, isobus::task_controller_object::DeviceElementObject::Type::Device, static_cast(ImplementDDOPObjectIDs::MainDeviceElement)); - retVal &= poolToPopulate->add_device_process_data("Actual Work State", static_cast(isobus::DataDescriptionIndex::ActualWorkState), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(ImplementDDOPObjectIDs::DeviceActualWorkState)); - retVal &= poolToPopulate->add_device_process_data("Request Default PD", static_cast(ImplementDDOPObjectIDs::RequestDefaultProcessData), isobus::task_controller_object::Object::NULL_OBJECT_ID, 0, static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::Total), static_cast(ImplementDDOPObjectIDs::RequestDefaultProcessData)); + retVal &= poolToPopulate->add_device_process_data("Actual Work State", static_cast(isobus::DataDescriptionIndex::ActualWorkState), isobus::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(ImplementDDOPObjectIDs::DeviceActualWorkState)); + retVal &= poolToPopulate->add_device_process_data("Request Default PD", static_cast(ImplementDDOPObjectIDs::RequestDefaultProcessData), isobus::NULL_OBJECT_ID, 0, static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::Total), static_cast(ImplementDDOPObjectIDs::RequestDefaultProcessData)); retVal &= poolToPopulate->add_device_process_data("Total Time", static_cast(isobus::DataDescriptionIndex::EffectiveTotalTime), static_cast(ImplementDDOPObjectIDs::TimePresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::Total), static_cast(ImplementDDOPObjectIDs::DeviceTotalTime)); retVal &= poolToPopulate->add_device_element("Connector", elementCounter++, static_cast(ImplementDDOPObjectIDs::MainDeviceElement), isobus::task_controller_object::DeviceElementObject::Type::Connector, static_cast(ImplementDDOPObjectIDs::Connector)); retVal &= poolToPopulate->add_device_process_data("Connector X", static_cast(isobus::DataDescriptionIndex::DeviceElementOffsetX), static_cast(ImplementDDOPObjectIDs::ShortWidthPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), 0, static_cast(ImplementDDOPObjectIDs::ConnectorXOffset)); retVal &= poolToPopulate->add_device_process_data("Connector Y", static_cast(isobus::DataDescriptionIndex::DeviceElementOffsetY), static_cast(ImplementDDOPObjectIDs::ShortWidthPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), 0, static_cast(ImplementDDOPObjectIDs::ConnectorYOffset)); - retVal &= poolToPopulate->add_device_property("Type", 9, static_cast(isobus::DataDescriptionIndex::ConnectorType), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(ImplementDDOPObjectIDs::ConnectorType)); + retVal &= poolToPopulate->add_device_property("Type", 9, static_cast(isobus::DataDescriptionIndex::ConnectorType), isobus::NULL_OBJECT_ID, static_cast(ImplementDDOPObjectIDs::ConnectorType)); // Set up Boom retVal &= poolToPopulate->add_device_element("Boom", elementCounter++, static_cast(ImplementDDOPObjectIDs::MainDeviceElement), isobus::task_controller_object::DeviceElementObject::Type::Function, static_cast(ImplementDDOPObjectIDs::SprayBoom)); @@ -98,19 +99,19 @@ bool SectionControlImplementSimulator::create_ddop(std::shared_ptradd_device_property("Offset Y", 0, static_cast(isobus::DataDescriptionIndex::DeviceElementOffsetY), static_cast(ImplementDDOPObjectIDs::ShortWidthPresentation), static_cast(ImplementDDOPObjectIDs::BoomYOffset)); retVal &= poolToPopulate->add_device_property("Offset Z", 0, static_cast(isobus::DataDescriptionIndex::DeviceElementOffsetZ), static_cast(ImplementDDOPObjectIDs::ShortWidthPresentation), static_cast(ImplementDDOPObjectIDs::BoomZOffset)); retVal &= poolToPopulate->add_device_process_data("Actual Working Width", static_cast(isobus::DataDescriptionIndex::ActualWorkingWidth), static_cast(ImplementDDOPObjectIDs::LongWidthPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(ImplementDDOPObjectIDs::ActualWorkingWidth)); - retVal &= poolToPopulate->add_device_process_data("Setpoint Work State", static_cast(isobus::DataDescriptionIndex::SetpointWorkState), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(ImplementDDOPObjectIDs::SetpointWorkState)); + retVal &= poolToPopulate->add_device_process_data("Setpoint Work State", static_cast(isobus::DataDescriptionIndex::SetpointWorkState), isobus::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(ImplementDDOPObjectIDs::SetpointWorkState)); retVal &= poolToPopulate->add_device_process_data("Area Total", static_cast(isobus::DataDescriptionIndex::TotalArea), static_cast(ImplementDDOPObjectIDs::AreaPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::Total), static_cast(ImplementDDOPObjectIDs::AreaTotal)); - retVal &= poolToPopulate->add_device_process_data("Section Control State", static_cast(isobus::DataDescriptionIndex::SectionControlState), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::TimeInterval), static_cast(ImplementDDOPObjectIDs::SectionControlState)); + retVal &= poolToPopulate->add_device_process_data("Section Control State", static_cast(isobus::DataDescriptionIndex::SectionControlState), isobus::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::TimeInterval), static_cast(ImplementDDOPObjectIDs::SectionControlState)); // Set up bin/tank retVal &= poolToPopulate->add_device_element("Product", elementCounter++, 9, isobus::task_controller_object::DeviceElementObject::Type::Bin, static_cast(ImplementDDOPObjectIDs::LiquidProduct)); retVal &= poolToPopulate->add_device_process_data("Tank Capacity", static_cast(isobus::DataDescriptionIndex::MaximumVolumeContent), static_cast(ImplementDDOPObjectIDs::VolumePresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::TimeInterval), static_cast(ImplementDDOPObjectIDs::TankCapacity)); retVal &= poolToPopulate->add_device_process_data("Tank Volume", static_cast(isobus::DataDescriptionIndex::ActualVolumeContent), static_cast(ImplementDDOPObjectIDs::VolumePresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::TimeInterval), static_cast(ImplementDDOPObjectIDs::TankVolume)); retVal &= poolToPopulate->add_device_process_data("Lifetime Total Volume", static_cast(isobus::DataDescriptionIndex::LifetimeApplicationTotalVolume), static_cast(ImplementDDOPObjectIDs::VolumePresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::Total), static_cast(ImplementDDOPObjectIDs::LifetimeApplicationVolumeTotal)); - retVal &= poolToPopulate->add_device_process_data("Rx Control State", static_cast(isobus::DataDescriptionIndex::PrescriptionControlState), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::TimeInterval), static_cast(ImplementDDOPObjectIDs::PrescriptionControlState)); + retVal &= poolToPopulate->add_device_process_data("Rx Control State", static_cast(isobus::DataDescriptionIndex::PrescriptionControlState), isobus::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::TimeInterval), static_cast(ImplementDDOPObjectIDs::PrescriptionControlState)); retVal &= poolToPopulate->add_device_process_data("Target Rate", static_cast(isobus::DataDescriptionIndex::SetpointVolumePerAreaApplicationRate), static_cast(ImplementDDOPObjectIDs::VolumePerAreaPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(ImplementDDOPObjectIDs::TargetRate)); retVal &= poolToPopulate->add_device_process_data("Actual Rate", static_cast(isobus::DataDescriptionIndex::ActualVolumePerAreaApplicationRate), static_cast(ImplementDDOPObjectIDs::VolumePerAreaPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::TimeInterval), static_cast(ImplementDDOPObjectIDs::ActualRate)); - retVal &= poolToPopulate->add_device_property("Operation Type", 3, static_cast(isobus::DataDescriptionIndex::ActualCulturalPractice), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(ImplementDDOPObjectIDs::ActualCulturalPractice)); + retVal &= poolToPopulate->add_device_property("Operation Type", 3, static_cast(isobus::DataDescriptionIndex::ActualCulturalPractice), isobus::NULL_OBJECT_ID, static_cast(ImplementDDOPObjectIDs::ActualCulturalPractice)); // Set up sections for section control // Using 7 ft sections @@ -130,8 +131,8 @@ bool SectionControlImplementSimulator::create_ddop(std::shared_ptradd_device_process_data("Actual Work State 1-16", static_cast(isobus::DataDescriptionIndex::ActualCondensedWorkState1_16) + (sectionCounter / NUMBER_SECTIONS_PER_CONDENSED_MESSAGE), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(ImplementDDOPObjectIDs::ActualCondensedWorkingState1To16) + (sectionCounter / NUMBER_SECTIONS_PER_CONDENSED_MESSAGE)); - retVal &= poolToPopulate->add_device_process_data("Setpoint Work State 1-16", static_cast(isobus::DataDescriptionIndex::SetpointCondensedWorkState1_16) + (sectionCounter / NUMBER_SECTIONS_PER_CONDENSED_MESSAGE), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(ImplementDDOPObjectIDs::SetpointCondensedWorkingState1To16) + (sectionCounter / NUMBER_SECTIONS_PER_CONDENSED_MESSAGE)); + retVal &= poolToPopulate->add_device_process_data("Actual Work State 1-16", static_cast(isobus::DataDescriptionIndex::ActualCondensedWorkState1_16) + (sectionCounter / NUMBER_SECTIONS_PER_CONDENSED_MESSAGE), isobus::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(ImplementDDOPObjectIDs::ActualCondensedWorkingState1To16) + (sectionCounter / NUMBER_SECTIONS_PER_CONDENSED_MESSAGE)); + retVal &= poolToPopulate->add_device_process_data("Setpoint Work State 1-16", static_cast(isobus::DataDescriptionIndex::SetpointCondensedWorkState1_16) + (sectionCounter / NUMBER_SECTIONS_PER_CONDENSED_MESSAGE), isobus::NULL_OBJECT_ID, static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable) | static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(isobus::task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(ImplementDDOPObjectIDs::SetpointCondensedWorkingState1To16) + (sectionCounter / NUMBER_SECTIONS_PER_CONDENSED_MESSAGE)); sectionCounter += NUMBER_SECTIONS_PER_CONDENSED_MESSAGE; } diff --git a/isobus/include/isobus/isobus/can_constants.hpp b/isobus/include/isobus/isobus/can_constants.hpp index 119957c8..d1b4772b 100644 --- a/isobus/include/isobus/isobus/can_constants.hpp +++ b/isobus/include/isobus/isobus/can_constants.hpp @@ -19,6 +19,7 @@ namespace isobus constexpr std::uint8_t BROADCAST_CAN_ADDRESS = 0xFF; ///< The global/broadcast CAN address constexpr std::uint8_t CAN_DATA_LENGTH = 8; ///< The length of a classical CAN frame constexpr std::uint32_t CAN_PORT_MAXIMUM = 4; ///< An arbitrary limit for memory consumption + constexpr std::uint16_t NULL_OBJECT_ID = 65535; ///< Special ID used to indicate no object } diff --git a/isobus/include/isobus/isobus/can_message.hpp b/isobus/include/isobus/isobus/can_message.hpp index fa783a58..853ccf9b 100644 --- a/isobus/include/isobus/isobus/can_message.hpp +++ b/isobus/include/isobus/isobus/can_message.hpp @@ -100,6 +100,11 @@ namespace isobus /// @returns True if the message is destined for the control function, false otherwise bool is_destination(std::shared_ptr controlFunction) const; + /// @brief Returns whether the message is originated from the control function. + /// @param[in] controlFunction The control function to check + /// @returns True if the message is originated from the control function, false otherwise + bool is_source(std::shared_ptr controlFunction) const; + /// @brief Returns the identifier of the message /// @returns The identifier of the message CANIdentifier get_identifier() const; diff --git a/isobus/include/isobus/isobus/isobus_task_controller_client_objects.hpp b/isobus/include/isobus/isobus/isobus_task_controller_client_objects.hpp index 79c2a945..8133beb7 100644 --- a/isobus/include/isobus/isobus/isobus_task_controller_client_objects.hpp +++ b/isobus/include/isobus/isobus/isobus_task_controller_client_objects.hpp @@ -72,9 +72,6 @@ namespace isobus /// @brief The max allowable "valid" object ID static constexpr std::uint16_t MAX_OBJECT_ID = 65534; - /// @brief Special ID used to indicate no object - static constexpr std::uint16_t NULL_OBJECT_ID = 65535; - /// @brief Defines the max length of a designator (in bytes) static constexpr std::size_t MAX_DESIGNATOR_LENGTH = 128; diff --git a/isobus/include/isobus/isobus/isobus_virtual_terminal_client.hpp b/isobus/include/isobus/isobus/isobus_virtual_terminal_client.hpp index a808aff1..78a610bf 100644 --- a/isobus/include/isobus/isobus/isobus_virtual_terminal_client.hpp +++ b/isobus/include/isobus/isobus/isobus_virtual_terminal_client.hpp @@ -372,8 +372,6 @@ namespace isobus AuxiliaryTypeTwoFunctionType functionType; ///< The type of function }; - static constexpr std::uint16_t NULL_OBJECT_ID = 0xFFFF; ///< The NULL Object ID, usually drawn as blank space - /// @brief The constructor for a VirtualTerminalClient /// @param[in] partner The VT server control function /// @param[in] clientSource The internal control function to communicate from 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 0fe883c3..d1cd77de 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 @@ -10,9 +10,11 @@ #ifndef ISOBUS_VIRTUAL_TERMINAL_CLIENT_STATE_TRACKER_HPP #define ISOBUS_VIRTUAL_TERMINAL_CLIENT_STATE_TRACKER_HPP +#include "isobus/isobus/can_constants.hpp" #include "isobus/isobus/can_control_function.hpp" #include "isobus/isobus/can_message.hpp" +#include #include #include @@ -57,6 +59,18 @@ namespace isobus /// @return The data/alarm mask currently active on the server for this client. std::uint16_t get_active_mask() const; + /// @brief Get the history of data/alarm masks that were active on the server for this client. + /// @return The history of data/alarm masks that were active on the server for this client. + const std::deque &get_mask_history() const; + + /// @brief Get the maximum size of the data/alarm mask history. + /// @return The maximum size of the data/alarm mask history. + std::size_t get_max_mask_history_size() const; + + /// @brief Sets the maximum size of the data/alarm mask history (default: 100) + /// @param[in] size The maximum size of the data/alarm mask history. + void set_max_mask_history_size(std::size_t size); + /// @brief Adds a data/alarm mask to track the soft key mask for. /// @param[in] dataOrAlarmMaskId The data/alarm mask to track the soft key mask for. /// @param[in] initialSoftKeyMaskId The initial soft key mask to associate with the data/alarm mask. @@ -81,6 +95,7 @@ namespace isobus 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. //! TODO: std::map shownStates; ///< Holds the 'hide/show' state of tracked objects. //! TODO: std::map enabledStates; ///< Holds the 'enable/disable' state of tracked objects. @@ -96,8 +111,10 @@ namespace isobus //! TODO: add font attribute state //! TODO: add line attribute state //! TODO: add fill attribute state - std::uint16_t activeDataOrAlarmMask; ///< Holds the data/alarm mask currently visible on the server for this client. - std::uint8_t activeWorkingSetAddress; ///< Holds the address of the control function that currently has it's working set active on the server. + std::uint16_t activeDataOrAlarmMask = NULL_OBJECT_ID; ///< Holds the data/alarm mask currently visible on the server for this client. + std::deque dataAndAlarmMaskHistory; ///< Holds the history of data/alarm masks that were active on the server for this client. + std::size_t maxDataAndAlarmMaskHistorySize = 100; ///< Holds the maximum size of the data/alarm mask history. + 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. //! TODO: std::map> attributeStates; ///< Holds the 'attribute' state of tracked objects. //! TODO: std::map alarmMaskPrioritiesStates; ///< Holds the 'alarm mask priority' state of tracked objects. @@ -110,14 +127,26 @@ namespace isobus //! TODO: std::uint16_t currentColourMap; ///< Holds the current colour map/palette object. private: - /// @brief Processes a received message. - /// @param[in] message The received message. + /// @brief Cache a mask as the active mask on the server. + /// @param[in] maskId The mask to cache as the active mask on the server. + void cache_active_mask(std::uint16_t maskId); + + /// @brief Processes a received or transmitted message. + /// @param[in] message The message to process. /// @param[in] parentPointer The pointer to the parent object, which should be the VirtualTerminalClientStateTracker. - static void process_rx_message(const CANMessage &message, void *parentPointer); + static void process_rx_or_tx_message(const CANMessage &message, void *parentPointer); + + /// @brief Processes a status message from a VT server. + /// @param[in] message The message to process. + void process_status_message(const CANMessage &message); + + /// @brief Processes a VT->ECU message received by any client, sent from the connected server. + /// @param[in] message The message to process. + void process_message_from_connected_server(const CANMessage &message); - /// @brief Processes a received message. - /// @param[in] message The received message. - void process_rx_message(const CANMessage &message); + /// @brief Processes a ECU->VT message received by the connected server, sent from any control function. + /// @param[in] message The message to process. + void process_message_to_connected_server(const CANMessage &message); }; } // namespace isobus diff --git a/isobus/include/isobus/isobus/isobus_virtual_terminal_objects.hpp b/isobus/include/isobus/isobus/isobus_virtual_terminal_objects.hpp index 7111de5a..3707b287 100644 --- a/isobus/include/isobus/isobus/isobus_virtual_terminal_objects.hpp +++ b/isobus/include/isobus/isobus/isobus_virtual_terminal_objects.hpp @@ -178,8 +178,6 @@ namespace isobus std::array colourTable; ///< Colour table data. Associates VT colour index with RGB value. }; - static constexpr std::uint16_t NULL_OBJECT_ID = 0xFFFF; ///< The NULL Object ID, usually drawn as blank space - /// @brief Generic VT object base class class VTObject { diff --git a/isobus/src/can_message.cpp b/isobus/src/can_message.cpp index c0b61da1..30b2b016 100644 --- a/isobus/src/can_message.cpp +++ b/isobus/src/can_message.cpp @@ -69,6 +69,11 @@ namespace isobus return has_valid_destination_control_function() && destination == controlFunction; } + bool CANMessage::is_source(std::shared_ptr controlFunction) const + { + return has_valid_source_control_function() && source == controlFunction; + } + CANIdentifier CANMessage::get_identifier() const { return identifier; diff --git a/isobus/src/isobus_device_descriptor_object_pool.cpp b/isobus/src/isobus_device_descriptor_object_pool.cpp index c25a351a..4d37dccd 100644 --- a/isobus/src/isobus_device_descriptor_object_pool.cpp +++ b/isobus/src/isobus_device_descriptor_object_pool.cpp @@ -8,6 +8,7 @@ //================================================================================================ #include "isobus/isobus/isobus_device_descriptor_object_pool.hpp" +#include "isobus/isobus/can_constants.hpp" #include "isobus/isobus/can_stack_logger.hpp" #include "isobus/utility/platform_endianness.hpp" #include "isobus/utility/to_string.hpp" @@ -1070,7 +1071,7 @@ namespace isobus { // Process parent object auto currentDeviceElement = reinterpret_cast(currentObject.get()); - if (task_controller_object::Object::NULL_OBJECT_ID != currentDeviceElement->get_parent_object()) + if (NULL_OBJECT_ID != currentDeviceElement->get_parent_object()) { auto parent = get_object_by_id(currentDeviceElement->get_parent_object()); if (nullptr != parent.get()) @@ -1143,7 +1144,7 @@ namespace isobus { auto currentProcessData = reinterpret_cast(currentObject.get()); - if (task_controller_object::Object::NULL_OBJECT_ID != currentProcessData->get_device_value_presentation_object_id()) + if (NULL_OBJECT_ID != currentProcessData->get_device_value_presentation_object_id()) { auto child = get_object_by_id(currentProcessData->get_device_value_presentation_object_id()); if (nullptr == child.get()) @@ -1171,7 +1172,7 @@ namespace isobus { auto currentProperty = reinterpret_cast(currentObject.get()); - if (task_controller_object::Object::NULL_OBJECT_ID != currentProperty->get_device_value_presentation_object_id()) + if (NULL_OBJECT_ID != currentProperty->get_device_value_presentation_object_id()) { auto child = get_object_by_id(currentProperty->get_device_value_presentation_object_id()); if (nullptr == child.get()) @@ -1214,7 +1215,7 @@ namespace isobus { bool retVal = true; - if ((0 != uniqueID) && (task_controller_object::Object::NULL_OBJECT_ID != uniqueID)) + if ((0 != uniqueID) && (NULL_OBJECT_ID != uniqueID)) { for (auto ¤tObject : objectList) { diff --git a/isobus/src/isobus_task_controller_client_objects.cpp b/isobus/src/isobus_task_controller_client_objects.cpp index b6cf47ba..38c2c8a2 100644 --- a/isobus/src/isobus_task_controller_client_objects.cpp +++ b/isobus/src/isobus_task_controller_client_objects.cpp @@ -8,6 +8,7 @@ //================================================================================================ #include "isobus/isobus/isobus_task_controller_client_objects.hpp" +#include "isobus/isobus/can_constants.hpp" #include "isobus/utility/platform_endianness.hpp" #include diff --git a/isobus/src/isobus_virtual_terminal_client.cpp b/isobus/src/isobus_virtual_terminal_client.cpp index f6d83aef..6130462b 100644 --- a/isobus/src/isobus_virtual_terminal_client.cpp +++ b/isobus/src/isobus_virtual_terminal_client.cpp @@ -4464,7 +4464,7 @@ namespace isobus if (!get_is_connected()) { - CANStackLogger::error("[VT]: Cannot send command, not connected"); + CANStackLogger::warn("[VT]: Cannot send command, not connected"); return false; } @@ -4486,7 +4486,7 @@ namespace isobus return false; } - if (send_command(data)) + if (get_is_connected() && send_command(data)) { return true; } @@ -4528,6 +4528,10 @@ namespace isobus void VirtualTerminalClient::process_command_queue() { + if (!get_is_connected()) + { + return; + } #if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO std::lock_guard lock(commandQueueMutex); #endif diff --git a/isobus/src/isobus_virtual_terminal_client_state_tracker.cpp b/isobus/src/isobus_virtual_terminal_client_state_tracker.cpp index 20cbc6a2..635eafa0 100644 --- a/isobus/src/isobus_virtual_terminal_client_state_tracker.cpp +++ b/isobus/src/isobus_virtual_terminal_client_state_tracker.cpp @@ -29,12 +29,16 @@ namespace isobus void VirtualTerminalClientStateTracker::initialize() { - CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast(CANLibParameterGroupNumber::VirtualTerminalToECU), process_rx_message, this); + CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast(CANLibParameterGroupNumber::VirtualTerminalToECU), process_rx_or_tx_message, this); + CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast(CANLibParameterGroupNumber::ECUtoVirtualTerminal), process_rx_or_tx_message, this); + CANNetworkManager::CANNetwork.add_global_parameter_group_number_callback(static_cast(CANLibParameterGroupNumber::VirtualTerminalToECU), process_rx_or_tx_message, this); } void VirtualTerminalClientStateTracker::terminate() { - CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast(CANLibParameterGroupNumber::VirtualTerminalToECU), process_rx_message, this); + CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast(CANLibParameterGroupNumber::VirtualTerminalToECU), process_rx_or_tx_message, this); + CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast(CANLibParameterGroupNumber::ECUtoVirtualTerminal), process_rx_or_tx_message, this); + CANNetworkManager::CANNetwork.remove_global_parameter_group_number_callback(static_cast(CANLibParameterGroupNumber::VirtualTerminalToECU), process_rx_or_tx_message, this); } void VirtualTerminalClientStateTracker::add_tracked_numeric_value(std::uint16_t objectId, std::uint32_t initialValue) @@ -75,6 +79,21 @@ namespace isobus return activeDataOrAlarmMask; } + const std::deque &VirtualTerminalClientStateTracker::get_mask_history() const + { + return dataAndAlarmMaskHistory; + } + + std::size_t VirtualTerminalClientStateTracker::get_max_mask_history_size() const + { + return maxDataAndAlarmMaskHistorySize; + } + + void VirtualTerminalClientStateTracker::set_max_mask_history_size(std::size_t size) + { + maxDataAndAlarmMaskHistorySize = size; + } + void VirtualTerminalClientStateTracker::add_tracked_soft_key_mask(std::uint16_t dataOrAlarmMaskId, std::uint16_t initialSoftKeyMaskId) { if (softKeyMasks.find(dataOrAlarmMaskId) != softKeyMasks.end()) @@ -124,83 +143,119 @@ namespace isobus return (client != nullptr) && client->get_address_valid() && (client->get_address() == activeWorkingSetAddress); } - void VirtualTerminalClientStateTracker::process_rx_message(const CANMessage &message, void *parentPointer) + void VirtualTerminalClientStateTracker::cache_active_mask(std::uint16_t maskId) { - auto *parent = static_cast(parentPointer); - parent->process_rx_message(message); + if (activeDataOrAlarmMask != maskId) + { + // Add the current active mask to the history if it is valid + if (activeDataOrAlarmMask != NULL_OBJECT_ID) + { + dataAndAlarmMaskHistory.push_front(activeDataOrAlarmMask); + if (dataAndAlarmMaskHistory.size() > maxDataAndAlarmMaskHistorySize) + { + dataAndAlarmMaskHistory.pop_back(); + } + } + // Update the active mask + activeDataOrAlarmMask = maskId; + } } - void VirtualTerminalClientStateTracker::process_rx_message(const CANMessage &message) + void VirtualTerminalClientStateTracker::process_rx_or_tx_message(const CANMessage &message, void *parentPointer) { - if (message.has_valid_source_control_function() && - message.is_destination(client) && + if ((!message.has_valid_source_control_function()) || (message.get_data_length() == 0)) + { + // We are not interested in messages without a valid source control function or without data + return; + } + + auto *parent = static_cast(parentPointer); + if (message.is_broadcast() && message.is_parameter_group_number(CANLibParameterGroupNumber::VirtualTerminalToECU) && - (message.get_data_length() >= 1)) + (message.get_uint8_at(0) == static_cast(VirtualTerminalClient::Function::VTStatusMessage))) + { + parent->process_status_message(message); + } + if (message.is_source(parent->server) && (!message.is_broadcast()) && message.is_parameter_group_number(CANLibParameterGroupNumber::VirtualTerminalToECU)) + { + parent->process_message_from_connected_server(message); + } + else if (message.is_destination(parent->server) && (!message.is_broadcast()) && message.is_parameter_group_number(CANLibParameterGroupNumber::ECUtoVirtualTerminal)) { - std::uint8_t function = message.get_uint8_at(0); - switch (function) + parent->process_message_to_connected_server(message); + } + } + + void VirtualTerminalClientStateTracker::process_status_message(const CANMessage &message) + { + if (CAN_DATA_LENGTH == message.get_data_length()) + { + activeWorkingSetAddress = message.get_uint8_at(1); + if (is_working_set_active()) { - case static_cast(VirtualTerminalClient::Function::VTStatusMessage): + server = message.get_source_control_function(); + cache_active_mask(message.get_uint16_at(2)); + if (softKeyMasks.find(activeDataOrAlarmMask) != softKeyMasks.end()) { - activeWorkingSetAddress = message.get_uint8_at(1); - if (is_working_set_active()) - { - activeDataOrAlarmMask = message.get_uint16_at(2); - if (softKeyMasks.find(activeDataOrAlarmMask) != softKeyMasks.end()) - { - std::uint16_t softKeyMask = message.get_uint16_at(4); - softKeyMasks[activeDataOrAlarmMask] = softKeyMask; - } - } + std::uint16_t softKeyMask = message.get_uint16_at(4); + softKeyMasks[activeDataOrAlarmMask] = softKeyMask; } - break; + } + } + } - case static_cast(VirtualTerminalClient::Function::ChangeActiveMaskCommand): + void VirtualTerminalClientStateTracker::process_message_from_connected_server(const CANMessage &message) + { + std::uint8_t function = message.get_uint8_at(0); + switch (function) + { + case static_cast(VirtualTerminalClient::Function::VTStatusMessage): + { + server = message.get_source_control_function(); + activeWorkingSetAddress = message.get_uint8_at(1); + if (is_working_set_active()) { - auto errorCode = message.get_uint8_at(3); - if (errorCode == 0) + cache_active_mask(message.get_uint16_at(2)); + if (softKeyMasks.find(activeDataOrAlarmMask) != softKeyMasks.end()) { - activeDataOrAlarmMask = message.get_uint16_at(1); + std::uint16_t softKeyMask = message.get_uint16_at(4); + softKeyMasks[activeDataOrAlarmMask] = softKeyMask; } } - break; + } + break; - case static_cast(VirtualTerminalClient::Function::ChangeSoftKeyMaskCommand): + case static_cast(VirtualTerminalClient::Function::ChangeActiveMaskCommand): + { + auto errorCode = message.get_uint8_at(3); + if (errorCode == 0) { - auto errorCode = message.get_uint8_at(3); - if (errorCode == 0) - { - std::uint16_t associatedMask = message.get_uint16_at(1); - std::uint16_t softKeyMask = message.get_uint16_at(4); - if (softKeyMasks.find(associatedMask) != softKeyMasks.end()) - { - softKeyMasks[associatedMask] = softKeyMask; - } - } + cache_active_mask(message.get_uint16_at(1)); } - break; + } + break; - case static_cast(VirtualTerminalClient::Function::ChangeNumericValueCommand): + case static_cast(VirtualTerminalClient::Function::ChangeSoftKeyMaskCommand): + { + auto errorCode = message.get_uint8_at(3); + if (errorCode == 0) { - if (CAN_DATA_LENGTH == message.get_data_length()) + std::uint16_t associatedMask = message.get_uint16_at(1); + std::uint16_t softKeyMask = message.get_uint16_at(4); + if (softKeyMasks.find(associatedMask) != softKeyMasks.end()) { - auto errorCode = message.get_uint8_at(3); - if (errorCode == 0) - { - std::uint16_t objectId = message.get_uint16_at(1); - if (numericValueStates.find(objectId) != numericValueStates.end()) - { - std::uint32_t value = message.get_uint32_at(4); - numericValueStates[objectId] = value; - } - } + softKeyMasks[associatedMask] = softKeyMask; } } - break; + } + break; - case static_cast(VirtualTerminalClient::Function::VTChangeNumericValueMessage): + case static_cast(VirtualTerminalClient::Function::ChangeNumericValueCommand): + { + if (CAN_DATA_LENGTH == message.get_data_length()) { - if (CAN_DATA_LENGTH == message.get_data_length()) + auto errorCode = message.get_uint8_at(3); + if (errorCode == 0) { std::uint16_t objectId = message.get_uint16_at(1); if (numericValueStates.find(objectId) != numericValueStates.end()) @@ -210,11 +265,30 @@ namespace isobus } } } - break; + } + break; - default: - break; + case static_cast(VirtualTerminalClient::Function::VTChangeNumericValueMessage): + { + if (CAN_DATA_LENGTH == message.get_data_length()) + { + std::uint16_t objectId = message.get_uint16_at(1); + if (numericValueStates.find(objectId) != numericValueStates.end()) + { + std::uint32_t value = message.get_uint32_at(4); + numericValueStates[objectId] = value; + } + } } + break; + + default: + break; } } + + void VirtualTerminalClientStateTracker::process_message_to_connected_server(const CANMessage &message) + { + //! TODO: will be used for change attribute command + } } // namespace isobus diff --git a/isobus/src/isobus_virtual_terminal_client_update_helper.cpp b/isobus/src/isobus_virtual_terminal_client_update_helper.cpp index 5d083210..0b906c78 100644 --- a/isobus/src/isobus_virtual_terminal_client_update_helper.cpp +++ b/isobus/src/isobus_virtual_terminal_client_update_helper.cpp @@ -40,7 +40,7 @@ namespace isobus } if (numericValueStates.at(object_id) == value) { - return false; + return true; } bool success = vtClient->send_change_numeric_value(object_id, value); @@ -98,7 +98,7 @@ namespace isobus } if (activeDataOrAlarmMask == dataOrAlarmMaskId) { - return false; + return true; } bool success = client->send_change_active_mask(workingSetId, dataOrAlarmMaskId); @@ -123,7 +123,7 @@ namespace isobus } if (softKeyMasks.at(maskId) == softKeyMaskId) { - return false; + return true; } bool success = client->send_change_softkey_mask(maskType, maskId, softKeyMaskId); diff --git a/test/ddop_tests.cpp b/test/ddop_tests.cpp index d6c51f86..5da4c010 100644 --- a/test/ddop_tests.cpp +++ b/test/ddop_tests.cpp @@ -1,5 +1,6 @@ #include +#include "isobus/isobus/can_constants.hpp" #include "isobus/isobus/isobus_device_descriptor_object_pool.hpp" #include "isobus/isobus/isobus_language_command_interface.hpp" #include "isobus/isobus/isobus_standard_data_description_indices.hpp" @@ -68,12 +69,12 @@ TEST(DDOP_TESTS, CreateSprayerDDOP) // Set up device EXPECT_EQ(true, testDDOP.add_device("AgIsoStack++ UnitTest", "1.0.0", "123", "I++1.0", testLanguageInterface.get_localization_raw_data(), std::vector(), 0)); EXPECT_EQ(true, testDDOP.add_device_element("Sprayer", static_cast(SprayerDDOPObjectIDs::MainDeviceElement), 0, task_controller_object::DeviceElementObject::Type::Device, static_cast(SprayerDDOPObjectIDs::MainDeviceElement))); - EXPECT_EQ(true, testDDOP.add_device_process_data("Actual Work State", static_cast(DataDescriptionIndex::ActualWorkState), task_controller_object::Object::NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::DeviceActualWorkState))); + EXPECT_EQ(true, testDDOP.add_device_process_data("Actual Work State", static_cast(DataDescriptionIndex::ActualWorkState), NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::DeviceActualWorkState))); EXPECT_EQ(true, testDDOP.add_device_value_presentation("minutes", 0, 1.0f, 1, static_cast(SprayerDDOPObjectIDs::TimePresentation))); EXPECT_EQ(true, testDDOP.add_device_element("Connector", static_cast(SprayerDDOPObjectIDs::Connector), static_cast(SprayerDDOPObjectIDs::MainDeviceElement), task_controller_object::DeviceElementObject::Type::Connector, static_cast(SprayerDDOPObjectIDs::Connector))); EXPECT_EQ(true, testDDOP.add_device_process_data("Connector X", static_cast(DataDescriptionIndex::DeviceElementOffsetX), static_cast(SprayerDDOPObjectIDs::ShortWidthPresentation), static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), 0, static_cast(SprayerDDOPObjectIDs::ConnectorXOffset))); EXPECT_EQ(true, testDDOP.add_device_process_data("Connector Y", static_cast(DataDescriptionIndex::DeviceElementOffsetY), static_cast(SprayerDDOPObjectIDs::ShortWidthPresentation), static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), 0, static_cast(SprayerDDOPObjectIDs::ConnectorYOffset))); - EXPECT_EQ(true, testDDOP.add_device_property("Type", 6, static_cast(DataDescriptionIndex::ConnectorType), task_controller_object::Object::NULL_OBJECT_ID, static_cast(SprayerDDOPObjectIDs::ConnectorType))); + EXPECT_EQ(true, testDDOP.add_device_property("Type", 6, static_cast(DataDescriptionIndex::ConnectorType), NULL_OBJECT_ID, static_cast(SprayerDDOPObjectIDs::ConnectorType))); // Set up Boom EXPECT_EQ(true, testDDOP.add_device_element("Boom", static_cast(SprayerDDOPObjectIDs::SprayBoom), 0, task_controller_object::DeviceElementObject::Type::Function, static_cast(SprayerDDOPObjectIDs::SprayBoom))); @@ -81,7 +82,7 @@ TEST(DDOP_TESTS, CreateSprayerDDOP) EXPECT_EQ(true, testDDOP.add_device_property("Offset Y", 0, static_cast(DataDescriptionIndex::DeviceElementOffsetY), static_cast(SprayerDDOPObjectIDs::ShortWidthPresentation), static_cast(SprayerDDOPObjectIDs::BoomYOffset))); EXPECT_EQ(true, testDDOP.add_device_property("Offset Z", 0, static_cast(DataDescriptionIndex::DeviceElementOffsetZ), static_cast(SprayerDDOPObjectIDs::ShortWidthPresentation), static_cast(SprayerDDOPObjectIDs::BoomZOffset))); EXPECT_EQ(true, testDDOP.add_device_process_data("Actual Working Width", static_cast(DataDescriptionIndex::ActualWorkingWidth), static_cast(SprayerDDOPObjectIDs::LongWidthPresentation), static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::ActualWorkingWidth))); - EXPECT_EQ(true, testDDOP.add_device_process_data("Setpoint Work State", static_cast(DataDescriptionIndex::SetpointWorkState), task_controller_object::Object::NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::SetpointWorkState))); + EXPECT_EQ(true, testDDOP.add_device_process_data("Setpoint Work State", static_cast(DataDescriptionIndex::SetpointWorkState), NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::SetpointWorkState))); EXPECT_EQ(true, testDDOP.add_device_process_data("Area Total", static_cast(DataDescriptionIndex::TotalArea), static_cast(SprayerDDOPObjectIDs::AreaPresentation), static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::Total), static_cast(SprayerDDOPObjectIDs::AreaTotal))); // Set up sections for section control @@ -93,8 +94,8 @@ TEST(DDOP_TESTS, CreateSprayerDDOP) EXPECT_EQ(true, testDDOP.add_device_property("Offset Y", (1067 * i) - 18288, static_cast(DataDescriptionIndex::DeviceElementOffsetY), static_cast(SprayerDDOPObjectIDs::LongWidthPresentation), static_cast(SprayerDDOPObjectIDs::Section1YOffset) + i)); EXPECT_EQ(true, testDDOP.add_device_property("Width", 2 * 1067, static_cast(DataDescriptionIndex::ActualWorkingWidth), static_cast(SprayerDDOPObjectIDs::LongWidthPresentation), static_cast(SprayerDDOPObjectIDs::Section1Width) + i)); } - EXPECT_EQ(true, testDDOP.add_device_process_data("Actual Work State 1-16", static_cast(DataDescriptionIndex::ActualCondensedWorkState1_16), task_controller_object::Object::NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::ActualCondensedWorkingState))); - EXPECT_EQ(true, testDDOP.add_device_process_data("Setpoint Work State", static_cast(DataDescriptionIndex::SetpointCondensedWorkState1_16), task_controller_object::Object::NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable) | static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::SetpointCondensedWorkingState))); + EXPECT_EQ(true, testDDOP.add_device_process_data("Actual Work State 1-16", static_cast(DataDescriptionIndex::ActualCondensedWorkState1_16), NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::ActualCondensedWorkingState))); + EXPECT_EQ(true, testDDOP.add_device_process_data("Setpoint Work State", static_cast(DataDescriptionIndex::SetpointCondensedWorkState1_16), NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable) | static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::SetpointCondensedWorkingState))); // Set up bin/tank EXPECT_EQ(true, testDDOP.add_device_element("Product", static_cast(SprayerDDOPObjectIDs::LiquidProduct), static_cast(SprayerDDOPObjectIDs::SprayBoom), task_controller_object::DeviceElementObject::Type::Bin, static_cast(SprayerDDOPObjectIDs::LiquidProduct))); @@ -392,7 +393,7 @@ TEST(DDOP_TESTS, ProcessDataTests) EXPECT_EQ(true, testDDOPVersion3.add_device("AgIsoStack++ UnitTest", "1.0.0", "123", "I++1.0", testLanguageInterface.get_localization_raw_data(), std::vector(), 0)); EXPECT_EQ(true, testDDOPVersion3.add_device_element("Sprayer", static_cast(SprayerDDOPObjectIDs::MainDeviceElement), 0, task_controller_object::DeviceElementObject::Type::Device, static_cast(SprayerDDOPObjectIDs::MainDeviceElement))); - EXPECT_EQ(true, testDDOPVersion3.add_device_process_data("This is a very long designator that should get truncated", static_cast(DataDescriptionIndex::ActualWorkState), task_controller_object::Object::NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::DeviceActualWorkState))); + EXPECT_EQ(true, testDDOPVersion3.add_device_process_data("This is a very long designator that should get truncated", static_cast(DataDescriptionIndex::ActualWorkState), NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::DeviceActualWorkState))); // Test that the PD Designator was truncated to 32 auto tempPD = testDDOPVersion3.get_object_by_id(static_cast(SprayerDDOPObjectIDs::DeviceActualWorkState)); @@ -401,7 +402,7 @@ TEST(DDOP_TESTS, ProcessDataTests) EXPECT_EQ(true, testDDOPVersion4.add_device("AgIsoStack++ UnitTest", "1.0.0", "123", "I++1.0", testLanguageInterface.get_localization_raw_data(), std::vector(), 0)); EXPECT_EQ(true, testDDOPVersion4.add_device_element("Sprayer", static_cast(SprayerDDOPObjectIDs::MainDeviceElement), 0, task_controller_object::DeviceElementObject::Type::Device, static_cast(SprayerDDOPObjectIDs::MainDeviceElement))); - EXPECT_EQ(true, testDDOPVersion4.add_device_process_data("This is an even longer designator that should get truncated ideally to 128 characters in length but in reality not very many TCs will support this kind of long designator", static_cast(DataDescriptionIndex::ActualWorkState), task_controller_object::Object::NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::DeviceActualWorkState))); + EXPECT_EQ(true, testDDOPVersion4.add_device_process_data("This is an even longer designator that should get truncated ideally to 128 characters in length but in reality not very many TCs will support this kind of long designator", static_cast(DataDescriptionIndex::ActualWorkState), NULL_OBJECT_ID, static_cast(task_controller_object::DeviceProcessDataObject::PropertiesBit::MemberOfDefaultSet), static_cast(task_controller_object::DeviceProcessDataObject::AvailableTriggerMethods::OnChange), static_cast(SprayerDDOPObjectIDs::DeviceActualWorkState))); // Version 4+ designators can be 128 long, mostly for utf-8 support, not ascii, but testing it with chars tempPD = testDDOPVersion4.get_object_by_id(static_cast(SprayerDDOPObjectIDs::DeviceActualWorkState)); @@ -437,7 +438,7 @@ TEST(DDOP_TESTS, PropertyTests) EXPECT_EQ(true, testDDOPVersion3.add_device_element("Connector", 2, static_cast(SprayerDDOPObjectIDs::MainDeviceElement), isobus::task_controller_object::DeviceElementObject::Type::Connector, static_cast(SprayerDDOPObjectIDs::Connector))); EXPECT_EQ(true, testDDOPVersion3.add_device_process_data("Connector X", static_cast(isobus::DataDescriptionIndex::DeviceElementOffsetX), static_cast(SprayerDDOPObjectIDs::ShortWidthPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), 0, static_cast(SprayerDDOPObjectIDs::ConnectorXOffset))); EXPECT_EQ(true, testDDOPVersion3.add_device_process_data("Connector Y", static_cast(isobus::DataDescriptionIndex::DeviceElementOffsetY), static_cast(SprayerDDOPObjectIDs::ShortWidthPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), 0, static_cast(SprayerDDOPObjectIDs::ConnectorYOffset))); - EXPECT_EQ(true, testDDOPVersion3.add_device_property("Type123456789123456789123456789000111222333", 9, static_cast(isobus::DataDescriptionIndex::ConnectorType), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(SprayerDDOPObjectIDs::ConnectorType))); + EXPECT_EQ(true, testDDOPVersion3.add_device_property("Type123456789123456789123456789000111222333", 9, static_cast(isobus::DataDescriptionIndex::ConnectorType), isobus::NULL_OBJECT_ID, static_cast(SprayerDDOPObjectIDs::ConnectorType))); auto tempProperty = testDDOPVersion3.get_object_by_id(static_cast(SprayerDDOPObjectIDs::ConnectorType)); ASSERT_NE(nullptr, tempProperty); @@ -452,7 +453,7 @@ TEST(DDOP_TESTS, PropertyTests) EXPECT_EQ(true, testDDOPVersion4.add_device_element("Connector", 2, static_cast(SprayerDDOPObjectIDs::MainDeviceElement), isobus::task_controller_object::DeviceElementObject::Type::Connector, static_cast(SprayerDDOPObjectIDs::Connector))); EXPECT_EQ(true, testDDOPVersion4.add_device_process_data("Connector X", static_cast(isobus::DataDescriptionIndex::DeviceElementOffsetX), static_cast(SprayerDDOPObjectIDs::ShortWidthPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), 0, static_cast(SprayerDDOPObjectIDs::ConnectorXOffset))); EXPECT_EQ(true, testDDOPVersion4.add_device_process_data("Connector Y", static_cast(isobus::DataDescriptionIndex::DeviceElementOffsetY), static_cast(SprayerDDOPObjectIDs::ShortWidthPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), 0, static_cast(SprayerDDOPObjectIDs::ConnectorYOffset))); - EXPECT_EQ(true, testDDOPVersion4.add_device_property("Type123456789123456789123456789000111222333", 9, static_cast(isobus::DataDescriptionIndex::ConnectorType), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(SprayerDDOPObjectIDs::ConnectorType))); + EXPECT_EQ(true, testDDOPVersion4.add_device_property("Type123456789123456789123456789000111222333", 9, static_cast(isobus::DataDescriptionIndex::ConnectorType), isobus::NULL_OBJECT_ID, static_cast(SprayerDDOPObjectIDs::ConnectorType))); tempProperty = testDDOPVersion4.get_object_by_id(static_cast(SprayerDDOPObjectIDs::ConnectorType)); ASSERT_NE(nullptr, tempProperty); @@ -464,7 +465,7 @@ TEST(DDOP_TESTS, PropertyTests) EXPECT_EQ(true, testDDOPVersion4_2.add_device_element("Connector", 2, static_cast(SprayerDDOPObjectIDs::MainDeviceElement), isobus::task_controller_object::DeviceElementObject::Type::Connector, static_cast(SprayerDDOPObjectIDs::Connector))); EXPECT_EQ(true, testDDOPVersion4_2.add_device_process_data("Connector X", static_cast(isobus::DataDescriptionIndex::DeviceElementOffsetX), static_cast(SprayerDDOPObjectIDs::ShortWidthPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), 0, static_cast(SprayerDDOPObjectIDs::ConnectorXOffset))); EXPECT_EQ(true, testDDOPVersion4_2.add_device_process_data("Connector Y", static_cast(isobus::DataDescriptionIndex::DeviceElementOffsetY), static_cast(SprayerDDOPObjectIDs::ShortWidthPresentation), static_cast(isobus::task_controller_object::DeviceProcessDataObject::PropertiesBit::Settable), 0, static_cast(SprayerDDOPObjectIDs::ConnectorYOffset))); - EXPECT_EQ(true, testDDOPVersion4_2.add_device_property("Type123456789123456789123456789000111222333aksjdhflkajhdfasdfasdfasdfasdfasdfasdfiouhsidlfhalksjdhlkajshdflkasdfhlhasdfhalksjdflkasjhflkjashdfl", 9, static_cast(isobus::DataDescriptionIndex::ConnectorType), isobus::task_controller_object::Object::NULL_OBJECT_ID, static_cast(SprayerDDOPObjectIDs::ConnectorType))); + EXPECT_EQ(true, testDDOPVersion4_2.add_device_property("Type123456789123456789123456789000111222333aksjdhflkajhdfasdfasdfasdfasdfasdfasdfiouhsidlfhalksjdhlkajshdflkasdfhlhasdfhalksjdflkasjhflkjashdfl", 9, static_cast(isobus::DataDescriptionIndex::ConnectorType), isobus::NULL_OBJECT_ID, static_cast(SprayerDDOPObjectIDs::ConnectorType))); tempProperty = testDDOPVersion4_2.get_object_by_id(static_cast(SprayerDDOPObjectIDs::ConnectorType)); ASSERT_NE(nullptr, tempProperty); diff --git a/test/vt_client_tests.cpp b/test/vt_client_tests.cpp index 400d889f..f0f6b6d9 100644 --- a/test/vt_client_tests.cpp +++ b/test/vt_client_tests.cpp @@ -148,7 +148,6 @@ TEST(VIRTUAL_TERMINAL_TESTS, VTStatusMessage) DerivedTestVTClient clientUnderTest(vtPartner, internalECU); - static constexpr std::uint16_t NULL_OBJECT_ID = isobus::VirtualTerminalClient::NULL_OBJECT_ID; EXPECT_EQ(NULL_OBJECT_ID, clientUnderTest.get_visible_data_mask()); EXPECT_EQ(NULL_OBJECT_ID, clientUnderTest.get_visible_soft_key_mask());