From 0343fa523047a63a4e248f88d04c9b34a21e6a89 Mon Sep 17 00:00:00 2001 From: Bob Long Date: Tue, 5 Nov 2024 23:01:10 +1100 Subject: [PATCH] Example22: Payload Select Config Page --- MissionPlanner.csproj | 3 + Plugins/example22-payloadconfig.cs | 265 +++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+) create mode 100644 Plugins/example22-payloadconfig.cs diff --git a/MissionPlanner.csproj b/MissionPlanner.csproj index 882b3916c8..c35395037a 100644 --- a/MissionPlanner.csproj +++ b/MissionPlanner.csproj @@ -391,6 +391,9 @@ Always + + Always + UserControl diff --git a/Plugins/example22-payloadconfig.cs b/Plugins/example22-payloadconfig.cs new file mode 100644 index 0000000000..bc1e93a807 --- /dev/null +++ b/Plugins/example22-payloadconfig.cs @@ -0,0 +1,265 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using MissionPlanner.Controls; +using MissionPlanner.GCSViews; +using MissionPlanner.Plugin; +using log4net; + +namespace MissionPlanner.plugins +{ +/// +/// This plugin adds a "Payload Selection" page to Mission Planner's Config tab. +/// It allows users to select various payload configurations, such as gimbals or cameras, +/// by checking boxes associated with each payload type. Each payload setting adjusts +/// specific parameters and reverts to defaults when unchecked. Parameter adjustments +/// are only allowed while the vehicle is disarmed. +/// +/// ### WARNING: +/// This is a simple example plugin with minimal testing and limited error handling. +/// It is recommended to review and test this code thoroughly in a safe environment +/// before relying on it in operational settings. +/// +/// ### Modifying the Plugin: +/// - To enable this plugin, add payloads to the `payloadParameters` dictionary. If +/// the dictionary is empty, the plugin will not initialize. +/// - To add new payloads, modify the `payloadParameters` dictionary with the desired +/// payload name as the key and a dictionary of parameter settings as the value. +/// - Example: Adding a new payload: +/// { "NewPayload", new Dictionary { { "PARAM_NAME", value } } } +/// - Each payload’s parameters are activated when checked and reverted to their default +/// when unchecked, if defaults exist. +/// + public class example22_payloadconfig : Plugin.Plugin + { + public override string Name => "Payload Select Page"; + public override string Version => "0.1"; + public override string Author => "Bob Long"; + + + // DEFINE YOUR PAYLOADS, AND THEIR PARAMETERS, HERE + public static readonly Dictionary> payloadParameters = new Dictionary> + { + // { + // "Gimbal", new Dictionary + // { + // { "MNT1_TYPE", 9}, // Set Mount1 Type to Scripting + // } + // }, + // { + // "Mapping Camera", new Dictionary + // { + // { "CAM_TRIGG_TYPE", 1 }, // Set trigger type to PWM + // { "SERVO9_FUNCTION", 10 }, // Set servo 9 to camera trigger + // } + // } + }; + + private CheckedListBox payloadCheckboxList; + + public override bool Init() + { + // Only initialize the plugin if payloads have been configured. + return payloadParameters.Count > 0; + } + + public override bool Loaded() + { + // Register the ConfigPayload view on the Config tab + SoftwareConfig.AddPluginViewPage(typeof(ConfigPayload), "Payload Selection", SoftwareConfig.pageOptions.isConnected | SoftwareConfig.pageOptions.gotAllParams); + + return true; + } + + public override bool Exit() { return true; } + } + + public class ConfigPayload : MyUserControl, IActivate + { + private Dictionary> payloadParameters = example22_payloadconfig.payloadParameters; + private readonly CheckedListBox payloadCheckboxList; + private readonly static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Initializes the ConfigPayload control with a checklist of available payload selections. + /// + public ConfigPayload() + { + // Initialize CheckedListBox for payload selection + payloadCheckboxList = new CheckedListBox + { + CheckOnClick = true, + Dock = DockStyle.Left, + }; + + // Add payload options as checkboxes + foreach (var payload in payloadParameters.Keys) + { + payloadCheckboxList.Items.Add(payload); + } + + // Handle check state changes + payloadCheckboxList.ItemCheck += PayloadCheckboxList_ItemCheck; + + // Add the CheckedListBox to the control + Controls.Add(payloadCheckboxList); + } + + /// + /// Called when the ConfigPayload view is activated. + /// + public void Activate() + { + UpdateCheckboxState(); + CheckArmed(); + } + + /// + /// Checks if the vehicle is armed, disables the checkbox list and warns the user if it is. + /// + private void CheckArmed() + { + payloadCheckboxList.Enabled = !MainV2.comPort.MAV.cs.armed; + if (MainV2.comPort.MAV.cs.armed) + { + CustomMessageBox.Show("The vehicle is armed. Payload selection is disabled.", "Payload Selection"); + } + } + + /// + /// Updates the checked state of each checkbox based on current parameter values. + /// If all parameters for a payload match the predefined values, the checkbox is checked. + /// + private void UpdateCheckboxState() + { + for (int i = 0; i < payloadCheckboxList.Items.Count; i++) + { + string payload = payloadCheckboxList.Items[i].ToString(); + if (IsPayloadActive(payloadParameters[payload])) + { + payloadCheckboxList.SetItemChecked(i, true); + } + } + } + + /// + /// Checks if all parameters in the vehicle match a given dictionary. + /// + /// Dictionary of parameter names and values + /// True if all parameters match, false otherwise. + private bool IsPayloadActive(Dictionary parameters) + { + foreach (var param in parameters) + { + if (!MainV2.comPort.MAV.param.ContainsKey(param.Key)) + { + log.Warn($"Parameter {param.Key} not found for comparison."); + return false; + } + if (!ParamEquality(MainV2.comPort.MAV.param[param.Key].Value, param.Value)) + { + return false; + } + } + return true; + } + + /// + /// Handles checkbox state changes, applying or reverting parameters based on the checked state. + /// + private void PayloadCheckboxList_ItemCheck(object sender, ItemCheckEventArgs e) + { + CheckArmed(); + + string payload = payloadCheckboxList.Items[e.Index].ToString(); + var parameters = payloadParameters[payload]; + + if (e.NewValue == CheckState.Checked) + { + ApplyPayloadParameters(parameters); + } + else + { + RevertParametersToDefault(parameters); + } + } + + /// + /// Applies the specified parameters. + /// + /// Dictionary of parameter names and values to set. + private void ApplyPayloadParameters(Dictionary parameters) + { + foreach (var param in parameters) + { + MainV2.comPort.setParam(param.Key, param.Value); + } + + if (CheckParamCountChanged() && parameters.Count > 1) + { + // Apply parameters again (we assume there will not be nested enable params for this plugin) + foreach (var param in parameters) + { + MainV2.comPort.setParam(param.Key, param.Value); + } + } + } + + /// + /// Checks if the parameter count has changed, which might indicate new parameters were added. + /// If so, triggers a parameter list refresh and logs the update. + /// + private bool CheckParamCountChanged() + { + if (MainV2.comPort.MAV.param.TotalReceived != MainV2.comPort.MAV.param.TotalReported) + { + CustomMessageBox.Show("The number of available parameters changed. A full param refresh will be done.", "Params"); + try + { + MainV2.comPort.getParamList(); + } + catch (Exception ex) + { + log.Error("Exception getting param list", ex); + CustomMessageBox.Show(Strings.ErrorReceivingParams, Strings.ERROR); + } + return true; + } + return false; + } + + /// + /// Reverts parameters for an unchecked payload to their default values. + /// + /// Dictionary of parameter names and expected default values. + private void RevertParametersToDefault(Dictionary parameters) + { + foreach (var param in parameters) + { + if (!MainV2.comPort.MAV.param.ContainsKey(param.Key)) + { + log.Warn($"Parameter {param.Key} missing during revert to default."); + continue; + } + if (MainV2.comPort.MAV.param[param.Key].default_value == null) + { + log.Warn($"No default value found for parameter {param.Key}"); + continue; + } + // This doesn't technically reset params if they get hidden after an enable param changes, + // but that is okay for our purposes. + MainV2.comPort.setParam(param.Key, MainV2.comPort.MAV.param[param.Key].default_value.Value); + } + + CheckParamCountChanged(); + } + + /// + /// Checks if two parameter values are equal within a small tolerance. + /// + private bool ParamEquality(double a, double b) + { + return Math.Abs(a - b) < Math.Max(1e-6, Math.Max(Math.Abs(a), Math.Abs(b)) * 1e-6); + } + } +}