diff --git a/msg/px4_msgs_old/msg/RegisterExtComponentReplyV0.msg b/msg/px4_msgs_old/msg/RegisterExtComponentReplyV0.msg new file mode 100644 index 0000000000..4495bcdb90 --- /dev/null +++ b/msg/px4_msgs_old/msg/RegisterExtComponentReplyV0.msg @@ -0,0 +1,15 @@ +uint32 MESSAGE_VERSION = 0 + +uint64 timestamp # time since system start (microseconds) + +uint64 request_id # ID from the request +char[25] name # name from the request + +uint16 px4_ros2_api_version + +bool success +int8 arming_check_id # arming check registration ID (-1 if invalid) +int8 mode_id # assigned mode ID (-1 if invalid) +int8 mode_executor_id # assigned mode executor ID (-1 if invalid) + +uint8 ORB_QUEUE_LENGTH = 2 diff --git a/msg/px4_msgs_old/msg/RegisterExtComponentRequestV0.msg b/msg/px4_msgs_old/msg/RegisterExtComponentRequestV0.msg new file mode 100644 index 0000000000..b0798705ca --- /dev/null +++ b/msg/px4_msgs_old/msg/RegisterExtComponentRequestV0.msg @@ -0,0 +1,24 @@ +# Request to register an external component + +uint32 MESSAGE_VERSION = 0 + +uint64 timestamp # time since system start (microseconds) + +uint64 request_id # ID, set this to a random value +char[25] name # either the requested mode name, or component name + +uint16 LATEST_PX4_ROS2_API_VERSION = 1 # API version compatibility. Increase this on a breaking semantic change. Changes to any message field are detected separately and do not require an API version change. + +uint16 px4_ros2_api_version # Set to LATEST_PX4_ROS2_API_VERSION + +# Components to be registered +bool register_arming_check +bool register_mode # registering a mode also requires arming_check to be set +bool register_mode_executor # registering an executor also requires a mode to be registered (which is the owned mode by the executor) + +bool enable_replace_internal_mode # set to true if an internal mode should be replaced +uint8 replace_internal_mode # vehicle_status::NAVIGATION_STATE_* +bool activate_mode_immediately # switch to the registered mode (can only be set in combination with an executor) + + +uint8 ORB_QUEUE_LENGTH = 2 diff --git a/msg/translation_node/translations/all_translations.h b/msg/translation_node/translations/all_translations.h index 1322253715..e463911482 100644 --- a/msg/translation_node/translations/all_translations.h +++ b/msg/translation_node/translations/all_translations.h @@ -12,6 +12,8 @@ #include "translation_battery_status_v1.h" #include "translation_event_v1.h" #include "translation_home_position_v1.h" +#include "translation_register_ext_component_reply_v1.h" +#include "translation_register_ext_component_request_v1.h" #include "translation_vehicle_attitude_setpoint_v1.h" #include "translation_vehicle_status_v1.h" #include "translation_vehicle_local_position_v1.h" diff --git a/msg/translation_node/translations/translation_register_ext_component_reply_v1.h b/msg/translation_node/translations/translation_register_ext_component_reply_v1.h new file mode 100644 index 0000000000..7ff61d7d97 --- /dev/null +++ b/msg/translation_node/translations/translation_register_ext_component_reply_v1.h @@ -0,0 +1,45 @@ +/**************************************************************************** + * Copyright (c) 2025 PX4 Development Team. + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************/ +#pragma once + +// Translate RegisterExtComponentReply v0 <--> v1 +#include +#include + +class RegisterExtComponentReplyV1Translation { +public: + using MessageOlder = px4_msgs_old::msg::RegisterExtComponentReplyV0; + static_assert(MessageOlder::MESSAGE_VERSION == 0); + + using MessageNewer = px4_msgs::msg::RegisterExtComponentReply; + static_assert(MessageNewer::MESSAGE_VERSION == 1); + + static constexpr const char* kTopic = "fmu/out/register_ext_component_reply"; + + static void fromOlder(const MessageOlder &msg_older, MessageNewer &msg_newer) { + msg_newer.timestamp = msg_older.timestamp; + msg_newer.request_id = msg_older.request_id; + msg_newer.name = msg_older.name; + msg_newer.px4_ros2_api_version = msg_older.px4_ros2_api_version; + msg_newer.success = msg_older.success; + msg_newer.arming_check_id = msg_older.arming_check_id; + msg_newer.mode_id = msg_older.mode_id; + msg_newer.mode_executor_id = msg_older.mode_executor_id; + msg_newer.not_user_selectable = false; + } + + static void toOlder(const MessageNewer &msg_newer, MessageOlder &msg_older) { + msg_older.timestamp = msg_newer.timestamp; + msg_older.request_id = msg_newer.request_id; + msg_older.name = msg_newer.name; + msg_older.px4_ros2_api_version = msg_newer.px4_ros2_api_version; + msg_older.success = msg_newer.success; + msg_older.arming_check_id = msg_newer.arming_check_id; + msg_older.mode_id = msg_newer.mode_id; + msg_older.mode_executor_id = msg_newer.mode_executor_id; + } +}; + +REGISTER_TOPIC_TRANSLATION_DIRECT(RegisterExtComponentReplyV1Translation); diff --git a/msg/translation_node/translations/translation_register_ext_component_request_v1.h b/msg/translation_node/translations/translation_register_ext_component_request_v1.h new file mode 100644 index 0000000000..9f90b90784 --- /dev/null +++ b/msg/translation_node/translations/translation_register_ext_component_request_v1.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * Copyright (c) 2025 PX4 Development Team. + * SPDX-License-Identifier: BSD-3-Clause + ****************************************************************************/ +#pragma once + +// Translate RegisterExtComponentRequest v0 <--> v1 +#include +#include + +class RegisterExtComponentRequestV1Translation { +public: + using MessageOlder = px4_msgs_old::msg::RegisterExtComponentRequestV0; + static_assert(MessageOlder::MESSAGE_VERSION == 0); + + using MessageNewer = px4_msgs::msg::RegisterExtComponentRequest; + static_assert(MessageNewer::MESSAGE_VERSION == 1); + + static constexpr const char* kTopic = "fmu/in/register_ext_component_request"; + + static void fromOlder(const MessageOlder &msg_older, MessageNewer &msg_newer) { + msg_newer.timestamp = msg_older.timestamp; + msg_newer.request_id = msg_older.request_id; + msg_newer.name = msg_older.name; + msg_newer.px4_ros2_api_version = msg_older.px4_ros2_api_version; + msg_newer.register_arming_check = msg_older.register_arming_check; + msg_newer.register_mode = msg_older.register_mode; + msg_newer.register_mode_executor = msg_older.register_mode_executor; + msg_newer.enable_replace_internal_mode = msg_older.enable_replace_internal_mode; + msg_newer.replace_internal_mode = msg_older.replace_internal_mode; + msg_newer.activate_mode_immediately = msg_older.activate_mode_immediately; + msg_newer.not_user_selectable = false; + } + + static void toOlder(const MessageNewer &msg_newer, MessageOlder &msg_older) { + msg_older.timestamp = msg_newer.timestamp; + msg_older.request_id = msg_newer.request_id; + msg_older.name = msg_newer.name; + msg_older.px4_ros2_api_version = msg_newer.px4_ros2_api_version; + msg_older.register_arming_check = msg_newer.register_arming_check; + msg_older.register_mode = msg_newer.register_mode; + msg_older.register_mode_executor = msg_newer.register_mode_executor; + msg_older.enable_replace_internal_mode = msg_newer.enable_replace_internal_mode; + msg_older.replace_internal_mode = msg_newer.replace_internal_mode; + msg_older.activate_mode_immediately = msg_newer.activate_mode_immediately; + } +}; + +REGISTER_TOPIC_TRANSLATION_DIRECT(RegisterExtComponentRequestV1Translation); diff --git a/msg/versioned/RegisterExtComponentReply.msg b/msg/versioned/RegisterExtComponentReply.msg index 4495bcdb90..17ff6765c9 100644 --- a/msg/versioned/RegisterExtComponentReply.msg +++ b/msg/versioned/RegisterExtComponentReply.msg @@ -1,4 +1,4 @@ -uint32 MESSAGE_VERSION = 0 +uint32 MESSAGE_VERSION = 1 uint64 timestamp # time since system start (microseconds) @@ -12,4 +12,6 @@ int8 arming_check_id # arming check registration ID (-1 if invalid) int8 mode_id # assigned mode ID (-1 if invalid) int8 mode_executor_id # assigned mode executor ID (-1 if invalid) +bool not_user_selectable # mode cannot be selected by the user + uint8 ORB_QUEUE_LENGTH = 2 diff --git a/msg/versioned/RegisterExtComponentRequest.msg b/msg/versioned/RegisterExtComponentRequest.msg index b0798705ca..3b76aef15e 100644 --- a/msg/versioned/RegisterExtComponentRequest.msg +++ b/msg/versioned/RegisterExtComponentRequest.msg @@ -1,6 +1,6 @@ # Request to register an external component -uint32 MESSAGE_VERSION = 0 +uint32 MESSAGE_VERSION = 1 uint64 timestamp # time since system start (microseconds) @@ -19,6 +19,6 @@ bool register_mode_executor # registering an executor also requires a mod bool enable_replace_internal_mode # set to true if an internal mode should be replaced uint8 replace_internal_mode # vehicle_status::NAVIGATION_STATE_* bool activate_mode_immediately # switch to the registered mode (can only be set in combination with an executor) - +bool not_user_selectable # mode cannot be selected by the user uint8 ORB_QUEUE_LENGTH = 2 diff --git a/src/modules/commander/ModeManagement.cpp b/src/modules/commander/ModeManagement.cpp index b26bb99993..d5d800f8de 100644 --- a/src/modules/commander/ModeManagement.cpp +++ b/src/modules/commander/ModeManagement.cpp @@ -232,6 +232,7 @@ void ModeManagement::checkNewRegistrations(UpdateRequest &update_request) static_assert(sizeof(request.name) == sizeof(reply.name), "size mismatch"); memcpy(reply.name, request.name, sizeof(request.name)); reply.request_id = request.request_id; + reply.not_user_selectable = request.not_user_selectable; reply.px4_ros2_api_version = register_ext_component_request_s::LATEST_PX4_ROS2_API_VERSION; // validate diff --git a/src/modules/mavlink/streams/AVAILABLE_MODES.hpp b/src/modules/mavlink/streams/AVAILABLE_MODES.hpp index c0d7730188..27e5852129 100644 --- a/src/modules/mavlink/streams/AVAILABLE_MODES.hpp +++ b/src/modules/mavlink/streams/AVAILABLE_MODES.hpp @@ -38,6 +38,7 @@ #include #include #include +#include class MavlinkStreamAvailableModes : public MavlinkStream { @@ -71,6 +72,8 @@ private: char name[sizeof(register_ext_component_reply_s::name)] {}; }; ExternalModeName *_external_mode_names{nullptr}; + uint8_t _not_user_selectable_mask{0}; + static_assert(MAX_NUM_EXTERNAL_MODES <= (sizeof(_not_user_selectable_mask) * CHAR_BIT), "Mask too small"); uORB::Subscription _vehicle_status_sub{ORB_ID(vehicle_status)}; uORB::Subscription _register_ext_component_reply_sub{ORB_ID(register_ext_component_reply)}; @@ -116,6 +119,10 @@ private: } else if (_external_mode_names) { strncpy(available_modes.mode_name, _external_mode_names[external_mode_index].name, sizeof(available_modes.mode_name)); available_modes.mode_name[sizeof(available_modes.mode_name) - 1] = '\0'; + + if ((_not_user_selectable_mask & (1 << external_mode_index)) > 0) { + available_modes.properties |= MAV_MODE_PROPERTY_NOT_USER_SELECTABLE; + } } } else { // Internal @@ -205,6 +212,13 @@ private: if (_external_mode_names && mode_index < MAX_NUM_EXTERNAL_MODES) { memcpy(_external_mode_names[mode_index].name, reply.name, sizeof(ExternalModeName::name)); + + if (reply.not_user_selectable) { + _not_user_selectable_mask |= (1 << mode_index); + + } else { + _not_user_selectable_mask &= ~(1 << mode_index); + } } dynamic_update = true;