diff --git a/Tools/ArdupilotMegaPlanner/3DRRadio/3DRRadio.csproj b/Tools/ArdupilotMegaPlanner/3DRRadio/3DRRadio.csproj index 7f514ee20ccca7f760c3fee1620ef728d4a774af..f326d027c5a6676801501e281bc62b5cc048d36d 100644 --- a/Tools/ArdupilotMegaPlanner/3DRRadio/3DRRadio.csproj +++ b/Tools/ArdupilotMegaPlanner/3DRRadio/3DRRadio.csproj @@ -32,20 +32,21 @@ </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PlatformTarget>x86</PlatformTarget> - <DebugSymbols>true</DebugSymbols> + <DebugSymbols>false</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\Debug\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> + <DefineConstants>DEBUG</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> <PlatformTarget>x86</PlatformTarget> - <DebugType>pdbonly</DebugType> + <DebugType>none</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release\</OutputPath> - <DefineConstants>TRACE</DefineConstants> + <DefineConstants> + </DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> @@ -195,12 +196,6 @@ <Install>true</Install> </BootstrapperPackage> </ItemGroup> - <ItemGroup> - <None Include="Resources\3dr.png" /> - </ItemGroup> - <ItemGroup> - <None Include="Resources\3dr2.png" /> - </ItemGroup> <ItemGroup> <Content Include="3dr.ico" /> <None Include="Resources\3dr3.png" /> diff --git a/Tools/ArdupilotMegaPlanner/3DRRadio/Config.resx b/Tools/ArdupilotMegaPlanner/3DRRadio/Config.resx index c2d6487d8e10e0bf986a7c1fae8bbd5bcc13e6ea..ff6e05843c3b10394f92bdc12f5acfedaa14a3f9 100644 --- a/Tools/ArdupilotMegaPlanner/3DRRadio/Config.resx +++ b/Tools/ArdupilotMegaPlanner/3DRRadio/Config.resx @@ -1518,11 +1518,8 @@ //////////////////////////////////8= </value> </data> - <data name="$this.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms"> - <value>NoControl</value> - </data> <data name="$this.Text" xml:space="preserve"> - <value>3DRRadio Config</value> + <value>3DRRadio Config 0.2</value> </data> <data name=">>$this.Name" xml:space="preserve"> <value>Config</value> diff --git a/Tools/ArdupilotMegaPlanner/3DRRadio/Program.cs b/Tools/ArdupilotMegaPlanner/3DRRadio/Program.cs index e4f207fc148a0f5c24929620476add781067e4ad..1570b6f7fdcdfdf39d9956819ca3f715212c33a0 100644 --- a/Tools/ArdupilotMegaPlanner/3DRRadio/Program.cs +++ b/Tools/ArdupilotMegaPlanner/3DRRadio/Program.cs @@ -12,7 +12,7 @@ namespace _3DRRadio /// The main entry point for the application. /// </summary> [STAThread] - static void Main() + static void Main(string[] args) { XmlConfigurator.Configure(); diff --git a/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/AssemblyInfo.cs b/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/AssemblyInfo.cs index ae9d3a35601fc2399b15958f2dc4e3af679215d7..b17a906705f980f449c7dba329e64baa87656304 100644 --- a/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/AssemblyInfo.cs +++ b/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.*")] -[assembly: AssemblyFileVersion("0.1.0.0")] +[assembly: AssemblyVersion("0.2.*")] +[assembly: AssemblyFileVersion("0.2.0.0")] diff --git a/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/Resources.Designer.cs b/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/Resources.Designer.cs index f107d01f7ade1ff550b49c3f38df3709623f17e9..3f01251d38f3953177944c955247fb35767b76fb 100644 --- a/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/Resources.Designer.cs +++ b/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/Resources.Designer.cs @@ -60,20 +60,6 @@ namespace _3DRRadio.Properties { } } - internal static System.Drawing.Bitmap _3dr { - get { - object obj = ResourceManager.GetObject("3dr", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap _3dr2 { - get { - object obj = ResourceManager.GetObject("3dr2", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - internal static System.Drawing.Bitmap _3dr3 { get { object obj = ResourceManager.GetObject("3dr3", resourceCulture); diff --git a/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/Resources.resx b/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/Resources.resx index 40514226acc3a1a20d00c8cef7ac48da95b0c4e9..572c8be44e80879b72cba9b6a58c458ba753b99c 100644 --- a/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/Resources.resx +++ b/Tools/ArdupilotMegaPlanner/3DRRadio/Properties/Resources.resx @@ -118,13 +118,6 @@ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> - <data name="3dr2" type="System.Resources.ResXFileRef, System.Windows.Forms"> - <value>..\Resources\3dr2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> - </data> - <data name="3dr" type="System.Resources.ResXFileRef, System.Windows.Forms"> - <value>..\Resources\3dr.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> - </data> - <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <data name="3dr3" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\3dr3.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> diff --git a/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj b/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj index d8d3db4b91937ac64053868adac912502e617302..b1e7ab83f7f19bba64a94259d9640815b676eb1c 100644 --- a/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj +++ b/Tools/ArdupilotMegaPlanner/ArdupilotMega.csproj @@ -201,6 +201,10 @@ <Reference Include="System.Management"> <Private>False</Private> </Reference> + <Reference Include="System.Reactive, Version=1.0.10621.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>Lib\System.Reactive.dll</HintPath> + </Reference> <Reference Include="System.Speech"> <Private>True</Private> </Reference> @@ -288,6 +292,12 @@ <Compile Include="Controls\ConfigPanel.Designer.cs"> <DependentUpon>ConfigPanel.cs</DependentUpon> </Compile> + <Compile Include="Controls\ConnectionStats.cs"> + <SubType>UserControl</SubType> + </Compile> + <Compile Include="Controls\ConnectionStats.designer.cs"> + <DependentUpon>ConnectionStats.cs</DependentUpon> + </Compile> <Compile Include="Controls\CustomMessageBox.cs" /> <Compile Include="Controls\LineSeparator.cs"> <SubType>UserControl</SubType> @@ -602,6 +612,9 @@ <EmbeddedResource Include="Controls\ConfigPanel.resx"> <DependentUpon>ConfigPanel.cs</DependentUpon> </EmbeddedResource> + <EmbeddedResource Include="Controls\ConnectionStats.resx"> + <DependentUpon>ConnectionStats.cs</DependentUpon> + </EmbeddedResource> <EmbeddedResource Include="Controls\HSI.resx"> <DependentUpon>HSI.cs</DependentUpon> </EmbeddedResource> @@ -1122,13 +1135,9 @@ <EmbeddedResource Include="temp.resx"> <DependentUpon>temp.cs</DependentUpon> </EmbeddedResource> - <None Include="AeroSimRCAPMHil.zip"> - <CopyToOutputDirectory>Always</CopyToOutputDirectory> - </None> + <None Include="AeroSimRCAPMHil.zip" /> <None Include="app.config" /> - <None Include="arducopter-xplane.zip"> - <CopyToOutputDirectory>Always</CopyToOutputDirectory> - </None> + <None Include="arducopter-xplane.zip" /> <None Include="m3u\GeoRefnetworklink.kml"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> @@ -1158,9 +1167,7 @@ <CopyToOutputDirectory>Always</CopyToOutputDirectory> <SubType>Designer</SubType> </Content> - <Content Include="JSBSim.exe"> - <CopyToOutputDirectory>Always</CopyToOutputDirectory> - </Content> + <Content Include="JSBSim.exe" /> <Content Include="mavcmd.xml"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> diff --git a/Tools/ArdupilotMegaPlanner/Common.cs b/Tools/ArdupilotMegaPlanner/Common.cs index ffb89d72b08dda1f240726c1a969d60319227f9d..ebc4326f59ce4caec3a90c393f145442fb487526 100644 --- a/Tools/ArdupilotMegaPlanner/Common.cs +++ b/Tools/ArdupilotMegaPlanner/Common.cs @@ -465,7 +465,6 @@ namespace ArdupilotMega CH6_STABILIZE_KD = 29 } - public static void linearRegression() { double[] values = { 4.8, 4.8, 4.5, 3.9, 4.4, 3.6, 3.6, 2.9, 3.5, 3.0, 2.5, 2.2, 2.6, 2.1, 2.2 }; diff --git a/Tools/ArdupilotMegaPlanner/Controls/ConnectionControl.Designer.cs b/Tools/ArdupilotMegaPlanner/Controls/ConnectionControl.Designer.cs index 72c5781a3d61add30e934f3190eb86aeb7ec87e4..f541cfe0b8abe62f825fbe47c224f630d3cb3144 100644 --- a/Tools/ArdupilotMegaPlanner/Controls/ConnectionControl.Designer.cs +++ b/Tools/ArdupilotMegaPlanner/Controls/ConnectionControl.Designer.cs @@ -31,6 +31,7 @@ this.cmb_Baud = new System.Windows.Forms.ComboBox(); this.cmb_ConnectionType = new System.Windows.Forms.ComboBox(); this.cmb_Connection = new System.Windows.Forms.ComboBox(); + this.linkLabel1 = new System.Windows.Forms.LinkLabel(); this.SuspendLayout(); // // cmb_Baud @@ -66,17 +67,28 @@ this.cmb_Connection.Size = new System.Drawing.Size(121, 21); this.cmb_Connection.TabIndex = 2; // + this.linkLabel1.AutoSize = true; + this.linkLabel1.Image = global::ArdupilotMega.Properties.Resources.bg; + this.linkLabel1.Location = new System.Drawing.Point(3, 60); + this.linkLabel1.Name = "linkLabel1"; + this.linkLabel1.Size = new System.Drawing.Size(63, 13); + this.linkLabel1.TabIndex = 3; + this.linkLabel1.TabStop = true; + this.linkLabel1.Text = "Link Stats..."; + this.linkLabel1.Visible = false; // ConnectionControl // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackgroundImage = global::ArdupilotMega.Properties.Resources.bg; + this.Controls.Add(this.linkLabel1); this.Controls.Add(this.cmb_Connection); this.Controls.Add(this.cmb_ConnectionType); this.Controls.Add(this.cmb_Baud); this.Name = "ConnectionControl"; this.Size = new System.Drawing.Size(230, 76); this.ResumeLayout(false); + this.PerformLayout(); } @@ -85,5 +97,6 @@ private System.Windows.Forms.ComboBox cmb_Baud; private System.Windows.Forms.ComboBox cmb_ConnectionType; private System.Windows.Forms.ComboBox cmb_Connection; + private System.Windows.Forms.LinkLabel linkLabel1; } } diff --git a/Tools/ArdupilotMegaPlanner/Controls/ConnectionControl.cs b/Tools/ArdupilotMegaPlanner/Controls/ConnectionControl.cs index 404a8de181f0b95f4a1dd5197aed50a34ba2cc8c..96f12fcc0fe3edcc0c2f5cbfd94c8d23c080cc26 100644 --- a/Tools/ArdupilotMegaPlanner/Controls/ConnectionControl.cs +++ b/Tools/ArdupilotMegaPlanner/Controls/ConnectionControl.cs @@ -14,10 +14,28 @@ namespace ArdupilotMega.Controls public ConnectionControl() { InitializeComponent(); + this.linkLabel1.Click += (sender, e) => + { + if (ShowLinkStats!=null) + ShowLinkStats.Invoke(this, EventArgs.Empty); + }; } + public event EventHandler ShowLinkStats; public ComboBox CMB_baudrate { get { return this.cmb_Baud; } } public ComboBox CMB_serialport { get { return this.cmb_Connection; } } public ComboBox TOOL_APMFirmware { get { return this.cmb_ConnectionType; } } + + /// <summary> + /// Called from the main form - set whether we are connected or not currently. + /// UI will be updated accordingly + /// </summary> + /// <param name="isConnected">Whether we are connected</param> + public void IsConnected(bool isConnected) + { + this.linkLabel1.Visible = isConnected; + cmb_Baud.Enabled = !isConnected; + cmb_Connection.Enabled = !isConnected; + } } } diff --git a/Tools/ArdupilotMegaPlanner/Controls/ConnectionStats.Designer.cs b/Tools/ArdupilotMegaPlanner/Controls/ConnectionStats.Designer.cs new file mode 100644 index 0000000000000000000000000000000000000000..333656539be171961da6cd43c097e8eb08051087 --- /dev/null +++ b/Tools/ArdupilotMegaPlanner/Controls/ConnectionStats.Designer.cs @@ -0,0 +1,292 @@ +namespace ArdupilotMega.Controls +{ + partial class ConnectionStats + { + /// <summary> + /// Required designer variable. + /// </summary> + private System.ComponentModel.IContainer components = null; + + /// <summary> + /// Clean up any resources being used. + /// </summary> + /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// <summary> + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// </summary> + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.txt_BytesReceived = new System.Windows.Forms.TextBox(); + this.txt_BytesPerSecondRx = new System.Windows.Forms.TextBox(); + this.txt_PacketsRx = new System.Windows.Forms.TextBox(); + this.txt_PacketsLost = new System.Windows.Forms.TextBox(); + this.txt_LinkQuality = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.txt_PacketsPerSecond = new System.Windows.Forms.TextBox(); + this.txt_BytesSent = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.txt_BytesPerSecondSent = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label10 = new System.Windows.Forms.Label(); + this.txt_MaxPacketInterval = new System.Windows.Forms.TextBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(10, 18); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(33, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Bytes"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(135, 18); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(43, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Bytes/s"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 44); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(46, 13); + this.label3.TabIndex = 2; + this.label3.Text = "Packets"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(3, 70); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(51, 13); + this.label4.TabIndex = 3; + this.label4.Text = "Pkts Lost"; + // + // txt_BytesReceived + // + this.txt_BytesReceived.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txt_BytesReceived.Location = new System.Drawing.Point(58, 16); + this.txt_BytesReceived.Name = "txt_BytesReceived"; + this.txt_BytesReceived.ReadOnly = true; + this.txt_BytesReceived.Size = new System.Drawing.Size(64, 20); + this.txt_BytesReceived.TabIndex = 4; + // + // txt_BytesPerSecondRx + // + this.txt_BytesPerSecondRx.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txt_BytesPerSecondRx.Location = new System.Drawing.Point(184, 16); + this.txt_BytesPerSecondRx.Name = "txt_BytesPerSecondRx"; + this.txt_BytesPerSecondRx.ReadOnly = true; + this.txt_BytesPerSecondRx.Size = new System.Drawing.Size(51, 20); + this.txt_BytesPerSecondRx.TabIndex = 5; + // + // txt_PacketsRx + // + this.txt_PacketsRx.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txt_PacketsRx.Location = new System.Drawing.Point(58, 42); + this.txt_PacketsRx.Name = "txt_PacketsRx"; + this.txt_PacketsRx.ReadOnly = true; + this.txt_PacketsRx.Size = new System.Drawing.Size(64, 20); + this.txt_PacketsRx.TabIndex = 6; + // + // txt_PacketsLost + // + this.txt_PacketsLost.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txt_PacketsLost.Location = new System.Drawing.Point(58, 68); + this.txt_PacketsLost.Name = "txt_PacketsLost"; + this.txt_PacketsLost.ReadOnly = true; + this.txt_PacketsLost.Size = new System.Drawing.Size(64, 20); + this.txt_PacketsLost.TabIndex = 7; + // + // txt_LinkQuality + // + this.txt_LinkQuality.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txt_LinkQuality.Location = new System.Drawing.Point(184, 68); + this.txt_LinkQuality.Name = "txt_LinkQuality"; + this.txt_LinkQuality.ReadOnly = true; + this.txt_LinkQuality.Size = new System.Drawing.Size(51, 20); + this.txt_LinkQuality.TabIndex = 9; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(139, 68); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(39, 13); + this.label5.TabIndex = 8; + this.label5.Text = "Quality"; + // + // txt_PacketsPerSecond + // + this.txt_PacketsPerSecond.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txt_PacketsPerSecond.Location = new System.Drawing.Point(184, 42); + this.txt_PacketsPerSecond.Name = "txt_PacketsPerSecond"; + this.txt_PacketsPerSecond.ReadOnly = true; + this.txt_PacketsPerSecond.Size = new System.Drawing.Size(51, 20); + this.txt_PacketsPerSecond.TabIndex = 10; + // + // txt_BytesSent + // + this.txt_BytesSent.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txt_BytesSent.Location = new System.Drawing.Point(74, 16); + this.txt_BytesSent.Name = "txt_BytesSent"; + this.txt_BytesSent.ReadOnly = true; + this.txt_BytesSent.Size = new System.Drawing.Size(64, 20); + this.txt_BytesSent.TabIndex = 12; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(6, 18); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(60, 13); + this.label6.TabIndex = 11; + this.label6.Text = "Total Bytes"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(23, 43); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(43, 13); + this.label7.TabIndex = 13; + this.label7.Text = "Bytes/s"; + // + // txt_BytesPerSecondSent + // + this.txt_BytesPerSecondSent.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txt_BytesPerSecondSent.Location = new System.Drawing.Point(74, 42); + this.txt_BytesPerSecondSent.Name = "txt_BytesPerSecondSent"; + this.txt_BytesPerSecondSent.ReadOnly = true; + this.txt_BytesPerSecondSent.Size = new System.Drawing.Size(64, 20); + this.txt_BytesPerSecondSent.TabIndex = 14; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(126, 43); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(56, 13); + this.label8.TabIndex = 15; + this.label8.Text = "Packets/s"; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label10); + this.groupBox1.Controls.Add(this.txt_MaxPacketInterval); + this.groupBox1.Controls.Add(this.label8); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.txt_BytesReceived); + this.groupBox1.Controls.Add(this.txt_PacketsPerSecond); + this.groupBox1.Controls.Add(this.txt_BytesPerSecondRx); + this.groupBox1.Controls.Add(this.txt_LinkQuality); + this.groupBox1.Controls.Add(this.txt_PacketsRx); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.txt_PacketsLost); + this.groupBox1.Location = new System.Drawing.Point(4, 4); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(245, 124); + this.groupBox1.TabIndex = 16; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Download"; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(22, 96); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(156, 13); + this.label10.TabIndex = 16; + this.label10.Text = "Max time between packets (ms)"; + // + // txt_MaxPacketInterval + // + this.txt_MaxPacketInterval.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txt_MaxPacketInterval.Location = new System.Drawing.Point(184, 94); + this.txt_MaxPacketInterval.Name = "txt_MaxPacketInterval"; + this.txt_MaxPacketInterval.ReadOnly = true; + this.txt_MaxPacketInterval.Size = new System.Drawing.Size(51, 20); + this.txt_MaxPacketInterval.TabIndex = 17; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.txt_BytesPerSecondSent); + this.groupBox2.Controls.Add(this.label7); + this.groupBox2.Controls.Add(this.label6); + this.groupBox2.Controls.Add(this.txt_BytesSent); + this.groupBox2.Location = new System.Drawing.Point(255, 4); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(144, 83); + this.groupBox2.TabIndex = 17; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Upload"; + // + // ConnectionStats + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.groupBox2); + this.Name = "ConnectionStats"; + this.Size = new System.Drawing.Size(408, 136); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox txt_BytesReceived; + private System.Windows.Forms.TextBox txt_BytesPerSecondRx; + private System.Windows.Forms.TextBox txt_PacketsRx; + private System.Windows.Forms.TextBox txt_PacketsLost; + private System.Windows.Forms.TextBox txt_LinkQuality; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox txt_PacketsPerSecond; + private System.Windows.Forms.TextBox txt_BytesSent; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.TextBox txt_BytesPerSecondSent; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.TextBox txt_MaxPacketInterval; + } +} diff --git a/Tools/ArdupilotMegaPlanner/Controls/ConnectionStats.cs b/Tools/ArdupilotMegaPlanner/Controls/ConnectionStats.cs new file mode 100644 index 0000000000000000000000000000000000000000..cea41e020921fe566b9d2bd155ebb34e9d1974ac --- /dev/null +++ b/Tools/ArdupilotMegaPlanner/Controls/ConnectionStats.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Threading; +using System.Windows.Forms; + +namespace ArdupilotMega.Controls +{ + public partial class ConnectionStats : UserControl + { + private readonly MAVLink _mavlink; + private CompositeDisposable _subscriptionsDisposable; + + public ConnectionStats(MAVLink comPort) : this() + { + _mavlink = comPort; + + this.Load += ConnectionStats_Load; + this.Disposed += (sender, e) => StopUpdates(); + } + + public ConnectionStats() + { + InitializeComponent(); + } + + void ConnectionStats_Load(object sender, EventArgs e) + { + _subscriptionsDisposable = new CompositeDisposable(); + + var packetsReceivedCount = _mavlink.WhenPacketReceived.Scan(0, (x, y) => x + y); + var packetsLostCount = _mavlink.WhenPacketLost.Scan(0, (x, y) => x + y); + + var bytesReceivedEverySecond = _mavlink.BytesReceived + .Buffer(TimeSpan.FromSeconds(1)) + .Select(bytes => bytes.Sum()); + + var subscriptions = new List<IDisposable> + { + // Total number of packets received + // but only update the text box at 4Hz + packetsReceivedCount + .Sample(TimeSpan.FromMilliseconds(250)) + .SubscribeForTextUpdates(txt_PacketsRx), + + packetsLostCount + .Sample(TimeSpan.FromMilliseconds(250)) + .SubscribeForTextUpdates(txt_PacketsLost), + + // Packets per second = total number of packets received over the + // last 3 seconds divided by three + // Do that every second + _mavlink.WhenPacketReceived + .Buffer(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(1)) + .Select(xs => xs.Sum()/3.0) + .ObserveOn(SynchronizationContext.Current) + .Subscribe(x => this.txt_PacketsPerSecond.Text = x.ToString("0")), + + // Link quality is a percentage of the number of good packets received + // to the number of packets missed (detected by mavlink seq no.) + // Calculated as an average over the last 3 seconds (non weighted) + // Calculated every second + CombineWithDefault(_mavlink.WhenPacketReceived, _mavlink.WhenPacketLost, Tuple.Create) + .Buffer(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(1)) + .Select(CalculateAverage) + .ObserveOn(SynchronizationContext.Current) + .Subscribe(x => this.txt_LinkQuality.Text = x.ToString("00%")), + + // Bytes per second is the average number of bytes received every second + // sampled for the last 3 seconds + // updated every second + bytesReceivedEverySecond + .Buffer(3, 1) + .Select(xs => (int) xs.Average()) + .Select(ToHumanReadableByteCount) + .SubscribeForTextUpdates(txt_BytesPerSecondRx), + + // Total bytes received - just count them up, + // but only update the text box at 4Hz so as not to swamp the UI thread + // Also use a human friendly version e.g '1.3K' not 1345 + _mavlink.BytesReceived + .Scan(0, (x, y) => x + y) + .Sample(TimeSpan.FromMilliseconds(250)) + .Select(ToHumanReadableByteCount) + .SubscribeForTextUpdates(txt_BytesReceived), + + _mavlink.BytesSent + .Scan(0, (x, y) => x + y) + .Sample(TimeSpan.FromMilliseconds(250)) + .Select(ToHumanReadableByteCount) + .SubscribeForTextUpdates(txt_BytesSent), + + _mavlink.BytesSent + .Buffer(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1)) + .Select(xs => xs.Any() ? xs.Average() : 0) + .Select(x => ToHumanReadableByteCount((int) x)) + .SubscribeForTextUpdates(txt_BytesPerSecondSent), + +// Observable.Interval(TimeSpan.FromSeconds(1)) +// .Scan(TimeSpan.Zero, (a, _) => a.Add(TimeSpan.FromSeconds(1))) +// .ObserveOn(SynchronizationContext.Current) +// .Subscribe(ts => this.txt_TimeConnected.Text = ts.ToString()), + + // The maximum length of time between reception of good packets + // evaluated continuously + _mavlink.WhenPacketReceived + .TimeInterval() + .Select(x => x.Interval.Ticks) + .Scan(0L, Math.Max) + .Select(TimeSpan.FromTicks) + .Select(ts => ts.Milliseconds) + .ObserveOn(SynchronizationContext.Current) + .SubscribeForTextUpdates(txt_MaxPacketInterval), + + }; + + subscriptions.ForEach(d => _subscriptionsDisposable.Add(d)); + } + + public void StopUpdates() + { + _subscriptionsDisposable.Dispose(); + } + + private static IObservable<TResult> CombineWithDefault<TSource, TResult>(IObservable<TSource> first, Subject<TSource> second, Func<TSource, TSource, TResult> resultSelector) + { + return Observable.Defer(() => + { + var foo = new Subject<TResult>(); + + first.Select(x => resultSelector(x, default(TSource))).Subscribe(foo); + second.Select(x => resultSelector(default(TSource), x)).Subscribe(foo); + + return foo; + }); + } + + private static double CalculateAverage(IList<Tuple<int, int>> xs) + { + var packetsReceived = xs.Sum(t => t.Item1); + var packetsLost = xs.Sum(t => t.Item2); + + return packetsReceived/(packetsReceived + (double)packetsLost); + } + + private static string ToHumanReadableByteCount(int i) + { + if (i > 1024) + return string.Format("{0:0.00}K", i/ (float)1024); + if (i > 1024 * 1024) + return string.Format("{0:0.00}Mb", i / (float)(1024 * 1024)); + return string.Format("{0:####}",i); + } + } + + + + + public static class CompositeDisposableEx + { + public static IDisposable SubscribeForTextUpdates<T>(this IObservable<T> source, TextBox txtBox) + { + return source + .ObserveOn(SynchronizationContext.Current) + .Subscribe(x => txtBox.Text = x.ToString()); + } + } +} diff --git a/Tools/ArdupilotMegaPlanner/Controls/ConnectionStats.resx b/Tools/ArdupilotMegaPlanner/Controls/ConnectionStats.resx new file mode 100644 index 0000000000000000000000000000000000000000..7080a7d118e8cd7ec668e9bb0d8e90767e0c7a3c --- /dev/null +++ b/Tools/ArdupilotMegaPlanner/Controls/ConnectionStats.resx @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> +</root> \ No newline at end of file diff --git a/Tools/ArdupilotMegaPlanner/CurrentState.cs b/Tools/ArdupilotMegaPlanner/CurrentState.cs index b15dccf96b437c57d4e12142e923dda294945f58..bdbac3a75894eca909b42e40b2c4fdfcbcd95b24 100644 --- a/Tools/ArdupilotMegaPlanner/CurrentState.cs +++ b/Tools/ArdupilotMegaPlanner/CurrentState.cs @@ -296,6 +296,8 @@ namespace ArdupilotMega // stats public ushort packetdropremote { get; set; } public ushort linkqualitygcs { get; set; } + public ushort hwvoltage { get; set; } + public ushort i2cerrors { get; set; } // requested stream rates public byte rateattitude { get; set; } @@ -400,9 +402,22 @@ namespace ArdupilotMega hilch3 = (int)(hil.throttle * 10000); hilch4 = (int)(hil.yaw_rudder * 10000); - //MAVLink.packets[MAVLink.MAVLINK_MSG_ID_RC_CHANNELS_SCALED] = null; + //MAVLink.packets[MAVLink.MAVLINK_MSG_ID_HIL_CONTROLS] = null; } + bytearray = mavinterface.packets[MAVLink.MAVLINK_MSG_ID_HWSTATUS]; + + if (bytearray != null) + { + var hwstatus = bytearray.ByteArrayToStructure<MAVLink.mavlink_hwstatus_t>(6); + + hwvoltage = hwstatus.Vcc; + i2cerrors = hwstatus.I2Cerr; + + //MAVLink.packets[MAVLink.MAVLINK_MSG_ID_HWSTATUS] = null; + } + + bytearray = mavinterface.packets[MAVLink.MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT]; if (bytearray != null) diff --git a/Tools/ArdupilotMegaPlanner/LogBrowse.cs b/Tools/ArdupilotMegaPlanner/LogBrowse.cs index d48c9d4fc82ef578805ecbcbcedb01ce3be078e7..c8a059461a2c6935191c1eee81ac2e336c4e8f5b 100644 --- a/Tools/ArdupilotMegaPlanner/LogBrowse.cs +++ b/Tools/ArdupilotMegaPlanner/LogBrowse.cs @@ -153,6 +153,9 @@ namespace ArdupilotMega { string option = dataGridView1[0, e.RowIndex].EditedFormattedValue.ToString(); + if (option.StartsWith("PID-")) + option = "PID-1"; + using (XmlReader reader = XmlReader.Create(Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + "dataflashlog.xml")) { reader.Read(); diff --git a/Tools/ArdupilotMegaPlanner/MAVLink.cs b/Tools/ArdupilotMegaPlanner/MAVLink.cs index 1d5f5dfde8848d0b1c08fb3d3abb851657988e32..ec49653fae3513db39584db5ec517242ece286dd 100644 --- a/Tools/ArdupilotMegaPlanner/MAVLink.cs +++ b/Tools/ArdupilotMegaPlanner/MAVLink.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reactive.Subjects; using System.Text; using System.Runtime.InteropServices; using System.Collections; // hashs @@ -58,6 +59,30 @@ namespace ArdupilotMega /// time last seen a packet of a type /// </summary> DateTime[] packetspersecondbuild = new DateTime[256]; + + + private readonly Subject<int> _bytesReceivedSubj = new Subject<int>(); + private readonly Subject<int> _bytesSentSubj = new Subject<int>(); + + /// <summary> + /// Observable of the count of bytes received, notified when the bytes themselves are received + /// </summary> + public IObservable<int> BytesReceived { get { return _bytesReceivedSubj; } } + + /// <summary> + /// Observable of the count of bytes sent, notified when the bytes themselves are received + /// </summary> + public IObservable<int> BytesSent { get { return _bytesSentSubj; } } + + /// <summary> + /// Observable of the count of packets skipped (on reception), + /// calculated from periods where received packet sequence is not + /// contiguous + /// </summary> + public readonly Subject<int> WhenPacketLost = new Subject<int>(); + + public Subject<int> WhenPacketReceived = new Subject<int>(); + /// <summary> /// used as a serial port write lock /// </summary> @@ -163,7 +188,7 @@ namespace ArdupilotMega OpenBg(false, e); } - private void OpenBg(bool getparams, ProgressWorkerEventArgs progressWorkerEventArgs) + private void OpenBg(bool getparams, ProgressWorkerEventArgs progressWorkerEventArgs) { frmProgressReporter.UpdateProgressAndStatus(-1, "Mavlink Connecting..."); @@ -286,8 +311,8 @@ namespace ArdupilotMega countDown.Stop(); -// if (Progress != null) -// Progress(-1, "Getting Params.. (sysid " + sysid + " compid " + compid + ") "); + // if (Progress != null) + // Progress(-1, "Getting Params.. (sysid " + sysid + " compid " + compid + ") "); frmProgressReporter.UpdateProgressAndStatus(0, "Getting Params.. (sysid " + sysid + " compid " + compid + ") "); if (getparams) @@ -309,8 +334,8 @@ namespace ArdupilotMega } catch { } MainV2.giveComport = false; -// if (Progress != null) -// Progress(-1, "Connect Failed\n" + e.Message); + // if (Progress != null) + // Progress(-1, "Connect Failed\n" + e.Message); if (string.IsNullOrEmpty(progressWorkerEventArgs.ErrorMessage)) progressWorkerEventArgs.ErrorMessage = "Connect Failed"; throw e; @@ -429,6 +454,7 @@ namespace ArdupilotMega { BaseStream.Write(packet, 0, i); } + _bytesSentSubj.OnNext(i); } try @@ -474,6 +500,7 @@ namespace ArdupilotMega { BaseStream.Write(line); } + _bytesSentSubj.OnNext(line.Length); return true; } @@ -492,7 +519,7 @@ namespace ArdupilotMega if ((float)param[paramname] == value) { - log.Debug("setParam "+paramname + " not modified"); + log.Debug("setParam " + paramname + " not modified"); return true; } @@ -592,7 +619,7 @@ namespace ArdupilotMega if (ParamListChanged != null) { - ParamListChanged(this, null); + ParamListChanged(this, null); } } @@ -622,7 +649,7 @@ namespace ArdupilotMega int param_count = 0; int param_total = 5; - goagain: + goagain: mavlink_param_request_list_t req = new mavlink_param_request_list_t(); req.target_system = sysid; @@ -686,12 +713,12 @@ namespace ArdupilotMega // check if we already have it if (got.Contains(par.param_index)) { - log.Info("Already got "+(par.param_index) + " '" + paramID + "'"); + log.Info("Already got " + (par.param_index) + " '" + paramID + "'"); this.frmProgressReporter.UpdateProgressAndStatus((got.Count * 100) / param_total, "Already Got param " + paramID); continue; } - log.Info(DateTime.Now.Millisecond + " got param " + (par.param_index) + " of " + (par.param_count - 2) + " name: " + paramID ); + log.Info(DateTime.Now.Millisecond + " got param " + (par.param_index) + " of " + (par.param_count - 2) + " name: " + paramID); modifyParamForDisplay(true, paramID, ref par.param_value); param[paramID] = (par.param_value); @@ -1040,9 +1067,9 @@ namespace ArdupilotMega public void requestDatastream(byte id, byte hzrate) { - + double pps = 0; - + switch (id) { case (byte)MAVLink.MAV_DATA_STREAM.ALL: @@ -1131,7 +1158,7 @@ namespace ArdupilotMega { return; } - + log.InfoFormat("Request stream {0} at {1} hz", Enum.Parse(typeof(MAV_DATA_STREAM), id.ToString()), hzrate); getDatastream(id, hzrate); @@ -1161,7 +1188,7 @@ namespace ArdupilotMega { return true; } - + return false; } @@ -1478,7 +1505,7 @@ namespace ArdupilotMega public object DebugPacket(byte[] datin) { string text = ""; - return DebugPacket(datin, ref text,true); + return DebugPacket(datin, ref text, true); } public object DebugPacket(byte[] datin, bool PrintToConsole) @@ -2055,6 +2082,7 @@ namespace ArdupilotMega TCPConsole.Write(temp[0]); Console.Write((char)temp[0]); } + _bytesReceivedSubj.OnNext(1); count = 0; lastbad[0] = lastbad[1]; lastbad[1] = temp[0]; @@ -2077,7 +2105,9 @@ namespace ArdupilotMega if (temp[3] == '3' && temp[4] == 'D') { // this is a 3dr radio rssi packet - } else { + } + else + { log.InfoFormat("Mavlink Bad Packet (not addressed to this MAV) got {0} {1} vs {2} {3}", temp[3], temp[4], sysid, compid); return new byte[0]; } @@ -2130,6 +2160,8 @@ namespace ArdupilotMega Array.Resize<byte>(ref temp, count); + _bytesReceivedSubj.OnNext(temp.Length); + if (packetlosttimer.AddSeconds(5) < DateTime.Now) { packetlosttimer = DateTime.Now; @@ -2168,7 +2200,7 @@ namespace ArdupilotMega { if (MAVLINK_MESSAGE_LENGTHS[temp[5]] == 0) // pass for unknown packets { - + } else { @@ -2212,26 +2244,33 @@ namespace ArdupilotMega } else { - if (temp[2] != ((recvpacketcount + 1) % 0x100)) + byte packetSeqNo = temp[2]; + int expectedPacketSeqNo = ((recvpacketcount + 1) % 0x100); + + if (packetSeqNo != expectedPacketSeqNo) { synclost++; // actualy sync loss's + int numLost = 0; - if (temp[2] < ((recvpacketcount + 1))) + if (packetSeqNo < ((recvpacketcount + 1))) // recvpacketcount = 255 then 10 < 256 = true if was % 0x100 this would fail { - packetslost += 0x100 - recvpacketcount + temp[2]; + numLost = 0x100 - expectedPacketSeqNo + packetSeqNo; } else { - packetslost += temp[2] - recvpacketcount; + numLost = packetSeqNo - recvpacketcount; } + packetslost += numLost; + WhenPacketLost.OnNext(numLost); - log.InfoFormat("lost {0} pktslost {1}", temp[2], (int)packetslost); + log.InfoFormat("lost {0} pkts {1}", packetSeqNo, (int)packetslost); } packetsnotlost++; - recvpacketcount = temp[2]; - + recvpacketcount = packetSeqNo; + WhenPacketReceived.OnNext(1); + // Console.WriteLine(DateTime.Now.Millisecond); } //MAVLINK_MSG_ID_GPS_STATUS @@ -2507,8 +2546,5 @@ namespace ArdupilotMega return temp; } - - - } } \ No newline at end of file diff --git a/Tools/ArdupilotMegaPlanner/MainV2.cs b/Tools/ArdupilotMegaPlanner/MainV2.cs index 8fbd76e4c0c12e7c867ca1de5fe2ede6dd735845..a7b4a603a57ce7e651a7bc4ab17be553737a8cf8 100644 --- a/Tools/ArdupilotMegaPlanner/MainV2.cs +++ b/Tools/ArdupilotMegaPlanner/MainV2.cs @@ -119,6 +119,7 @@ namespace ArdupilotMega ArduCopter2, } + DateTime connectButtonUpdate = DateTime.Now; /// <summary> /// declared here if i want a "single" instance of the form /// ie configuration gets reloaded on every click @@ -131,10 +132,15 @@ namespace ArdupilotMega GCSViews.Firmware Firmware; GCSViews.Terminal Terminal; + private Form connectionStatsForm; + private ConnectionStats _connectionStats; + /// <summary> - /// control for the serial port and firmware selector. + /// This 'Control' is the toolstrip control that holds the comport combo, baudrate combo etc + /// Otiginally seperate controls, each hosted in a toolstip sqaure, combined into this custom + /// control for layout reasons. /// </summary> - private ConnectionControl _connectionControl; + private readonly ConnectionControl _connectionControl; public MainV2() { @@ -154,7 +160,7 @@ namespace ArdupilotMega instance = this; InitializeComponent(); - + _connectionControl = toolStripConnectionControl.ConnectionControl; _connectionControl.CMB_baudrate.TextChanged += this.CMB_baudrate_TextChanged; _connectionControl.CMB_baudrate.SelectedIndexChanged += this.CMB_baudrate_SelectedIndexChanged; @@ -163,6 +169,7 @@ namespace ArdupilotMega _connectionControl.CMB_serialport.Click += this.CMB_serialport_Click; _connectionControl.TOOL_APMFirmware.SelectedIndexChanged += this.TOOL_APMFirmware_SelectedIndexChanged; + _connectionControl.ShowLinkStats += (sender, e) => ShowConnectionStatsForm(); srtm.datadirectory = Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar + "srtm"; var t = Type.GetType("Mono.Runtime"); @@ -174,7 +181,6 @@ namespace ArdupilotMega MainMenu.Renderer = new MyRenderer(); - List<object> list = new List<object>(); foreach (object obj in Enum.GetValues(typeof(Firmwares))) { _connectionControl.TOOL_APMFirmware.Items.Add(obj); @@ -188,14 +194,14 @@ namespace ArdupilotMega comPort.BaseStream.BaudRate = 115200; // ** Old -// CMB_serialport.Items.AddRange(SerialPort.GetPortNames()); -// CMB_serialport.Items.Add("TCP"); -// CMB_serialport.Items.Add("UDP"); -// if (CMB_serialport.Items.Count > 0) -// { -// CMB_baudrate.SelectedIndex = 7; -// CMB_serialport.SelectedIndex = 0; -// } + // CMB_serialport.Items.AddRange(SerialPort.GetPortNames()); + // CMB_serialport.Items.Add("TCP"); + // CMB_serialport.Items.Add("UDP"); + // if (CMB_serialport.Items.Count > 0) + // { + // CMB_baudrate.SelectedIndex = 7; + // CMB_serialport.SelectedIndex = 0; + // } // ** new _connectionControl.CMB_serialport.Items.AddRange(ArdupilotMega.Comms.SerialPort.GetPortNames()); _connectionControl.CMB_serialport.Items.Add("TCP"); @@ -341,6 +347,46 @@ namespace ArdupilotMega splash.Close(); } + + private void ResetConnectionStats() + { + // If the form has been closed, or never shown before, we need do nothing, as + // connection stats will be reset when shown + if (this.connectionStatsForm != null && connectionStatsForm.Visible) + { + // else the form is already showing. reset the stats + this.connectionStatsForm.Controls.Clear(); + _connectionStats = new ConnectionStats(comPort); + this.connectionStatsForm.Controls.Add(_connectionStats); + ThemeManager.ApplyThemeTo(this.connectionStatsForm); + } + } + + private void ShowConnectionStatsForm() + { + if (this.connectionStatsForm == null || this.connectionStatsForm.IsDisposed) + { + // If the form has been closed, or never shown before, we need all new stuff + this.connectionStatsForm = new Form + { + Width = 430, + Height = 180, + MaximizeBox = false, + MinimizeBox = false, + FormBorderStyle = FormBorderStyle.FixedDialog, + Text = "Link Stats" + }; + // Change the connection stats control, so that when/if the connection stats form is showing, + // there will be something to see + this.connectionStatsForm.Controls.Clear(); + _connectionStats = new ConnectionStats(comPort); + this.connectionStatsForm.Controls.Add(_connectionStats); + } + + this.connectionStatsForm.Show(); + ThemeManager.ApplyThemeTo(this.connectionStatsForm); + } + /// <summary> /// used to create planner screenshots - access by control-s /// </summary> @@ -542,7 +588,10 @@ namespace ArdupilotMega if (speechEngine != null) // cancel all pending speech speechEngine.SpeakAsyncCancelAll(); } - catch { } + catch (Exception ex) + { + log.Error(ex); + } if (comPort.logfile != null) comPort.logfile.Close(); @@ -553,25 +602,39 @@ namespace ArdupilotMega comPort.BaseStream.DtrEnable = false; comPort.Close(); } - catch (Exception ex) { log.Debug(ex.ToString()); } + catch (Exception ex) + { + log.Error(ex); + } + + // now that we have closed the connection, cancel the connection stats + // so that the 'time connected' etc does not grow, but the user can still + // look at the now frozen stats on the still open form + ((ConnectionStats)this.connectionStatsForm.Controls[0]).StopUpdates(); this.MenuConnect.BackgroundImage = global::ArdupilotMega.Properties.Resources.connect; } else { - if (_connectionControl.CMB_serialport.Text == "TCP") + switch (_connectionControl.CMB_serialport.Text) { - comPort.BaseStream = new TcpSerial(); - } - else if (_connectionControl.CMB_serialport.Text == "UDP") - { - comPort.BaseStream = new UdpSerial(); - } - else - { - comPort.BaseStream = new ArdupilotMega.Comms.SerialPort(); + case "TCP": + comPort.BaseStream = new TcpSerial(); + break; + case "UDP": + comPort.BaseStream = new UdpSerial(); + break; + default: + comPort.BaseStream = new Comms.SerialPort(); + break; } + // Tell the connection UI that we are now connected. + this._connectionControl.IsConnected(true); + + // Here we want to reset the connection stats counter etc. + this.ResetConnectionStats(); + try { // set port, then options @@ -849,11 +912,18 @@ namespace ArdupilotMega break; } } - catch (Exception ee) { log.Info(ee.Message); } // silent fail on bad entry + // silent fail on bad entry + catch (Exception ee) + { + log.Error(ee); + } } } } - catch (Exception ex) { log.Info("Bad Config File: " + ex.ToString()); } // bad config file + catch (Exception ex) + { + log.Error("Bad Config File", ex); + } } } @@ -939,7 +1009,7 @@ namespace ArdupilotMega } */ -// Console.WriteLine(DateTime.Now.Millisecond + " {0} {1} {2} {3} {4}", rc.chan1_raw, rc.chan2_raw, rc.chan3_raw, rc.chan4_raw,rate); + // Console.WriteLine(DateTime.Now.Millisecond + " {0} {1} {2} {3} {4}", rc.chan1_raw, rc.chan2_raw, rc.chan3_raw, rc.chan4_raw,rate); comPort.sendPacket(rc); count++; lastjoystick = DateTime.Now; @@ -947,18 +1017,19 @@ namespace ArdupilotMega } } - System.Threading.Thread.Sleep(20); + Thread.Sleep(20); } - catch { } // cant fall out + catch + { + + } // cant fall out } } - DateTime connectButtonUpdate = DateTime.Now; - /// <summary> /// Used to fix the icon status for unexpected unplugs etc... /// </summary> - private void updateConnectIcon() + private void UpdateConnectIcon() { if ((DateTime.Now - connectButtonUpdate).Milliseconds > 500) { @@ -971,8 +1042,7 @@ namespace ArdupilotMega { this.MenuConnect.BackgroundImage = global::ArdupilotMega.Properties.Resources.disconnect; this.MenuConnect.BackgroundImage.Tag = "Disconnect"; - _connectionControl.CMB_baudrate.Enabled = false; - _connectionControl.CMB_serialport.Enabled = false; + _connectionControl.IsConnected(true); }); } } @@ -984,8 +1054,9 @@ namespace ArdupilotMega { this.MenuConnect.BackgroundImage = global::ArdupilotMega.Properties.Resources.connect; this.MenuConnect.BackgroundImage.Tag = "Connect"; - _connectionControl.CMB_baudrate.Enabled = true; - _connectionControl.CMB_serialport.Enabled = true; + _connectionControl.IsConnected(false); + if (_connectionStats != null) + _connectionStats.StopUpdates(); }); } } @@ -1022,9 +1093,9 @@ namespace ArdupilotMega { try { - System.Threading.Thread.Sleep(5); - - updateConnectIcon(); + Thread.Sleep(5); + + UpdateConnectIcon(); if (speechEnable && speechEngine != null && (DateTime.Now - speechcustomtime).TotalSeconds > 30 && MainV2.cs.lat != 0 && (MainV2.comPort.logreadmode || comPort.BaseStream.IsOpen)) { @@ -1121,7 +1192,7 @@ namespace ArdupilotMega } catch (Exception e) { - log.Info("Serial Reader fail :" + e.Message); + log.Error("Serial Reader fail :" + e.Message); try { comPort.Close(); @@ -1131,6 +1202,10 @@ namespace ArdupilotMega } } + /// <summary> + /// Override the stock ToolStripProfessionalRenderer to implement 'highlighting' of the + /// currently selected GCS view. + /// </summary> private class MyRenderer : ToolStripProfessionalRenderer { public static ToolStripItem currentpressed; @@ -1217,11 +1292,11 @@ namespace ArdupilotMega try { - CheckForUpdate(); + CheckForUpdate(); } catch (Exception ex) { - log.Error("Update check failed", ex); + log.Error("Update check failed", ex); } } @@ -1253,7 +1328,11 @@ namespace ArdupilotMega { listener.Start(); } - catch { log.Info("do you have the planner open already"); return; } // in use + catch (Exception e) + { + log.Error("Exception starting lister. Possible multiple instances of planner?", e); + return; + } // in use // Enter the listening loop. while (true) { @@ -1281,12 +1360,12 @@ namespace ArdupilotMega NetworkStream stream = client.GetStream(); - System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); + var asciiEncoding = new ASCIIEncoding(); - byte[] request = new byte[1024]; + var request = new byte[1024]; int len = stream.Read(request, 0, request.Length); - string head = System.Text.ASCIIEncoding.ASCII.GetString(request, 0, len); + string head = System.Text.Encoding.ASCII.GetString(request, 0, len); log.Info(head); int index = head.IndexOf('\n'); @@ -1322,8 +1401,8 @@ namespace ArdupilotMega while (client.Connected) { - System.Threading.Thread.Sleep(200); - log.Info(stream.DataAvailable + " " + client.Available); + Thread.Sleep(200); + log.Debug(stream.DataAvailable + " " + client.Available); while (client.Available > 0) { @@ -1352,7 +1431,7 @@ namespace ArdupilotMega else if (url.Contains("georefnetwork.kml")) { string header = "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.google-earth.kml+xml\n\n"; - byte[] temp = encoding.GetBytes(header); + byte[] temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); byte[] buffer = Encoding.ASCII.GetBytes(georefkml); @@ -1364,7 +1443,7 @@ namespace ArdupilotMega else if (url.Contains("network.kml")) { string header = "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.google-earth.kml+xml\n\n"; - byte[] temp = encoding.GetBytes(header); + byte[] temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); SharpKml.Dom.Document kml = new SharpKml.Dom.Document(); @@ -1433,7 +1512,7 @@ namespace ArdupilotMega else if (url.Contains("block_plane_0.dae")) { string header = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\n\n"; - byte[] temp = encoding.GetBytes(header); + byte[] temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); BinaryReader file = new BinaryReader(File.Open("block_plane_0.dae", FileMode.Open, FileAccess.Read, FileShare.Read)); @@ -1451,7 +1530,7 @@ namespace ArdupilotMega else if (url.Contains("hud.html")) { string header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\n\n"; - byte[] temp = encoding.GetBytes(header); + byte[] temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); BinaryReader file = new BinaryReader(File.Open("hud.html", FileMode.Open, FileAccess.Read, FileShare.Read)); @@ -1469,7 +1548,7 @@ namespace ArdupilotMega else if (url.ToLower().Contains("hud.jpg") || url.ToLower().Contains("map.jpg") || url.ToLower().Contains("both.jpg")) { string header = "HTTP/1.1 200 OK\r\nContent-Type: multipart/x-mixed-replace;boundary=APMPLANNER\n\n--APMPLANNER\r\n"; - byte[] temp = encoding.GetBytes(header); + byte[] temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); while (client.Connected) @@ -1508,13 +1587,13 @@ namespace ArdupilotMega } header = "Content-Type: image/jpeg\r\nContent-Length: " + data.Length + "\r\n\r\n"; - temp = encoding.GetBytes(header); + temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); stream.Write(data, 0, data.Length); header = "\r\n--APMPLANNER\r\n"; - temp = encoding.GetBytes(header); + temp = asciiEncoding.GetBytes(header); stream.Write(temp, 0, temp.Length); } @@ -1525,7 +1604,10 @@ namespace ArdupilotMega } stream.Close(); } - catch (Exception ee) { log.Info("Failed mjpg " + ee.Message); } + catch (Exception ee) + { + log.Error("Failed mjpg ", ee); + } } } @@ -1730,30 +1812,30 @@ namespace ArdupilotMega static void DoUpdateWorker_DoWork(object sender, Controls.ProgressWorkerEventArgs e) { - // TODO: Is this the right place? - #region Fetch Parameter Meta Data - - var progressReporterDialogue = ((ProgressReporterDialogue) sender); - progressReporterDialogue.UpdateProgressAndStatus(-1, "Getting Updated Parameters"); - - try - { - ParameterMetaDataParser.GetParameterInformation(); - } - catch (Exception ex) { log.Error(ex.ToString()); CustomMessageBox.Show("Error getting Parameter Information"); } - - #endregion Fetch Parameter Meta Data - - progressReporterDialogue.UpdateProgressAndStatus(-1, "Getting Base URL"); - // check for updates - if (Debugger.IsAttached) - { - log.Info("Skipping update test as it appears we are debugging"); - } - else - { - MainV2.updateCheckMain(progressReporterDialogue); - } + // TODO: Is this the right place? + #region Fetch Parameter Meta Data + + var progressReporterDialogue = ((ProgressReporterDialogue)sender); + progressReporterDialogue.UpdateProgressAndStatus(-1, "Getting Updated Parameters"); + + try + { + ParameterMetaDataParser.GetParameterInformation(); + } + catch (Exception ex) { log.Error(ex.ToString()); CustomMessageBox.Show("Error getting Parameter Information"); } + + #endregion Fetch Parameter Meta Data + + progressReporterDialogue.UpdateProgressAndStatus(-1, "Getting Base URL"); + // check for updates + if (Debugger.IsAttached) + { + log.Info("Skipping update test as it appears we are debugging"); + } + else + { + MainV2.updateCheckMain(progressReporterDialogue); + } } private static bool updateCheck(ProgressReporterDialogue frmProgressReporter, string baseurl, string subdir) @@ -1920,7 +2002,7 @@ namespace ArdupilotMega // Get the response. response = request.GetResponse(); // Display the status. - log.Info(((HttpWebResponse)response).StatusDescription); + log.Debug(((HttpWebResponse)response).StatusDescription); // Get the stream containing content returned by the server. dataStream = response.GetResponseStream(); @@ -1946,7 +2028,7 @@ namespace ArdupilotMega } } catch { } - log.Info(file + " " + bytes); + log.Debug(file + " " + bytes); int len = dataStream.Read(buf1, 0, 1024); if (len == 0) break; @@ -2195,7 +2277,7 @@ namespace ArdupilotMega private void CMB_baudrate_TextChanged(object sender, EventArgs e) { - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); int baud = 0; for (int i = 0; i < _connectionControl.CMB_baudrate.Text.Length; i++) if (char.IsDigit(_connectionControl.CMB_baudrate.Text[i])) diff --git a/Tools/ArdupilotMegaPlanner/Msi/wix.pdb b/Tools/ArdupilotMegaPlanner/Msi/wix.pdb index f4ce1358c9560f2ff52014713bc05527a56d0f43..bce0c1ecacf422c8cccb29bffab97004f6f9e78b 100644 Binary files a/Tools/ArdupilotMegaPlanner/Msi/wix.pdb and b/Tools/ArdupilotMegaPlanner/Msi/wix.pdb differ diff --git a/Tools/ArdupilotMegaPlanner/Properties/AssemblyInfo.cs b/Tools/ArdupilotMegaPlanner/Properties/AssemblyInfo.cs index f87006bf3faa9c58f43c145f83a41b35f7bbe740..099c10818d369adeebc643127c8cb6a5086a3c12 100644 --- a/Tools/ArdupilotMegaPlanner/Properties/AssemblyInfo.cs +++ b/Tools/ArdupilotMegaPlanner/Properties/AssemblyInfo.cs @@ -34,5 +34,5 @@ using System.Resources; // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.1.*")] -[assembly: AssemblyFileVersion("1.1.81")] +[assembly: AssemblyFileVersion("1.1.82")] [assembly: NeutralResourcesLanguageAttribute("")] diff --git a/Tools/ArdupilotMegaPlanner/Radio/3DRradio.cs b/Tools/ArdupilotMegaPlanner/Radio/3DRradio.cs index 3d55bb84b7ad9297133b0d007fc3868402dd9e22..f6a385a381e6ba042326eb03f7f7dae81b75284a 100644 --- a/Tools/ArdupilotMegaPlanner/Radio/3DRradio.cs +++ b/Tools/ArdupilotMegaPlanner/Radio/3DRradio.cs @@ -172,6 +172,10 @@ namespace ArdupilotMega log.Info(message); Application.DoEvents(); } + else if (level < 5) // 5 = byte data + { + log.Debug(message); + } } catch { } } diff --git a/Tools/ArdupilotMegaPlanner/Radio/Uploader.cs b/Tools/ArdupilotMegaPlanner/Radio/Uploader.cs index 315c43ae77836ecbb145e4a6721010e09db23a04..663f23993bf6a9400a1ec073a529e2a70c2addd7 100644 --- a/Tools/ArdupilotMegaPlanner/Radio/Uploader.cs +++ b/Tools/ArdupilotMegaPlanner/Radio/Uploader.cs @@ -33,8 +33,8 @@ namespace uploader REBOOT = 0x30, // protocol constants - PROG_MULTI_MAX = 64, // maximum number of bytes in a PROG_MULTI command - READ_MULTI_MAX = 64, // from 255 // largest read that can be requested + PROG_MULTI_MAX = 32, // maximum number of bytes in a PROG_MULTI command + READ_MULTI_MAX = 255, // largest read that can be requested // device IDs XXX should come with the firmware image... DEVICE_ID_RF50 = 0x4d,