diff --git a/isobus/include/isobus/isobus/isobus_virtual_terminal_objects.hpp b/isobus/include/isobus/isobus/isobus_virtual_terminal_objects.hpp index 56691446..7171919f 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 01af6a08..0be9b2e9 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 07b708d3..64b9b1c3 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 0028c6d6..1671263d 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 f6028273..0464c3f1 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 d16c0b32..2fd42666 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;