From fdcbb099cf8ffea819a45fe17931f916b7896f35 Mon Sep 17 00:00:00 2001 From: Michael Oborne Date: Mon, 18 Nov 2024 11:41:17 +1100 Subject: [PATCH] Example: switch example --- MissionPlanner.csproj | 6 + Plugins/example23-switch.cs | 468 ++++++++++++++++++++++++++++++++++ Plugins/example23-switch.resx | 120 +++++++++ 3 files changed, 594 insertions(+) create mode 100644 Plugins/example23-switch.cs create mode 100644 Plugins/example23-switch.resx diff --git a/MissionPlanner.csproj b/MissionPlanner.csproj index c35395037a..084c1408b4 100644 --- a/MissionPlanner.csproj +++ b/MissionPlanner.csproj @@ -391,6 +391,9 @@ Always + + Always + Always @@ -1184,4 +1187,7 @@ + + + \ No newline at end of file diff --git a/Plugins/example23-switch.cs b/Plugins/example23-switch.cs new file mode 100644 index 0000000000..115653103b --- /dev/null +++ b/Plugins/example23-switch.cs @@ -0,0 +1,468 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using MissionPlanner.Controls; +using MissionPlanner.GCSViews; +using MissionPlanner.Plugin; +using log4net; +using System.Linq; +using DeviceProgramming; +using System.Threading; +using Xamarin.Forms.PlatformConfiguration; + +//loadassembly: DeviceProgramming +//loadassembly: log4net + +namespace MissionPlanner.plugins +{ + public class ConfigSwitch : UserControl, IActivate + { + private readonly static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + public struct Command + { + public byte phyaddress; + public byte register; + public byte highbyte; + public byte lowbyte; + } + + const ushort CommandStart = 0x55aa; + List CommandList = new List(); + private TableLayoutPanel tableLayoutPanel1; + const ushort CommandEnd = 0xaa55; + + public enum phyaddress + { + cos = 21, // class of service + EEE = 22, // Energy Efficient Ethernet + vlan = 23, // Virtual Local Area Network + } + + /// + /// Initializes the ConfigPayload control with a checklist of available payload selections. + /// + public ConfigSwitch() + { + InitializeComponent(); + } + + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 8; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 12.5F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 12.5F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 12.5F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 12.5F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 12.5F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 12.5F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 12.5F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 12.5F)); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 13; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(596, 322); + this.tableLayoutPanel1.TabIndex = 0; + // + // ConfigSwitch + // + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "ConfigSwitch"; + this.Size = new System.Drawing.Size(596, 322); + this.ResumeLayout(false); + + } + + /// + /// Called when the ConfigPayload view is activated. + /// + public void Activate() + { + tableLayoutPanel1.PerformLayout(); + + tableLayoutPanel1.RowCount = 13; + for (int a = 0; a <= 7; a++) + { + CheckBox cbcos = new CheckBox(); + cbcos.Text = "Port " + a + " COS Enable"; + + cbcos.Tag = (21, a, 10); + + tableLayoutPanel1.Controls.Add(cbcos); + + cbcos.CheckedChanged += (s, e) => { + var data = (ValueTuple)cbcos.Tag; + ProcessCmd(data, cbcos.Checked); + }; + + SetDefault(cbcos, false); + } + + for (int a = 0; a <= 7; a++) + { + CheckBox cbcoshp = new CheckBox(); + cbcoshp.Text = "Port " + a + " COS High Priority"; + cbcoshp.Tag = (21, a, 11); + + tableLayoutPanel1.Controls.Add(cbcoshp); + + cbcoshp.CheckedChanged += (s, e) => { + var data = (ValueTuple)cbcoshp.Tag; + ProcessCmd(data, cbcoshp.Checked); + }; + + SetDefault(cbcoshp, false); + } + + for (int a = 0; a <= 7; a++) + { + CheckBox cbeee = new CheckBox(); + + cbeee.Text = "Port " + a + " EEE Enable"; + cbeee.Tag = (22, 0, a); + + tableLayoutPanel1.Controls.Add(cbeee); + + cbeee.CheckedChanged += (s, e) => { + var data = (ValueTuple)cbeee.Tag; + ProcessCmd(data, cbeee.Checked); + }; + + SetDefault(cbeee, true); + } + + for (int a = 0; a <= 7; a++) + { + CheckBox cbtagged = new CheckBox(); + cbtagged.Checked = false; + + cbtagged.Text = "Port " + a + " VLAN Tagged"; + + cbtagged.Tag = (23, 13, a); + + tableLayoutPanel1.Controls.Add(cbtagged); + + cbtagged.CheckedChanged += (s, e) => { + var data = (ValueTuple)cbtagged.Tag; + ProcessCmd(data, cbtagged.Checked); + }; + + SetDefault(cbtagged, false); + } + + for (int port = 0; port <= 7; port++) + { + for (int a = 0; a <= 7; a++) + { + CheckBox cbvlanportmembers = new CheckBox(); + + cbvlanportmembers.Text = "Port " + port + " to Port " + a + " "; + + var high = (int)(port / 2); + var align = port % 2; + + cbvlanportmembers.Tag = (23, 15 + high, a + (align == 1 ? 8 : 0)); + + tableLayoutPanel1.Controls.Add(cbvlanportmembers); + + cbvlanportmembers.CheckedChanged += (s, e) => + { + var data = (ValueTuple)cbvlanportmembers.Tag; + ProcessCmd(data, cbvlanportmembers.Checked); + }; + + SetDefault(cbvlanportmembers, true); + } + } + + MyButton btn = new MyButton(); + btn.Text = "Apply"; + btn.Click += (s, e) => + { + Apply(); + }; + tableLayoutPanel1.Controls.Add(btn); + + MyButton btn2 = new MyButton(); + btn2.Text = "Reset"; + btn2.Click += (s, e) => + { + CommandList.Clear(); + Apply(); + }; + tableLayoutPanel1.Controls.Add(btn2); + + var buffer = new byte[100]; + var result = MainV2.comPort.device_op(1, 1, out buffer, + MAVLink.DEVICE_OP_BUSTYPE.I2C, + "", 0, 80, + 0, (byte)buffer.Length); + + if (result != 0) + { + this.Enabled = false; + return; + } + // load save config + decode(buffer); + + tableLayoutPanel1.Controls.Add(new Label() { Text = buffer.Select(a => a.ToString("X2")).Aggregate((a, b) => a + b) }); + tableLayoutPanel1.Controls.Add(new Label() { Text = "i2c2 only" }); + + // restore config + foreach (var item in tableLayoutPanel1.Controls) + { + if(item is CheckBox) + { + SetDefaultFromConfig((CheckBox)item); + } + } + } + + private void SetDefault(CheckBox cbcontrol, bool @default) + { + // set the default + cbcontrol.Checked = @default; + // create the config + var data = (ValueTuple)cbcontrol.Tag; + ProcessCmd(data, @default); + } + + private void SetDefaultFromConfig(CheckBox cbcontrol) + { + var data = (ValueTuple)cbcontrol.Tag; + // get the saved default + var newdefault = ProcessCmdGet(data); + + cbcontrol.Checked = newdefault; + } + + private void decode(byte[] buffer) + { + var work = buffer.AsSpan(); + if (buffer[0] == 0xaa && buffer[1] == 0x55) + { + // drop header + work = work.Slice(2); + while(work.Length > 3) + { + var phy = work[0]; + var reg = work[1]; + if (work[0] == 0x55 && work[1] == 0xaa) + break; + var value = (work[2] << 8) + work[3]; + + var command = new Command() { phyaddress = phy, register = reg, highbyte = work[2], lowbyte = work[3] }; + + log.InfoFormat("phy {0} {1} reg {2} value {3}", phy, (phyaddress)phy, reg, value); + + work = work.Slice(4); + + // add to list - replace existing + var item = CommandList.Where(a => a.phyaddress == command.phyaddress && a.register == command.register); + if (item.Count() > 0) + CommandList.Remove(item.First()); + + CommandList.Add(command); + } + } + } + + private void Apply() + { + var start = BitConverter.GetBytes(CommandStart); + var end = BitConverter.GetBytes(CommandEnd); + + var data = new List(); + data.AddRange(start); + + CommandList.Sort((a, b) => + { + var cmp1 = a.phyaddress.CompareTo(b.phyaddress); + var cmp2 = a.register.CompareTo(b.register); + if (cmp1 != 0) + return cmp1; + return cmp2; + }); + + CommandList.ForEach(a => data.AddRange(a.ToBytes())); + + data.AddRange(end); + + data.AddRange(BitConverter.GetBytes(0xffffffff)); + + byte count = 1; + var buffer = new byte[count]; + + var offset = 0; + foreach (var item in data) + { + again: + + // read it + var result = MainV2.comPort.device_op(1, 1, out buffer, + MAVLink.DEVICE_OP_BUSTYPE.I2C, + "", 0, 80, + (byte)offset, 1); + + if (result != 0 || buffer.Length == 0) + goto again; + + // skip already set + if (buffer[0] == item) + { + offset++; + continue; + } + + // write it + result = MainV2.comPort.device_op(1, 1, out buffer, + MAVLink.DEVICE_OP_BUSTYPE.I2C, + "", 0, 80, + (byte)offset, 0, new[] { item }); + + if (result != 0) + { + log.Error("bad i2c op " + result); + goto again; + } + + goto again; + } + } + + int SetBitTo1(int value, int position) + { + return value |= (1 << position); + } + + int SetBitTo0(int value, int position) + { + return value & ~(1 << position); + } + + bool IsBitSetTo1(int value, int position) + { + // Return whether bit at position is set to 1. + return (value & (1 << position)) != 0; + } + + bool IsBitSetTo0(int value, int position) + { + // If not 1, bit is 0. + return !IsBitSetTo1(value, position); + } + + private void ProcessCmd((int, int, int) data, bool @checked) + { + // update + if (CommandList.Any(a => a.phyaddress == data.Item1 && a.register == data.Item2)) + { + var item = CommandList.First(a => a.phyaddress == data.Item1 && a.register == data.Item2); + CommandList.Remove(item); + + var value = (item.highbyte << 8) + item.lowbyte; + + if (@checked) + value = (ushort)SetBitTo1(value, data.Item3); + else + value = (ushort)SetBitTo0(value, data.Item3); + + item.highbyte = (byte)(value >> 8); + item.lowbyte = (byte)(value & 0xff); + + CommandList.Add(item); + } + else + { + //add + var value = (ushort)((@checked ? 1 : 0) << data.Item3); + + CommandList.Add(new Command() + { + phyaddress = (byte)data.Item1, + register = (byte)data.Item2, + highbyte = (byte)(value >> 8), + lowbyte = (byte)(value & 0xff) + }); + } + } + + private bool ProcessCmdGet((int, int, int) data) + { + if (CommandList.Any(a => a.phyaddress == data.Item1 && a.register == data.Item2)) + { + var item = CommandList.First(a => a.phyaddress == data.Item1 && a.register == data.Item2); + + var value = (item.highbyte << 8) + item.lowbyte; + + var ans = IsBitSetTo1(value, data.Item3); + log.InfoFormat("ProcessCmdGet: phy {0} reg {1} value {2} bit {3} ans {4}", item.phyaddress, item.register, value, data.Item3, ans); + return ans; + } + + throw new Exception("no prior config - setdefault should have created this"); + } + + public class example23_switch : Plugin.Plugin + { + public override string Name => "CubeLan 8 port Switch"; + public override string Version => "0.1"; + public override string Author => "Michael Oborne"; + + + public override bool Init() + { + return true; + } + + public override bool Loaded() + { + // Register the ConfigPayload view on the Config tab + SoftwareConfig.AddPluginViewPage(typeof(ConfigSwitch), Name, SoftwareConfig.pageOptions.isConnected); + + return true; + } + + public override bool Exit() { return true; } + } + } +} \ No newline at end of file diff --git a/Plugins/example23-switch.resx b/Plugins/example23-switch.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/Plugins/example23-switch.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file