From 5f3df7d992b1dbbc9daddd5f9dce6d12756cd021 Mon Sep 17 00:00:00 2001 From: Adrian Del Grosso <10929341+ad3154@users.noreply.github.com> Date: Thu, 9 May 2024 23:45:29 -0500 Subject: [PATCH] [VT]: Add VT server implementation of change polygon point and delete object pool Added the ability to change output polygons' point information in the VT objects. Added VT server support for change polygon point messages. Added VT server support for delete object pool messages. --- .../isobus_virtual_terminal_objects.hpp | 7 ++ .../isobus/isobus_virtual_terminal_server.hpp | 37 ++++++ ...al_terminal_server_managed_working_set.hpp | 10 ++ .../src/isobus_virtual_terminal_objects.cpp | 13 +++ isobus/src/isobus_virtual_terminal_server.cpp | 108 ++++++++++++++++++ ...al_terminal_server_managed_working_set.cpp | 10 ++ 6 files changed, 185 insertions(+) diff --git a/isobus/include/isobus/isobus/isobus_virtual_terminal_objects.hpp b/isobus/include/isobus/isobus/isobus_virtual_terminal_objects.hpp index 566914468..7171919f8 100644 --- a/isobus/include/isobus/isobus/isobus_virtual_terminal_objects.hpp +++ b/isobus/include/isobus/isobus/isobus_virtual_terminal_objects.hpp @@ -2506,6 +2506,13 @@ namespace isobus /// @returns A point in the polygon by index, or zeros if the index is out of range. PolygonPoint get_point(std::uint8_t index); + /// @brief Changes a polygon point by index + /// @param[in] index The point index to modify + /// @param[in] x The new X position of the point, relative to the top left corner of the polygon + /// @param[in] y The new Y position of the point, relative to the top left corner of the polygon + /// @returns True if the point was modified, false if the index was out of range + bool change_point(std::uint8_t index, std::uint16_t x, std::uint16_t y); + /// @brief Returns the polygon type of this object /// @returns The polygon type of this object PolygonType get_type() const; diff --git a/isobus/include/isobus/isobus/isobus_virtual_terminal_server.hpp b/isobus/include/isobus/isobus/isobus_virtual_terminal_server.hpp index 01af6a08e..0be9b2e9e 100644 --- a/isobus/include/isobus/isobus/isobus_virtual_terminal_server.hpp +++ b/isobus/include/isobus/isobus/isobus_virtual_terminal_server.hpp @@ -171,6 +171,16 @@ namespace isobus /// @returns True if all relevant object pools were deleted from VT non-volatile storage, otherwise false. virtual bool delete_all_versions(NAME clientNAME) = 0; + /// @brief This function is called when the client wants the server to deactivate its object pool. + /// You should treat this as a disconnection by the client, as it may be moving to another VT. + /// @attention This does not mean to delete the pool from non-volatile memory!!! This only deactivates the active pool. + /// @details This command is used to delete the entire object pool of this Working Set from volatile storage. + /// This command can be used by an implement when it wants to move its object pool to another VT, + /// or when it is shutting down or during the development of object pools. + /// @param[in] clientNAME The NAME of the client that is requesting deletion + /// @returns True if the client's active object pool was deactivated and removed from volatile storage, otherwise false. + virtual bool delete_object_pool(NAME clientNAME) = 0; + //------------ Optional functions you can override -------------------- virtual VirtualTerminalBase::GraphicMode get_graphic_mode() const; virtual std::uint8_t get_powerup_time() const; @@ -345,6 +355,20 @@ namespace isobus ObjectIsOpenedForEdit = 2 // VT version 4 and later }; + /// @brief Enumerates the bit indices of the error fields that can be set in a change polygon point response + enum class ChangePolygonPointErrorBit : std::uint8_t + { + InvalidObjectID = 0, + InvalidPointIndex = 1, + AnyOtherError = 2 + }; + + enum class DeleteObjectPoolErrorBit : std::uint8_t + { + DeletionError = 0, + AnyOtherError = 8 + }; + /// @brief Checks to see if the message should be listened to based on /// what the message is, and if the client has sent the proper working set master message bool check_if_source_is_managed(const CANMessage &message); @@ -454,6 +478,13 @@ namespace isobus /// @returns true if the message was sent, otherwise false bool send_change_numeric_value_response(std::uint16_t objectID, std::uint8_t errorBitfield, std::uint32_t value, std::shared_ptr destination); + /// @brief Sends a response to a change polygon point command + /// @param[in] objectID The object ID of the modified polygon + /// @param[in] errorBitfield An error bitfield + /// @param[in] destination The control function to send the message to + /// @returns true if the message was sent, otherwise false + bool send_change_polygon_point_response(std::uint16_t objectID, std::uint8_t errorBitfield, std::shared_ptr destination); + /// @brief Sends a response to a change size command /// @param[in] objectID The object ID for the object whose size was meant to be changed /// @param[in] errorBitfield An error bitfield @@ -482,6 +513,12 @@ namespace isobus /// @returns True if the message was sent, otherwise false bool send_delete_version_response(std::uint8_t errorBitfield, std::shared_ptr destination) const; + /// @brief Sends a response to a delete object pool command + /// @param[in] errorBitfield An error bitfield to report back to the client + /// @param[in] destination The control function to send the message to + /// @returns True if the message was sent, otherwise false + bool send_delete_object_pool_response(std::uint8_t errorBitfield, std::shared_ptr destination) const; + /// @brief Sends a response to the enable/disable object command /// @param[in] objectID The object ID for the object /// @param[in] errorBitfield An error bitfield diff --git a/isobus/include/isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp b/isobus/include/isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp index 07b708d3f..64b9b1c38 100644 --- a/isobus/include/isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp +++ b/isobus/include/isobus/isobus/isobus_virtual_terminal_server_managed_working_set.hpp @@ -120,6 +120,15 @@ namespace isobus /// @returns The timestamp for when we received the last auxiliary input maintenance message std::uint32_t get_auxiliary_input_maintenance_timestamp_ms() const; + /// @brief Marks the working set for deletion/deactivation by the server. + /// The server will call this when object pool deletion is requested for this working set + /// by the appropriate working set master. + void request_deletion(); + + /// @brief Returns if the server has marked this working set for deletion + /// @returns true if the working set should be deleted, otherwise false + bool is_deletion_requested() const; + private: /// @brief Adds an object to the object tree, and replaces an object of the same type /// if there's already one in the tree with the same ID. @@ -168,6 +177,7 @@ namespace isobus std::uint16_t faultingObjectID = NULL_OBJECT_ID; ///< Stores the faulting object ID to send to a client when parsing the pool fails std::uint16_t focusedObject = NULL_OBJECT_ID; ///< Stores the object ID of the currently focused object bool wasLoadedFromNonVolatileMemory = false; ///< Used to tell the server how this object pool was obtained + bool workingSetDeletionRequested = false; }; } // namespace isobus diff --git a/isobus/src/isobus_virtual_terminal_objects.cpp b/isobus/src/isobus_virtual_terminal_objects.cpp index 0028c6d6c..1671263d5 100644 --- a/isobus/src/isobus_virtual_terminal_objects.cpp +++ b/isobus/src/isobus_virtual_terminal_objects.cpp @@ -4933,6 +4933,19 @@ namespace isobus return retVal; } + bool OutputPolygon::change_point(std::uint8_t index, std::uint16_t x, std::uint16_t y) + { + bool retVal = false; + + if (index < pointList.size()) + { + pointList.at(index).xValue = x; + pointList.at(index).yValue = y; + retVal = true; + } + return retVal; + } + OutputPolygon::PolygonType OutputPolygon::get_type() const { return static_cast(polygonType); diff --git a/isobus/src/isobus_virtual_terminal_server.cpp b/isobus/src/isobus_virtual_terminal_server.cpp index f6028273a..0464c3f17 100644 --- a/isobus/src/isobus_virtual_terminal_server.cpp +++ b/isobus/src/isobus_virtual_terminal_server.cpp @@ -1643,6 +1643,61 @@ namespace isobus } break; + case Function::DeleteObjectPoolCommand: + { + CANStackLogger::info("[VT Server]: Client %u requests deletion of object pool from volatile memory.", cf->get_control_function()->get_address()); + if (parentServer->delete_object_pool(cf->get_control_function()->get_NAME())) + { + CANStackLogger::info("[VT Server]: Client %u object pool has been deactivated.", cf->get_control_function()->get_address()); + parentServer->send_delete_object_pool_response(0, message.get_source_control_function()); + } + else + { + CANStackLogger::error("[VT Server]: Client %u object pool failed to be deactivated.", cf->get_control_function()->get_address()); + parentServer->send_delete_object_pool_response((1 << static_cast(DeleteObjectPoolErrorBit::DeletionError)), message.get_source_control_function()); + } + } + break; + + case Function::ChangePolygonPointCommand: + { + auto objectID = static_cast(static_cast(data[1]) | (static_cast(data[2]) << 8)); + const std::uint8_t polygonPointIndex = data[3]; + const std::uint16_t newXValue = static_cast(static_cast(data[4]) | (static_cast(data[5]) << 8)); + const std::uint16_t newYValue = static_cast(static_cast(data[6]) | (static_cast(data[7]) << 8)); + auto targetObject = cf->get_object_by_id(objectID); + + if (nullptr != targetObject) + { + if (VirtualTerminalObjectType::OutputPolygon == targetObject->get_object_type()) + { + auto polygon = std::static_pointer_cast(targetObject); + + if (polygon->change_point(polygonPointIndex, newXValue, newYValue)) + { + CANStackLogger::debug("[VT Server]: Client %u change polygon id %u point index %u. X = %u, Y = %u", cf->get_control_function()->get_address(), objectID, polygonPointIndex, newXValue, newYValue); + parentServer->send_change_polygon_point_response(objectID, 0, message.get_source_control_function()); + } + else + { + CANStackLogger::warn("[VT Server]: Client %u change polygon point: the point index of %u is not valid for object %u", cf->get_control_function()->get_address(), polygonPointIndex, objectID); + parentServer->send_change_polygon_point_response(objectID, (1 << static_cast(ChangePolygonPointErrorBit::InvalidPointIndex)), message.get_source_control_function()); + } + } + else + { + CANStackLogger::warn("[VT Server]: Client %u change polygon point: object id %u is not an output polygon", cf->get_control_function()->get_address(), objectID); + parentServer->send_change_polygon_point_response(objectID, (1 << static_cast(ChangePolygonPointErrorBit::AnyOtherError)), message.get_source_control_function()); + } + } + else + { + CANStackLogger::warn("[VT Server]: Client %u change polygon point: invalid object ID of %u", cf->get_control_function()->get_address(), objectID); + parentServer->send_change_polygon_point_response(objectID, (1 << static_cast(ChangePolygonPointErrorBit::InvalidObjectID)), message.get_source_control_function()); + } + } + break; + case Function::ButtonActivationMessage: case Function::SoftKeyActivationMessage: case Function::PointingEventMessage: @@ -2136,6 +2191,33 @@ namespace isobus return retVal; } + bool VirtualTerminalServer::send_change_polygon_point_response(std::uint16_t objectID, std::uint8_t errorBitfield, std::shared_ptr destination) + { + bool retVal = false; + + if (nullptr != destination) + { + std::array buffer; + + buffer[0] = static_cast(Function::ChangePolygonPointCommand); + buffer[1] = static_cast(objectID & 0xFF); + buffer[2] = static_cast(objectID >> 8); + buffer[3] = errorBitfield; + buffer[4] = 0xFF; + buffer[5] = 0xFF; + buffer[6] = 0xFF; + buffer[7] = 0xFF; + + retVal = CANNetworkManager::CANNetwork.send_can_message(static_cast(CANLibParameterGroupNumber::VirtualTerminalToECU), + buffer.data(), + CAN_DATA_LENGTH, + serverInternalControlFunction, + destination, + get_priority()); + } + return retVal; + } + bool VirtualTerminalServer::send_change_size_response(std::uint16_t objectID, std::uint8_t errorBitfield, std::shared_ptr destination) { bool retVal = false; @@ -2242,6 +2324,32 @@ namespace isobus return retVal; } + bool VirtualTerminalServer::send_delete_object_pool_response(std::uint8_t errorBitfield, std::shared_ptr destination) const + { + bool retVal = false; + + if (nullptr != destination) + { + const std::array buffer = { + static_cast(Function::DeleteObjectPoolCommand), + errorBitfield, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF + }; + retVal = CANNetworkManager::CANNetwork.send_can_message(static_cast(CANLibParameterGroupNumber::VirtualTerminalToECU), + buffer.data(), + CAN_DATA_LENGTH, + serverInternalControlFunction, + destination, + get_priority()); + } + return retVal; + } + bool VirtualTerminalServer::send_enable_disable_object_response(std::uint16_t objectID, std::uint8_t errorBitfield, bool value, std::shared_ptr destination) { bool retVal = false; diff --git a/isobus/src/isobus_virtual_terminal_server_managed_working_set.cpp b/isobus/src/isobus_virtual_terminal_server_managed_working_set.cpp index d16c0b322..2fd42666c 100644 --- a/isobus/src/isobus_virtual_terminal_server_managed_working_set.cpp +++ b/isobus/src/isobus_virtual_terminal_server_managed_working_set.cpp @@ -177,6 +177,16 @@ namespace isobus return auxiliaryInputMaintenanceMessageTimestamp_ms; } + void VirtualTerminalServerManagedWorkingSet::request_deletion() + { + workingSetDeletionRequested = true; + } + + bool VirtualTerminalServerManagedWorkingSet::is_deletion_requested() const + { + return workingSetDeletionRequested; + } + bool VirtualTerminalServerManagedWorkingSet::add_or_replace_object(std::shared_ptr objectToAdd) { bool retVal = false;