Skip to content

Commit

Permalink
Example22: Payload Select Config Page
Browse files Browse the repository at this point in the history
  • Loading branch information
robertlong13 authored and meee1 committed Nov 7, 2024
1 parent 2fbeb9a commit 0343fa5
Show file tree
Hide file tree
Showing 2 changed files with 268 additions and 0 deletions.
3 changes: 3 additions & 0 deletions MissionPlanner.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,9 @@
<None Include="plugins\example20-multiplepositions.cs">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="plugins\example22-payloadconfig.cs">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Compile Update="Utilities\AirMarket.cs">
<SubType>UserControl</SubType>
</Compile>
Expand Down
265 changes: 265 additions & 0 deletions Plugins/example22-payloadconfig.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// 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<string, double> { { "PARAM_NAME", value } } }
/// - Each payload’s parameters are activated when checked and reverted to their default
/// when unchecked, if defaults exist.
/// </summary>
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<string, Dictionary<string, double>> payloadParameters = new Dictionary<string, Dictionary<string, double>>
{
// {
// "Gimbal", new Dictionary<string, double>
// {
// { "MNT1_TYPE", 9}, // Set Mount1 Type to Scripting
// }
// },
// {
// "Mapping Camera", new Dictionary<string, double>
// {
// { "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<string, Dictionary<string, double>> payloadParameters = example22_payloadconfig.payloadParameters;
private readonly CheckedListBox payloadCheckboxList;
private readonly static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

/// <summary>
/// Initializes the ConfigPayload control with a checklist of available payload selections.
/// </summary>
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);
}

/// <summary>
/// Called when the ConfigPayload view is activated.
/// </summary>
public void Activate()
{
UpdateCheckboxState();
CheckArmed();
}

/// <summary>
/// Checks if the vehicle is armed, disables the checkbox list and warns the user if it is.
/// </summary>
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");
}
}

/// <summary>
/// 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.
/// </summary>
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);
}
}
}

/// <summary>
/// Checks if all parameters in the vehicle match a given dictionary.
/// </summary>
/// <param name="parameters">Dictionary of parameter names and values</param>
/// <returns>True if all parameters match, false otherwise.</returns>
private bool IsPayloadActive(Dictionary<string, double> 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;
}

/// <summary>
/// Handles checkbox state changes, applying or reverting parameters based on the checked state.
/// </summary>
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);
}
}

/// <summary>
/// Applies the specified parameters.
/// </summary>
/// <param name="parameters">Dictionary of parameter names and values to set.</param>
private void ApplyPayloadParameters(Dictionary<string, double> 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);
}
}
}

/// <summary>
/// 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.
/// </summary>
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;
}

/// <summary>
/// Reverts parameters for an unchecked payload to their default values.
/// </summary>
/// <param name="parameters">Dictionary of parameter names and expected default values.</param>
private void RevertParametersToDefault(Dictionary<string, double> 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();
}

/// <summary>
/// Checks if two parameter values are equal within a small tolerance.
/// </summary>
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);
}
}
}

0 comments on commit 0343fa5

Please sign in to comment.