Initial commit
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
/.idea/
|
||||
21
CruiseControllerMX5.csproj
Normal file
21
CruiseControllerMX5.csproj
Normal file
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<ApplicationVisualStyles>true</ApplicationVisualStyles>
|
||||
<ApplicationUseCompatibleTextRendering>false</ApplicationUseCompatibleTextRendering>
|
||||
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
|
||||
<LangVersion>default</LangVersion>
|
||||
<!-- <ApplicationDefaultFont>Microsoft Sans Serif, 8.25pt</ApplicationDefaultFont> -->
|
||||
<!-- <AllowUnsafeBlocks>true</AllowUnsafeBlocks> -->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.Ports" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
4
CruiseControllerMX5.csproj.user
Normal file
4
CruiseControllerMX5.csproj.user
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup />
|
||||
</Project>
|
||||
25
CruiseControllerMX5.sln
Normal file
25
CruiseControllerMX5.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.002.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CruiseControllerMX5", "CruiseControllerMX5.csproj", "{1EB855FC-DA5B-4693-9AA9-F83B3EFCD166}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1EB855FC-DA5B-4693-9AA9-F83B3EFCD166}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1EB855FC-DA5B-4693-9AA9-F83B3EFCD166}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1EB855FC-DA5B-4693-9AA9-F83B3EFCD166}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1EB855FC-DA5B-4693-9AA9-F83B3EFCD166}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D516363E-E077-41A2-B6C6-E6E893675F31}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
838
src/App.Designer.cs
generated
Normal file
838
src/App.Designer.cs
generated
Normal file
@@ -0,0 +1,838 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
partial class App
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private IContainer components = null;
|
||||
|
||||
#region Windows Form 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()
|
||||
{
|
||||
leftPanel = new System.Windows.Forms.Panel();
|
||||
leftFillPanel = new System.Windows.Forms.Panel();
|
||||
speedGaugeCanvas = new System.Windows.Forms.PictureBox();
|
||||
leftFillTopPanel = new System.Windows.Forms.Panel();
|
||||
leftBottomPanel = new System.Windows.Forms.Panel();
|
||||
kpidPanel = new System.Windows.Forms.TableLayoutPanel();
|
||||
kdCurrentField = new System.Windows.Forms.TextBox();
|
||||
kdField = new System.Windows.Forms.TextBox();
|
||||
kpidNewValueLabel = new System.Windows.Forms.Label();
|
||||
kpidCurrentValueLabel = new System.Windows.Forms.Label();
|
||||
kpLabel = new System.Windows.Forms.Label();
|
||||
kpField = new System.Windows.Forms.TextBox();
|
||||
kpCurrentField = new System.Windows.Forms.TextBox();
|
||||
kiLabel = new System.Windows.Forms.Label();
|
||||
kiField = new System.Windows.Forms.TextBox();
|
||||
kiCurrentField = new System.Windows.Forms.TextBox();
|
||||
kdLabel = new System.Windows.Forms.Label();
|
||||
rightPanel = new System.Windows.Forms.Panel();
|
||||
graphPanel = new System.Windows.Forms.Panel();
|
||||
graphCanvas = new System.Windows.Forms.PictureBox();
|
||||
graphControlsPanel = new System.Windows.Forms.Panel();
|
||||
servoToggle = new System.Windows.Forms.CheckBox();
|
||||
accelerationToggle = new System.Windows.Forms.CheckBox();
|
||||
speedToggle = new System.Windows.Forms.CheckBox();
|
||||
derivativeToggle = new System.Windows.Forms.CheckBox();
|
||||
integralToggle = new System.Windows.Forms.CheckBox();
|
||||
errorToggle = new System.Windows.Forms.CheckBox();
|
||||
valuesPanel = new System.Windows.Forms.Panel();
|
||||
tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
errorField = new System.Windows.Forms.TextBox();
|
||||
errorLabel = new System.Windows.Forms.Label();
|
||||
accelerationLabel = new System.Windows.Forms.Label();
|
||||
speedLabel = new System.Windows.Forms.Label();
|
||||
speedField = new System.Windows.Forms.TextBox();
|
||||
accelerationField = new System.Windows.Forms.TextBox();
|
||||
derivativeField = new System.Windows.Forms.TextBox();
|
||||
integralField = new System.Windows.Forms.TextBox();
|
||||
proportionalField = new System.Windows.Forms.TextBox();
|
||||
derivativeLabel = new System.Windows.Forms.Label();
|
||||
integralLabel = new System.Windows.Forms.Label();
|
||||
proportionalLabel = new System.Windows.Forms.Label();
|
||||
servoLabel = new System.Windows.Forms.Label();
|
||||
servoMinLabel = new System.Windows.Forms.Label();
|
||||
servoMaxLabel = new System.Windows.Forms.Label();
|
||||
servoNeutralLabel = new System.Windows.Forms.Label();
|
||||
servoField = new System.Windows.Forms.TextBox();
|
||||
servoMinField = new System.Windows.Forms.TextBox();
|
||||
servoMaxField = new System.Windows.Forms.TextBox();
|
||||
servoNeutralField = new System.Windows.Forms.TextBox();
|
||||
statusPanel = new System.Windows.Forms.TableLayoutPanel();
|
||||
stateLabel = new System.Windows.Forms.Label();
|
||||
brakeLabel = new System.Windows.Forms.Label();
|
||||
menuStrip1 = new System.Windows.Forms.MenuStrip();
|
||||
leftPanel.SuspendLayout();
|
||||
leftFillPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)speedGaugeCanvas).BeginInit();
|
||||
leftBottomPanel.SuspendLayout();
|
||||
kpidPanel.SuspendLayout();
|
||||
rightPanel.SuspendLayout();
|
||||
graphPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)graphCanvas).BeginInit();
|
||||
graphControlsPanel.SuspendLayout();
|
||||
valuesPanel.SuspendLayout();
|
||||
tableLayoutPanel1.SuspendLayout();
|
||||
statusPanel.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// leftPanel
|
||||
//
|
||||
leftPanel.Controls.Add(leftFillPanel);
|
||||
leftPanel.Controls.Add(leftBottomPanel);
|
||||
leftPanel.Dock = System.Windows.Forms.DockStyle.Left;
|
||||
leftPanel.Location = new System.Drawing.Point(0, 24);
|
||||
leftPanel.Name = "leftPanel";
|
||||
leftPanel.Size = new System.Drawing.Size(300, 480);
|
||||
leftPanel.TabIndex = 1;
|
||||
//
|
||||
// leftFillPanel
|
||||
//
|
||||
leftFillPanel.Controls.Add(speedGaugeCanvas);
|
||||
leftFillPanel.Controls.Add(leftFillTopPanel);
|
||||
leftFillPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
leftFillPanel.Location = new System.Drawing.Point(0, 0);
|
||||
leftFillPanel.Name = "leftFillPanel";
|
||||
leftFillPanel.Size = new System.Drawing.Size(300, 300);
|
||||
leftFillPanel.TabIndex = 4;
|
||||
//
|
||||
// speedGaugeCanvas
|
||||
//
|
||||
speedGaugeCanvas.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
speedGaugeCanvas.Location = new System.Drawing.Point(0, 40);
|
||||
speedGaugeCanvas.Name = "speedGaugeCanvas";
|
||||
speedGaugeCanvas.Size = new System.Drawing.Size(300, 260);
|
||||
speedGaugeCanvas.TabIndex = 2;
|
||||
speedGaugeCanvas.TabStop = false;
|
||||
speedGaugeCanvas.Paint += speedGaugePanel_Paint;
|
||||
//
|
||||
// leftFillTopPanel
|
||||
//
|
||||
leftFillTopPanel.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
leftFillTopPanel.Location = new System.Drawing.Point(0, 0);
|
||||
leftFillTopPanel.Name = "leftFillTopPanel";
|
||||
leftFillTopPanel.Size = new System.Drawing.Size(300, 40);
|
||||
leftFillTopPanel.TabIndex = 3;
|
||||
//
|
||||
// leftBottomPanel
|
||||
//
|
||||
leftBottomPanel.Controls.Add(kpidPanel);
|
||||
leftBottomPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
leftBottomPanel.Location = new System.Drawing.Point(0, 300);
|
||||
leftBottomPanel.Name = "leftBottomPanel";
|
||||
leftBottomPanel.Size = new System.Drawing.Size(300, 180);
|
||||
leftBottomPanel.TabIndex = 3;
|
||||
//
|
||||
// kpidPanel
|
||||
//
|
||||
kpidPanel.AutoSize = true;
|
||||
kpidPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
kpidPanel.ColumnCount = 3;
|
||||
kpidPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
kpidPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
kpidPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
kpidPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
kpidPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
kpidPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
kpidPanel.Controls.Add(kdCurrentField, 0, 3);
|
||||
kpidPanel.Controls.Add(kdField, 0, 3);
|
||||
kpidPanel.Controls.Add(kpidNewValueLabel, 1, 0);
|
||||
kpidPanel.Controls.Add(kpidCurrentValueLabel, 2, 0);
|
||||
kpidPanel.Controls.Add(kpLabel, 0, 1);
|
||||
kpidPanel.Controls.Add(kpField, 1, 1);
|
||||
kpidPanel.Controls.Add(kpCurrentField, 2, 1);
|
||||
kpidPanel.Controls.Add(kiLabel, 0, 2);
|
||||
kpidPanel.Controls.Add(kiField, 1, 2);
|
||||
kpidPanel.Controls.Add(kiCurrentField, 2, 2);
|
||||
kpidPanel.Controls.Add(kdLabel, 0, 3);
|
||||
kpidPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
kpidPanel.Location = new System.Drawing.Point(0, 29);
|
||||
kpidPanel.Name = "kpidPanel";
|
||||
kpidPanel.Padding = new System.Windows.Forms.Padding(16);
|
||||
kpidPanel.RowCount = 4;
|
||||
kpidPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
kpidPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
kpidPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
kpidPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
kpidPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
kpidPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
kpidPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
kpidPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
kpidPanel.Size = new System.Drawing.Size(300, 151);
|
||||
kpidPanel.TabIndex = 1;
|
||||
//
|
||||
// kdCurrentField
|
||||
//
|
||||
kdCurrentField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kdCurrentField.Location = new System.Drawing.Point(165, 105);
|
||||
kdCurrentField.Name = "kdCurrentField";
|
||||
kdCurrentField.ReadOnly = true;
|
||||
kdCurrentField.Size = new System.Drawing.Size(116, 27);
|
||||
kdCurrentField.TabIndex = 10;
|
||||
kdCurrentField.TabStop = false;
|
||||
//
|
||||
// kdField
|
||||
//
|
||||
kdField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kdField.Location = new System.Drawing.Point(44, 105);
|
||||
kdField.Name = "kdField";
|
||||
kdField.Size = new System.Drawing.Size(115, 27);
|
||||
kdField.TabIndex = 9;
|
||||
//
|
||||
// kpidNewValueLabel
|
||||
//
|
||||
kpidNewValueLabel.AutoSize = true;
|
||||
kpidNewValueLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kpidNewValueLabel.Location = new System.Drawing.Point(41, 16);
|
||||
kpidNewValueLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
kpidNewValueLabel.Name = "kpidNewValueLabel";
|
||||
kpidNewValueLabel.Size = new System.Drawing.Size(121, 20);
|
||||
kpidNewValueLabel.TabIndex = 0;
|
||||
kpidNewValueLabel.Text = "Réglage";
|
||||
kpidNewValueLabel.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
|
||||
//
|
||||
// kpidCurrentValueLabel
|
||||
//
|
||||
kpidCurrentValueLabel.AutoSize = true;
|
||||
kpidCurrentValueLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kpidCurrentValueLabel.Location = new System.Drawing.Point(162, 16);
|
||||
kpidCurrentValueLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
kpidCurrentValueLabel.Name = "kpidCurrentValueLabel";
|
||||
kpidCurrentValueLabel.Size = new System.Drawing.Size(122, 20);
|
||||
kpidCurrentValueLabel.TabIndex = 1;
|
||||
kpidCurrentValueLabel.Text = "Actuel";
|
||||
kpidCurrentValueLabel.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
|
||||
//
|
||||
// kpLabel
|
||||
//
|
||||
kpLabel.AutoSize = true;
|
||||
kpLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kpLabel.Location = new System.Drawing.Point(16, 36);
|
||||
kpLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
kpLabel.Name = "kpLabel";
|
||||
kpLabel.Size = new System.Drawing.Size(25, 33);
|
||||
kpLabel.TabIndex = 2;
|
||||
kpLabel.Text = "kp";
|
||||
kpLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// kpField
|
||||
//
|
||||
kpField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kpField.Location = new System.Drawing.Point(44, 39);
|
||||
kpField.Name = "kpField";
|
||||
kpField.Size = new System.Drawing.Size(115, 27);
|
||||
kpField.TabIndex = 3;
|
||||
//
|
||||
// kpCurrentField
|
||||
//
|
||||
kpCurrentField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kpCurrentField.Location = new System.Drawing.Point(165, 39);
|
||||
kpCurrentField.Name = "kpCurrentField";
|
||||
kpCurrentField.ReadOnly = true;
|
||||
kpCurrentField.Size = new System.Drawing.Size(116, 27);
|
||||
kpCurrentField.TabIndex = 4;
|
||||
kpCurrentField.TabStop = false;
|
||||
//
|
||||
// kiLabel
|
||||
//
|
||||
kiLabel.AutoSize = true;
|
||||
kiLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kiLabel.Location = new System.Drawing.Point(16, 69);
|
||||
kiLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
kiLabel.Name = "kiLabel";
|
||||
kiLabel.Size = new System.Drawing.Size(25, 33);
|
||||
kiLabel.TabIndex = 5;
|
||||
kiLabel.Text = "ki";
|
||||
kiLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// kiField
|
||||
//
|
||||
kiField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kiField.Location = new System.Drawing.Point(44, 72);
|
||||
kiField.Name = "kiField";
|
||||
kiField.Size = new System.Drawing.Size(115, 27);
|
||||
kiField.TabIndex = 6;
|
||||
//
|
||||
// kiCurrentField
|
||||
//
|
||||
kiCurrentField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kiCurrentField.Location = new System.Drawing.Point(165, 72);
|
||||
kiCurrentField.Name = "kiCurrentField";
|
||||
kiCurrentField.ReadOnly = true;
|
||||
kiCurrentField.Size = new System.Drawing.Size(116, 27);
|
||||
kiCurrentField.TabIndex = 7;
|
||||
kiCurrentField.TabStop = false;
|
||||
//
|
||||
// kdLabel
|
||||
//
|
||||
kdLabel.AutoSize = true;
|
||||
kdLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
kdLabel.Location = new System.Drawing.Point(16, 102);
|
||||
kdLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
kdLabel.Name = "kdLabel";
|
||||
kdLabel.Size = new System.Drawing.Size(25, 33);
|
||||
kdLabel.TabIndex = 8;
|
||||
kdLabel.Text = "kd";
|
||||
kdLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// rightPanel
|
||||
//
|
||||
rightPanel.Controls.Add(graphPanel);
|
||||
rightPanel.Controls.Add(valuesPanel);
|
||||
rightPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
rightPanel.Location = new System.Drawing.Point(300, 24);
|
||||
rightPanel.Name = "rightPanel";
|
||||
rightPanel.Size = new System.Drawing.Size(1300, 480);
|
||||
rightPanel.TabIndex = 2;
|
||||
//
|
||||
// graphPanel
|
||||
//
|
||||
graphPanel.Controls.Add(graphCanvas);
|
||||
graphPanel.Controls.Add(graphControlsPanel);
|
||||
graphPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
graphPanel.Location = new System.Drawing.Point(0, 0);
|
||||
graphPanel.Name = "graphPanel";
|
||||
graphPanel.Size = new System.Drawing.Size(1300, 300);
|
||||
graphPanel.TabIndex = 3;
|
||||
//
|
||||
// graphCanvas
|
||||
//
|
||||
graphCanvas.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
graphCanvas.Location = new System.Drawing.Point(0, 40);
|
||||
graphCanvas.Name = "graphCanvas";
|
||||
graphCanvas.Size = new System.Drawing.Size(1300, 260);
|
||||
graphCanvas.TabIndex = 2;
|
||||
graphCanvas.TabStop = false;
|
||||
graphCanvas.Paint += graphCanvas_Paint;
|
||||
//
|
||||
// graphControlsPanel
|
||||
//
|
||||
graphControlsPanel.Controls.Add(servoToggle);
|
||||
graphControlsPanel.Controls.Add(accelerationToggle);
|
||||
graphControlsPanel.Controls.Add(speedToggle);
|
||||
graphControlsPanel.Controls.Add(derivativeToggle);
|
||||
graphControlsPanel.Controls.Add(integralToggle);
|
||||
graphControlsPanel.Controls.Add(errorToggle);
|
||||
graphControlsPanel.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
graphControlsPanel.Location = new System.Drawing.Point(0, 0);
|
||||
graphControlsPanel.Name = "graphControlsPanel";
|
||||
graphControlsPanel.Size = new System.Drawing.Size(1300, 40);
|
||||
graphControlsPanel.TabIndex = 3;
|
||||
//
|
||||
// servoToggle
|
||||
//
|
||||
servoToggle.AutoSize = true;
|
||||
servoToggle.Location = new System.Drawing.Point(452, 10);
|
||||
servoToggle.Name = "servoToggle";
|
||||
servoToggle.Size = new System.Drawing.Size(65, 24);
|
||||
servoToggle.TabIndex = 5;
|
||||
servoToggle.Text = "Servo";
|
||||
servoToggle.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// accelerationToggle
|
||||
//
|
||||
accelerationToggle.AutoSize = true;
|
||||
accelerationToggle.Location = new System.Drawing.Point(335, 10);
|
||||
accelerationToggle.Name = "accelerationToggle";
|
||||
accelerationToggle.Size = new System.Drawing.Size(111, 24);
|
||||
accelerationToggle.TabIndex = 4;
|
||||
accelerationToggle.Text = "Accélération";
|
||||
accelerationToggle.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// speedToggle
|
||||
//
|
||||
speedToggle.AutoSize = true;
|
||||
speedToggle.Location = new System.Drawing.Point(255, 10);
|
||||
speedToggle.Name = "speedToggle";
|
||||
speedToggle.Size = new System.Drawing.Size(74, 24);
|
||||
speedToggle.TabIndex = 3;
|
||||
speedToggle.Text = "Vitesse";
|
||||
speedToggle.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// derivativeToggle
|
||||
//
|
||||
derivativeToggle.AutoSize = true;
|
||||
derivativeToggle.Location = new System.Drawing.Point(164, 10);
|
||||
derivativeToggle.Name = "derivativeToggle";
|
||||
derivativeToggle.Size = new System.Drawing.Size(85, 24);
|
||||
derivativeToggle.TabIndex = 2;
|
||||
derivativeToggle.Text = "Dérivatif";
|
||||
derivativeToggle.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// integralToggle
|
||||
//
|
||||
integralToggle.AutoSize = true;
|
||||
integralToggle.Location = new System.Drawing.Point(79, 10);
|
||||
integralToggle.Name = "integralToggle";
|
||||
integralToggle.Size = new System.Drawing.Size(79, 24);
|
||||
integralToggle.TabIndex = 1;
|
||||
integralToggle.Text = "Intégral";
|
||||
integralToggle.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// errorToggle
|
||||
//
|
||||
errorToggle.AutoSize = true;
|
||||
errorToggle.Location = new System.Drawing.Point(6, 10);
|
||||
errorToggle.Name = "errorToggle";
|
||||
errorToggle.Size = new System.Drawing.Size(67, 24);
|
||||
errorToggle.TabIndex = 0;
|
||||
errorToggle.Text = "Erreur";
|
||||
errorToggle.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// valuesPanel
|
||||
//
|
||||
valuesPanel.Controls.Add(tableLayoutPanel1);
|
||||
valuesPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
valuesPanel.Location = new System.Drawing.Point(0, 300);
|
||||
valuesPanel.Name = "valuesPanel";
|
||||
valuesPanel.Size = new System.Drawing.Size(1300, 180);
|
||||
valuesPanel.TabIndex = 1;
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
tableLayoutPanel1.AutoSize = true;
|
||||
tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
tableLayoutPanel1.ColumnCount = 8;
|
||||
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 200F));
|
||||
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 16F));
|
||||
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 100F));
|
||||
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 16F));
|
||||
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 50F));
|
||||
tableLayoutPanel1.Controls.Add(errorField, 1, 0);
|
||||
tableLayoutPanel1.Controls.Add(errorLabel, 0, 0);
|
||||
tableLayoutPanel1.Controls.Add(accelerationLabel, 3, 1);
|
||||
tableLayoutPanel1.Controls.Add(speedLabel, 3, 0);
|
||||
tableLayoutPanel1.Controls.Add(speedField, 4, 0);
|
||||
tableLayoutPanel1.Controls.Add(accelerationField, 4, 1);
|
||||
tableLayoutPanel1.Controls.Add(derivativeField, 1, 3);
|
||||
tableLayoutPanel1.Controls.Add(integralField, 1, 2);
|
||||
tableLayoutPanel1.Controls.Add(proportionalField, 1, 1);
|
||||
tableLayoutPanel1.Controls.Add(derivativeLabel, 0, 3);
|
||||
tableLayoutPanel1.Controls.Add(integralLabel, 0, 2);
|
||||
tableLayoutPanel1.Controls.Add(proportionalLabel, 0, 1);
|
||||
tableLayoutPanel1.Controls.Add(servoLabel, 6, 0);
|
||||
tableLayoutPanel1.Controls.Add(servoMinLabel, 6, 1);
|
||||
tableLayoutPanel1.Controls.Add(servoMaxLabel, 6, 2);
|
||||
tableLayoutPanel1.Controls.Add(servoNeutralLabel, 6, 3);
|
||||
tableLayoutPanel1.Controls.Add(servoField, 7, 0);
|
||||
tableLayoutPanel1.Controls.Add(servoMinField, 7, 1);
|
||||
tableLayoutPanel1.Controls.Add(servoMaxField, 7, 2);
|
||||
tableLayoutPanel1.Controls.Add(servoNeutralField, 7, 3);
|
||||
tableLayoutPanel1.Location = new System.Drawing.Point(16, 32);
|
||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
tableLayoutPanel1.RowCount = 4;
|
||||
tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
tableLayoutPanel1.Size = new System.Drawing.Size(699, 132);
|
||||
tableLayoutPanel1.TabIndex = 11;
|
||||
//
|
||||
// errorField
|
||||
//
|
||||
errorField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
errorField.Location = new System.Drawing.Point(103, 3);
|
||||
errorField.Name = "errorField";
|
||||
errorField.ReadOnly = true;
|
||||
errorField.Size = new System.Drawing.Size(194, 27);
|
||||
errorField.TabIndex = 1;
|
||||
errorField.TabStop = false;
|
||||
//
|
||||
// errorLabel
|
||||
//
|
||||
errorLabel.AutoSize = true;
|
||||
errorLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
errorLabel.Location = new System.Drawing.Point(0, 0);
|
||||
errorLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
errorLabel.Name = "errorLabel";
|
||||
errorLabel.Size = new System.Drawing.Size(100, 33);
|
||||
errorLabel.TabIndex = 0;
|
||||
errorLabel.Text = "Erreur";
|
||||
errorLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// accelerationLabel
|
||||
//
|
||||
accelerationLabel.AutoSize = true;
|
||||
accelerationLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
accelerationLabel.Location = new System.Drawing.Point(316, 33);
|
||||
accelerationLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
accelerationLabel.Name = "accelerationLabel";
|
||||
accelerationLabel.Size = new System.Drawing.Size(92, 33);
|
||||
accelerationLabel.TabIndex = 10;
|
||||
accelerationLabel.Text = "Accélération";
|
||||
accelerationLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// speedLabel
|
||||
//
|
||||
speedLabel.AutoSize = true;
|
||||
speedLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
speedLabel.Location = new System.Drawing.Point(316, 0);
|
||||
speedLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
speedLabel.Name = "speedLabel";
|
||||
speedLabel.Size = new System.Drawing.Size(92, 33);
|
||||
speedLabel.TabIndex = 8;
|
||||
speedLabel.Text = "Vitesse";
|
||||
speedLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// speedField
|
||||
//
|
||||
speedField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
speedField.Location = new System.Drawing.Point(411, 3);
|
||||
speedField.Name = "speedField";
|
||||
speedField.ReadOnly = true;
|
||||
speedField.Size = new System.Drawing.Size(94, 27);
|
||||
speedField.TabIndex = 9;
|
||||
speedField.TabStop = false;
|
||||
//
|
||||
// accelerationField
|
||||
//
|
||||
accelerationField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
accelerationField.Location = new System.Drawing.Point(411, 36);
|
||||
accelerationField.Name = "accelerationField";
|
||||
accelerationField.ReadOnly = true;
|
||||
accelerationField.Size = new System.Drawing.Size(94, 27);
|
||||
accelerationField.TabIndex = 11;
|
||||
accelerationField.TabStop = false;
|
||||
//
|
||||
// derivativeField
|
||||
//
|
||||
derivativeField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
derivativeField.Location = new System.Drawing.Point(103, 102);
|
||||
derivativeField.Name = "derivativeField";
|
||||
derivativeField.ReadOnly = true;
|
||||
derivativeField.Size = new System.Drawing.Size(194, 27);
|
||||
derivativeField.TabIndex = 7;
|
||||
derivativeField.TabStop = false;
|
||||
//
|
||||
// integralField
|
||||
//
|
||||
integralField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
integralField.Location = new System.Drawing.Point(103, 69);
|
||||
integralField.Name = "integralField";
|
||||
integralField.ReadOnly = true;
|
||||
integralField.Size = new System.Drawing.Size(194, 27);
|
||||
integralField.TabIndex = 5;
|
||||
integralField.TabStop = false;
|
||||
//
|
||||
// proportionalField
|
||||
//
|
||||
proportionalField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
proportionalField.Location = new System.Drawing.Point(103, 36);
|
||||
proportionalField.Name = "proportionalField";
|
||||
proportionalField.ReadOnly = true;
|
||||
proportionalField.Size = new System.Drawing.Size(194, 27);
|
||||
proportionalField.TabIndex = 3;
|
||||
proportionalField.TabStop = false;
|
||||
//
|
||||
// derivativeLabel
|
||||
//
|
||||
derivativeLabel.AutoSize = true;
|
||||
derivativeLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
derivativeLabel.Location = new System.Drawing.Point(0, 99);
|
||||
derivativeLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
derivativeLabel.Name = "derivativeLabel";
|
||||
derivativeLabel.Size = new System.Drawing.Size(100, 33);
|
||||
derivativeLabel.TabIndex = 6;
|
||||
derivativeLabel.Text = "Dérivatif";
|
||||
derivativeLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// integralLabel
|
||||
//
|
||||
integralLabel.AutoSize = true;
|
||||
integralLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
integralLabel.Location = new System.Drawing.Point(0, 66);
|
||||
integralLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
integralLabel.Name = "integralLabel";
|
||||
integralLabel.Size = new System.Drawing.Size(100, 33);
|
||||
integralLabel.TabIndex = 4;
|
||||
integralLabel.Text = "Intégral";
|
||||
integralLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// proportionalLabel
|
||||
//
|
||||
proportionalLabel.AutoSize = true;
|
||||
proportionalLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
proportionalLabel.Location = new System.Drawing.Point(0, 33);
|
||||
proportionalLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
proportionalLabel.Name = "proportionalLabel";
|
||||
proportionalLabel.Size = new System.Drawing.Size(100, 33);
|
||||
proportionalLabel.TabIndex = 2;
|
||||
proportionalLabel.Text = "Proportionnel";
|
||||
proportionalLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// servoLabel
|
||||
//
|
||||
servoLabel.AutoSize = true;
|
||||
servoLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
servoLabel.Location = new System.Drawing.Point(524, 0);
|
||||
servoLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
servoLabel.Name = "servoLabel";
|
||||
servoLabel.Size = new System.Drawing.Size(125, 33);
|
||||
servoLabel.TabIndex = 12;
|
||||
servoLabel.Text = "Commande servo";
|
||||
servoLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// servoMinLabel
|
||||
//
|
||||
servoMinLabel.AutoSize = true;
|
||||
servoMinLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
servoMinLabel.Location = new System.Drawing.Point(524, 33);
|
||||
servoMinLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
servoMinLabel.Name = "servoMinLabel";
|
||||
servoMinLabel.Size = new System.Drawing.Size(125, 33);
|
||||
servoMinLabel.TabIndex = 14;
|
||||
servoMinLabel.Text = "Servo min";
|
||||
servoMinLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// servoMaxLabel
|
||||
//
|
||||
servoMaxLabel.AutoSize = true;
|
||||
servoMaxLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
servoMaxLabel.Location = new System.Drawing.Point(524, 66);
|
||||
servoMaxLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
servoMaxLabel.Name = "servoMaxLabel";
|
||||
servoMaxLabel.Size = new System.Drawing.Size(125, 33);
|
||||
servoMaxLabel.TabIndex = 16;
|
||||
servoMaxLabel.Text = "Servo max";
|
||||
servoMaxLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// servoNeutralLabel
|
||||
//
|
||||
servoNeutralLabel.AutoSize = true;
|
||||
servoNeutralLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
servoNeutralLabel.Location = new System.Drawing.Point(524, 99);
|
||||
servoNeutralLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
servoNeutralLabel.Name = "servoNeutralLabel";
|
||||
servoNeutralLabel.Size = new System.Drawing.Size(125, 33);
|
||||
servoNeutralLabel.TabIndex = 18;
|
||||
servoNeutralLabel.Text = "Servo neutre";
|
||||
servoNeutralLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// servoField
|
||||
//
|
||||
servoField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
servoField.Location = new System.Drawing.Point(652, 3);
|
||||
servoField.Name = "servoField";
|
||||
servoField.ReadOnly = true;
|
||||
servoField.Size = new System.Drawing.Size(44, 27);
|
||||
servoField.TabIndex = 13;
|
||||
servoField.TabStop = false;
|
||||
//
|
||||
// servoMinField
|
||||
//
|
||||
servoMinField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
servoMinField.Location = new System.Drawing.Point(652, 36);
|
||||
servoMinField.Name = "servoMinField";
|
||||
servoMinField.ReadOnly = true;
|
||||
servoMinField.Size = new System.Drawing.Size(44, 27);
|
||||
servoMinField.TabIndex = 15;
|
||||
servoMinField.TabStop = false;
|
||||
//
|
||||
// servoMaxField
|
||||
//
|
||||
servoMaxField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
servoMaxField.Location = new System.Drawing.Point(652, 69);
|
||||
servoMaxField.Name = "servoMaxField";
|
||||
servoMaxField.ReadOnly = true;
|
||||
servoMaxField.Size = new System.Drawing.Size(44, 27);
|
||||
servoMaxField.TabIndex = 17;
|
||||
servoMaxField.TabStop = false;
|
||||
//
|
||||
// servoNeutralField
|
||||
//
|
||||
servoNeutralField.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
servoNeutralField.Location = new System.Drawing.Point(652, 102);
|
||||
servoNeutralField.Name = "servoNeutralField";
|
||||
servoNeutralField.ReadOnly = true;
|
||||
servoNeutralField.Size = new System.Drawing.Size(44, 27);
|
||||
servoNeutralField.TabIndex = 19;
|
||||
servoNeutralField.TabStop = false;
|
||||
//
|
||||
// statusPanel
|
||||
//
|
||||
statusPanel.ColumnCount = 3;
|
||||
statusPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.333332F));
|
||||
statusPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.333332F));
|
||||
statusPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.333332F));
|
||||
statusPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.333332F));
|
||||
statusPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.333332F));
|
||||
statusPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.333332F));
|
||||
statusPanel.Controls.Add(stateLabel, 0, 0);
|
||||
statusPanel.Controls.Add(brakeLabel, 1, 0);
|
||||
statusPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
statusPanel.Location = new System.Drawing.Point(0, 504);
|
||||
statusPanel.Name = "statusPanel";
|
||||
statusPanel.RowCount = 1;
|
||||
statusPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
statusPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
statusPanel.Size = new System.Drawing.Size(1600, 32);
|
||||
statusPanel.TabIndex = 3;
|
||||
//
|
||||
// stateLabel
|
||||
//
|
||||
stateLabel.BackColor = System.Drawing.Color.FromArgb(((int)((byte)70)), ((int)((byte)70)), ((int)((byte)70)));
|
||||
stateLabel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
stateLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
stateLabel.Font = new System.Drawing.Font("Segoe UI", 14F, System.Drawing.FontStyle.Bold);
|
||||
stateLabel.Location = new System.Drawing.Point(0, 0);
|
||||
stateLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
stateLabel.Name = "stateLabel";
|
||||
stateLabel.Size = new System.Drawing.Size(533, 32);
|
||||
stateLabel.TabIndex = 0;
|
||||
stateLabel.Text = "Déconnecté / OFF";
|
||||
stateLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// brakeLabel
|
||||
//
|
||||
brakeLabel.BackColor = System.Drawing.Color.FromArgb(((int)((byte)70)), ((int)((byte)70)), ((int)((byte)70)));
|
||||
brakeLabel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
brakeLabel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
brakeLabel.Font = new System.Drawing.Font("Segoe UI", 14F, System.Drawing.FontStyle.Bold);
|
||||
brakeLabel.Location = new System.Drawing.Point(533, 0);
|
||||
brakeLabel.Margin = new System.Windows.Forms.Padding(0);
|
||||
brakeLabel.Name = "brakeLabel";
|
||||
brakeLabel.Size = new System.Drawing.Size(533, 32);
|
||||
brakeLabel.TabIndex = 1;
|
||||
brakeLabel.Text = "Frein";
|
||||
brakeLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
menuStrip1.Location = new System.Drawing.Point(0, 0);
|
||||
menuStrip1.Name = "menuStrip1";
|
||||
menuStrip1.Size = new System.Drawing.Size(1600, 24);
|
||||
menuStrip1.TabIndex = 4;
|
||||
menuStrip1.Text = "menuStrip1";
|
||||
//
|
||||
// App
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
BackColor = System.Drawing.Color.FromArgb(((int)((byte)30)), ((int)((byte)30)), ((int)((byte)30)));
|
||||
ClientSize = new System.Drawing.Size(1600, 536);
|
||||
Controls.Add(rightPanel);
|
||||
Controls.Add(leftPanel);
|
||||
Controls.Add(statusPanel);
|
||||
Controls.Add(menuStrip1);
|
||||
Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)0));
|
||||
ForeColor = System.Drawing.Color.White;
|
||||
Location = new System.Drawing.Point(15, 15);
|
||||
MainMenuStrip = menuStrip1;
|
||||
MinimumSize = new System.Drawing.Size(1616, 551);
|
||||
Text = "Cruise Controller MX5";
|
||||
Load += App_Load;
|
||||
leftPanel.ResumeLayout(false);
|
||||
leftFillPanel.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)speedGaugeCanvas).EndInit();
|
||||
leftBottomPanel.ResumeLayout(false);
|
||||
leftBottomPanel.PerformLayout();
|
||||
kpidPanel.ResumeLayout(false);
|
||||
kpidPanel.PerformLayout();
|
||||
rightPanel.ResumeLayout(false);
|
||||
graphPanel.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)graphCanvas).EndInit();
|
||||
graphControlsPanel.ResumeLayout(false);
|
||||
graphControlsPanel.PerformLayout();
|
||||
valuesPanel.ResumeLayout(false);
|
||||
valuesPanel.PerformLayout();
|
||||
tableLayoutPanel1.ResumeLayout(false);
|
||||
tableLayoutPanel1.PerformLayout();
|
||||
statusPanel.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
private System.Windows.Forms.MenuStrip menuStrip1;
|
||||
|
||||
private System.Windows.Forms.CheckBox speedToggle;
|
||||
private System.Windows.Forms.CheckBox accelerationToggle;
|
||||
private System.Windows.Forms.CheckBox servoToggle;
|
||||
|
||||
private System.Windows.Forms.CheckBox integralToggle;
|
||||
private System.Windows.Forms.CheckBox derivativeToggle;
|
||||
|
||||
private System.Windows.Forms.CheckBox errorToggle;
|
||||
|
||||
private System.Windows.Forms.Label servoMinLabel;
|
||||
private System.Windows.Forms.Label servoMaxLabel;
|
||||
private System.Windows.Forms.Label servoNeutralLabel;
|
||||
private System.Windows.Forms.TextBox servoField;
|
||||
private System.Windows.Forms.TextBox servoMinField;
|
||||
private System.Windows.Forms.TextBox servoMaxField;
|
||||
private System.Windows.Forms.TextBox servoNeutralField;
|
||||
|
||||
private System.Windows.Forms.Label servoLabel;
|
||||
|
||||
private System.Windows.Forms.Panel leftFillTopPanel;
|
||||
|
||||
private System.Windows.Forms.Panel leftFillPanel;
|
||||
|
||||
private System.Windows.Forms.Panel leftBottomPanel;
|
||||
|
||||
private System.Windows.Forms.TextBox speedField;
|
||||
private System.Windows.Forms.TextBox accelerationField;
|
||||
|
||||
private System.Windows.Forms.Label speedLabel;
|
||||
private System.Windows.Forms.Label accelerationLabel;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
|
||||
private System.Windows.Forms.TextBox errorField;
|
||||
|
||||
private System.Windows.Forms.TextBox integralField;
|
||||
private System.Windows.Forms.TextBox derivativeField;
|
||||
|
||||
private System.Windows.Forms.Label derivativeLabel;
|
||||
private System.Windows.Forms.Label errorLabel;
|
||||
private System.Windows.Forms.TextBox proportionalField;
|
||||
|
||||
private System.Windows.Forms.Label integralLabel;
|
||||
|
||||
private System.Windows.Forms.Label proportionalLabel;
|
||||
|
||||
private System.Windows.Forms.Label brakeLabel;
|
||||
|
||||
private System.Windows.Forms.Label stateLabel;
|
||||
|
||||
private System.Windows.Forms.PictureBox graphCanvas;
|
||||
|
||||
private System.Windows.Forms.Panel graphControlsPanel;
|
||||
|
||||
private System.Windows.Forms.Panel graphPanel;
|
||||
|
||||
private System.Windows.Forms.PictureBox speedGaugeCanvas;
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel statusPanel;
|
||||
|
||||
private System.Windows.Forms.Panel valuesPanel;
|
||||
|
||||
private System.Windows.Forms.Label kpidNewValueLabel;
|
||||
private System.Windows.Forms.Label kpidCurrentValueLabel;
|
||||
private System.Windows.Forms.Label kpLabel;
|
||||
private System.Windows.Forms.TextBox kpField;
|
||||
private System.Windows.Forms.TextBox kpCurrentField;
|
||||
private System.Windows.Forms.Label kiLabel;
|
||||
private System.Windows.Forms.TextBox kiField;
|
||||
private System.Windows.Forms.TextBox kiCurrentField;
|
||||
private System.Windows.Forms.Label kdLabel;
|
||||
private System.Windows.Forms.TextBox kdField;
|
||||
private System.Windows.Forms.TextBox kdCurrentField;
|
||||
|
||||
private System.Windows.Forms.TableLayoutPanel kpidPanel;
|
||||
|
||||
private System.Windows.Forms.Panel rightPanel;
|
||||
|
||||
private System.Windows.Forms.Panel leftPanel;
|
||||
|
||||
#endregion
|
||||
}
|
||||
1196
src/App.cs
Normal file
1196
src/App.cs
Normal file
File diff suppressed because it is too large
Load Diff
64
src/App.resx
Normal file
64
src/App.resx
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<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=9.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing.Primitives, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
502
src/ArduinoCom.cs
Normal file
502
src/ArduinoCom.cs
Normal file
@@ -0,0 +1,502 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Globalization;
|
||||
using System.IO.Ports;
|
||||
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
public interface IArduinoCom : IDisposable, IObservable<Sample>, IObserver<string>
|
||||
{
|
||||
void Open();
|
||||
void Close();
|
||||
IDisposable AddSerialObserver(IObserver<Sample> observer);
|
||||
void SendCommand(string command);
|
||||
}
|
||||
|
||||
public sealed class ArduinoCom : IArduinoCom
|
||||
{
|
||||
private readonly List<IObserver<Sample>> _sampleObservers = [];
|
||||
private readonly BlockingCollection<string> _commands = [];
|
||||
|
||||
private readonly SerialPort _serialPort;
|
||||
private readonly bool _keepOpen;
|
||||
|
||||
private bool _hasIgnoredFirstPacket, _hasReadSecondPacket;
|
||||
private Sample? _previousSample;
|
||||
|
||||
public ArduinoCom(SerialPort serialPort, bool keepOpen = false)
|
||||
{
|
||||
_serialPort = serialPort;
|
||||
_keepOpen = keepOpen;
|
||||
}
|
||||
|
||||
public ArduinoCom(Action<SerialPort> configure)
|
||||
{
|
||||
var serialPort = new SerialPort();
|
||||
configure(serialPort);
|
||||
_serialPort = serialPort;
|
||||
_keepOpen = false;
|
||||
}
|
||||
|
||||
public long ZeroTimestamp { get; private set; }
|
||||
|
||||
public void Open()
|
||||
{
|
||||
_serialPort.Open();
|
||||
|
||||
var readThread = new Thread(DoRead)
|
||||
{
|
||||
IsBackground = true
|
||||
};
|
||||
readThread.Start();
|
||||
|
||||
var writeThread = new Thread(DoWrite)
|
||||
{
|
||||
IsBackground = true
|
||||
};
|
||||
writeThread.Start();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_serialPort.Close();
|
||||
|
||||
_hasIgnoredFirstPacket = false;
|
||||
_hasReadSecondPacket = false;
|
||||
ZeroTimestamp = 0;
|
||||
_previousSample = null;
|
||||
}
|
||||
|
||||
public IDisposable AddSerialObserver(IObserver<Sample> observer)
|
||||
{
|
||||
_sampleObservers.Add(observer);
|
||||
return new Disposer(() => _sampleObservers.Remove(observer));
|
||||
}
|
||||
|
||||
public void SendCommand(string command)
|
||||
{
|
||||
_commands.Add(command);
|
||||
}
|
||||
|
||||
private Sample HandlePacket(string packet)
|
||||
{
|
||||
var timestamp = TimeProvider.System.GetTimestamp();
|
||||
|
||||
if (!_hasReadSecondPacket)
|
||||
{
|
||||
ZeroTimestamp = timestamp;
|
||||
_hasReadSecondPacket = true;
|
||||
}
|
||||
|
||||
Console.WriteLine(packet);
|
||||
var millis = (uint)TimeProvider.System.GetElapsedTime(ZeroTimestamp, timestamp).TotalMilliseconds;
|
||||
var sample = new Sample(millis,
|
||||
_previousSample == null || _previousSample.Timestamp / 1000 != timestamp / 1000);
|
||||
|
||||
var variables = packet.Split(';');
|
||||
|
||||
for (int i = 0, max = variables.Length - 1; i < max; i++)
|
||||
{
|
||||
var variable = variables[i];
|
||||
var split = variable.Split(':', 2);
|
||||
|
||||
var name = split[0];
|
||||
var value = split[1];
|
||||
|
||||
UpdateSample(sample, name, value);
|
||||
}
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
private static void UpdateSample(Sample sample, string name, string value)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "KP":
|
||||
sample.Kp = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "KI":
|
||||
sample.Ki = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "KD":
|
||||
sample.Kd = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "VITESSEMIN":
|
||||
sample.SpeedMin = int.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "VITESSEMAX":
|
||||
sample.SpeedMax = int.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "ETAT":
|
||||
sample.Active = Utils.IntToBool(value);
|
||||
break;
|
||||
case "CONSIGNE":
|
||||
sample.Consigne = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "VITESSE":
|
||||
sample.Speed = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "ACCEL":
|
||||
sample.Acceleration = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "ERREUR":
|
||||
sample.Error = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "PROPORTIONNEL":
|
||||
sample.Proportional = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "INTEGRAL":
|
||||
sample.Integral = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "DERIVATIF":
|
||||
sample.Derivative = float.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "SERVO":
|
||||
sample.Servo = int.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "SERVOMIN":
|
||||
sample.ServoMin = int.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "SERVOMAX":
|
||||
sample.ServoMax = int.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "SERVONEUTRE":
|
||||
sample.ServoNeutre = int.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "FREIN":
|
||||
sample.BrakeFlag = Utils.IntToBool(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void DoRead()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (_serialPort.IsOpen)
|
||||
{
|
||||
string line;
|
||||
try
|
||||
{
|
||||
line = _serialPort.ReadLine();
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("Failed to read line from serial connection");
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_hasIgnoredFirstPacket)
|
||||
{
|
||||
_hasIgnoredFirstPacket = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
var sample = HandlePacket(line);
|
||||
_previousSample = sample;
|
||||
|
||||
foreach (var observer in _sampleObservers)
|
||||
{
|
||||
try
|
||||
{
|
||||
observer.OnNext(sample);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("An exception occurred in a packet handler");
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("An exception occurred in the serial read loop");
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void DoWrite()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (_serialPort.IsOpen)
|
||||
{
|
||||
string line;
|
||||
|
||||
try
|
||||
{
|
||||
line = _commands.Take();
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_serialPort.WriteLine(line);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("Failed to send command");
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("An exception occurred in the serial write loop");
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#region IObservable
|
||||
|
||||
IDisposable IObservable<Sample>.Subscribe(IObserver<Sample> observer)
|
||||
{
|
||||
return AddSerialObserver(observer);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IObserver
|
||||
|
||||
void IObserver<string>.OnCompleted()
|
||||
{
|
||||
}
|
||||
|
||||
void IObserver<string>.OnError(Exception error)
|
||||
{
|
||||
}
|
||||
|
||||
void IObserver<string>.OnNext(string value)
|
||||
{
|
||||
SendCommand(value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposedValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_keepOpen)
|
||||
{
|
||||
_serialPort.Close();
|
||||
}
|
||||
|
||||
_commands.Dispose();
|
||||
_sampleObservers.Clear();
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public sealed class TestArduinoCom : IArduinoCom
|
||||
{
|
||||
private readonly List<IObserver<Sample>> _sampleObservers = [];
|
||||
private long _zeroTimestamp;
|
||||
|
||||
private volatile Sample? _previousSample;
|
||||
private volatile bool _keepGoing;
|
||||
|
||||
public void Open()
|
||||
{
|
||||
_keepGoing = true;
|
||||
|
||||
var readThread = new Thread(DoRead)
|
||||
{
|
||||
IsBackground = true
|
||||
};
|
||||
readThread.Start();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_keepGoing = false;
|
||||
|
||||
_previousSample = null;
|
||||
}
|
||||
|
||||
public IDisposable AddSerialObserver(IObserver<Sample> observer)
|
||||
{
|
||||
_sampleObservers.Add(observer);
|
||||
return new Disposer(() => _sampleObservers.Remove(observer));
|
||||
}
|
||||
|
||||
public void SendCommand(string command)
|
||||
{
|
||||
}
|
||||
|
||||
private void DoRead()
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.Sleep(2000);
|
||||
|
||||
while (_keepGoing)
|
||||
{
|
||||
var timestamp = TimeProvider.System.GetTimestamp();
|
||||
|
||||
if (_zeroTimestamp == 0L)
|
||||
{
|
||||
_zeroTimestamp = timestamp;
|
||||
}
|
||||
|
||||
var currentSecs = (int)TimeProvider.System.GetElapsedTime(_zeroTimestamp, timestamp).TotalSeconds;
|
||||
|
||||
Sample sample;
|
||||
|
||||
if (_previousSample == null)
|
||||
{
|
||||
sample = new Sample(timestamp, true)
|
||||
{
|
||||
Speed = 0,
|
||||
SpeedMin = 30,
|
||||
SpeedMax = 150,
|
||||
Active = true,
|
||||
Consigne = 30,
|
||||
ServoMin = 1160,
|
||||
ServoMax = 1600,
|
||||
ServoNeutre = 1200,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var previousSecs = (int)TimeProvider.System
|
||||
.GetElapsedTime(_zeroTimestamp, _previousSample.Timestamp).TotalSeconds;
|
||||
|
||||
sample = _previousSample.Copy(timestamp, previousSecs != currentSecs);
|
||||
|
||||
sample.Speed += 1f;
|
||||
if (sample.Speed > 240)
|
||||
{
|
||||
sample.Speed = 0;
|
||||
}
|
||||
|
||||
sample.Consigne += 0.1f;
|
||||
if (sample.Consigne > sample.SpeedMax)
|
||||
{
|
||||
sample.Consigne = sample.SpeedMin;
|
||||
}
|
||||
}
|
||||
|
||||
sample.Active = currentSecs / 3 % 3 == 0;
|
||||
sample.BrakeFlag = currentSecs % 2 == 0;
|
||||
|
||||
_previousSample = sample;
|
||||
|
||||
foreach (var observer in _sampleObservers)
|
||||
{
|
||||
try
|
||||
{
|
||||
observer.OnNext(sample);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("An exception occurred in a packet handler");
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("An exception occurred in the serial read loop");
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#region IObservable
|
||||
|
||||
IDisposable IObservable<Sample>.Subscribe(IObserver<Sample> observer)
|
||||
{
|
||||
return AddSerialObserver(observer);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IObserver
|
||||
|
||||
void IObserver<string>.OnCompleted()
|
||||
{
|
||||
}
|
||||
|
||||
void IObserver<string>.OnError(Exception error)
|
||||
{
|
||||
}
|
||||
|
||||
void IObserver<string>.OnNext(string value)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposedValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Close();
|
||||
_sampleObservers.Clear();
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
73
src/Buffer.cs
Normal file
73
src/Buffer.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
public static class Buffer
|
||||
{
|
||||
public static IBuffer<T> CreateBounded<T>(int capacity)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(capacity);
|
||||
|
||||
return new BoundedBuffer<T>(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IBuffer<T> : IEnumerable<T>
|
||||
{
|
||||
int Capacity { get; }
|
||||
|
||||
int Size { get; }
|
||||
|
||||
T? Get();
|
||||
|
||||
T? Get(int index);
|
||||
|
||||
void Add(T value);
|
||||
|
||||
void Clear();
|
||||
}
|
||||
|
||||
file class BoundedBuffer<T>(int capacity) : IBuffer<T>
|
||||
{
|
||||
private readonly LinkedList<T> _buffer = [];
|
||||
|
||||
public int Capacity { get; } = capacity;
|
||||
|
||||
public int Size => _buffer.Count;
|
||||
|
||||
public T? Get()
|
||||
{
|
||||
var head = _buffer.First;
|
||||
return head is null ? default : head.Value;
|
||||
}
|
||||
|
||||
public T? Get(int index)
|
||||
{
|
||||
var node = _buffer.First;
|
||||
if (node is null) return default;
|
||||
|
||||
for (var i = 0; i < index; i++)
|
||||
{
|
||||
node = node.Next;
|
||||
if (node is null) return default;
|
||||
}
|
||||
|
||||
return node.Value;
|
||||
}
|
||||
|
||||
public void Add(T value)
|
||||
{
|
||||
_buffer.AddFirst(value);
|
||||
|
||||
if (Size > Capacity)
|
||||
{
|
||||
_buffer.RemoveLast();
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() => _buffer.Clear();
|
||||
|
||||
public IEnumerator<T> GetEnumerator() => _buffer.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_buffer).GetEnumerator();
|
||||
}
|
||||
6
src/Disposer.cs
Normal file
6
src/Disposer.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
public sealed class Disposer(Action callback) : IDisposable
|
||||
{
|
||||
public void Dispose() => callback();
|
||||
}
|
||||
296
src/DrawContext.cs
Normal file
296
src/DrawContext.cs
Normal file
@@ -0,0 +1,296 @@
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
public sealed class DrawContext(Graphics g) : IDisposable
|
||||
{
|
||||
private readonly Stack<Context> _contexts = new();
|
||||
|
||||
// private Font font = (Font)SystemFonts.DefaultFont.Clone();
|
||||
private EllipseMode _ellipseMode = EllipseMode.Default;
|
||||
private RectMode _rectMode = RectMode.Default;
|
||||
private bool _noStroke, _noFill;
|
||||
|
||||
public Graphics Graphics { get; } = g;
|
||||
|
||||
public Pen DrawPen { get; private set; } = new(Color.White)
|
||||
{
|
||||
StartCap = LineCap.Round,
|
||||
EndCap = LineCap.Round,
|
||||
DashStyle = DashStyle.Solid,
|
||||
DashCap = DashCap.Round
|
||||
};
|
||||
|
||||
public Brush FillBrush { get; private set; } = new SolidBrush(Color.White);
|
||||
|
||||
public StringFormat TextAlignment { get; private set; } = new();
|
||||
|
||||
public void Push()
|
||||
{
|
||||
_contexts.Push(new Context(Graphics.Save(), (Pen)DrawPen.Clone(), (Brush)FillBrush.Clone(),
|
||||
(StringFormat)TextAlignment.Clone(), _ellipseMode, _rectMode, _noStroke, _noFill));
|
||||
}
|
||||
|
||||
public void Pop()
|
||||
{
|
||||
if (_contexts.Count > 0)
|
||||
{
|
||||
var ctx = _contexts.Pop();
|
||||
Graphics.Restore(ctx.GraphicsState);
|
||||
DrawPen.Dispose();
|
||||
DrawPen = ctx.DrawPen;
|
||||
FillBrush.Dispose();
|
||||
FillBrush = ctx.FillBrush;
|
||||
TextAlignment.Dispose();
|
||||
TextAlignment = ctx.StringFormat;
|
||||
_noStroke = ctx.NoStroke;
|
||||
_noFill = ctx.NoFill;
|
||||
}
|
||||
}
|
||||
|
||||
public void Stroke(int gray) => Stroke(gray, gray, gray);
|
||||
public void Stroke(int alpha, int gray) => Stroke(alpha, gray, gray, gray);
|
||||
public void Stroke(int red, int green, int blue) => Stroke(Color.FromArgb(red, green, blue));
|
||||
public void Stroke(int alpha, int red, int green, int blue) => Stroke(Color.FromArgb(alpha, red, green, blue));
|
||||
|
||||
public void Stroke(Color color)
|
||||
{
|
||||
DrawPen.Color = color;
|
||||
_noStroke = false;
|
||||
}
|
||||
|
||||
public void StrokeWeight(float strokeWeight)
|
||||
{
|
||||
DrawPen.Width = strokeWeight;
|
||||
}
|
||||
|
||||
public void StrokeCap(LineCap cap)
|
||||
{
|
||||
DrawPen.StartCap = cap;
|
||||
DrawPen.EndCap = cap;
|
||||
}
|
||||
|
||||
public void Fill(int gray) => Fill(gray, gray, gray);
|
||||
public void Fill(int alpha, int gray) => Fill(alpha, gray, gray, gray);
|
||||
public void Fill(int red, int green, int blue) => Fill(Color.FromArgb(red, green, blue));
|
||||
public void Fill(int alpha, int red, int green, int blue) => Fill(Color.FromArgb(alpha, red, green, blue));
|
||||
|
||||
public void Fill(Color color)
|
||||
{
|
||||
FillBrush.Dispose();
|
||||
FillBrush = new SolidBrush(color);
|
||||
_noFill = false;
|
||||
}
|
||||
|
||||
public void NoStroke()
|
||||
{
|
||||
_noStroke = true;
|
||||
}
|
||||
|
||||
public void NoFill()
|
||||
{
|
||||
_noFill = true;
|
||||
}
|
||||
|
||||
public void ResetDashes()
|
||||
{
|
||||
DrawPen.DashStyle = DashStyle.Solid;
|
||||
}
|
||||
|
||||
public void SetDashes(float filled, float empty)
|
||||
{
|
||||
DrawPen.DashStyle = DashStyle.Custom;
|
||||
DrawPen.DashPattern = [filled, empty];
|
||||
}
|
||||
|
||||
public void ResetTextAlign() => SetTextAlign(TextHorizontalAlignment.Default, TextVerticalAlignment.Default);
|
||||
|
||||
public void SetTextAlign(TextHorizontalAlignment hAlign = TextHorizontalAlignment.Unspecified,
|
||||
TextVerticalAlignment vAlign = TextVerticalAlignment.Unspecified)
|
||||
{
|
||||
if (hAlign is not TextHorizontalAlignment.Unspecified)
|
||||
{
|
||||
TextAlignment.Alignment = hAlign switch
|
||||
{
|
||||
TextHorizontalAlignment.Center => StringAlignment.Center,
|
||||
TextHorizontalAlignment.Left => StringAlignment.Near,
|
||||
TextHorizontalAlignment.Right => StringAlignment.Far,
|
||||
_ => throw new ArgumentException("Invalid horizontal alignment", nameof(hAlign))
|
||||
};
|
||||
}
|
||||
|
||||
if (vAlign is not TextVerticalAlignment.Unspecified)
|
||||
{
|
||||
TextAlignment.LineAlignment = vAlign switch
|
||||
{
|
||||
TextVerticalAlignment.Center => StringAlignment.Center,
|
||||
TextVerticalAlignment.Top => StringAlignment.Near,
|
||||
TextVerticalAlignment.Bottom => StringAlignment.Far,
|
||||
_ => throw new ArgumentException("Invalid vertical alignment", nameof(vAlign))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void SetEllipseMode(EllipseMode mode)
|
||||
{
|
||||
_ellipseMode = mode;
|
||||
}
|
||||
|
||||
public void SetRectMode(RectMode mode)
|
||||
{
|
||||
_rectMode = mode;
|
||||
}
|
||||
|
||||
// public void Arc(float x, float y, float width, float height, float startAngle, float sweepAngle)
|
||||
// {
|
||||
// g.DrawArc(drawPen, RectangleExtensions.FromCenter((int)speedGaugeX, (int)speedGaugeY, speedGaugeRect.Width - 16, speedGaugeRect.Height - 16), speedGaugeStartDeg, speedGaugeEndDeg);
|
||||
// }
|
||||
|
||||
// public void Rect(int x, int y, int width, int height)
|
||||
// {
|
||||
// if (!noFill)
|
||||
// {
|
||||
// g.FillRectangle(fillBrush, x, y, width, height);
|
||||
// }
|
||||
|
||||
// if (!noStroke)
|
||||
// {
|
||||
// g.DrawRectangle(DrawPen, x, y, width, height);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public void Rect(float x, float y, float width, float height)
|
||||
// {
|
||||
// if (!noFill)
|
||||
// {
|
||||
// g.FillRectangle(fillBrush, x, y, width, height);
|
||||
// }
|
||||
|
||||
// if (!noStroke)
|
||||
// {
|
||||
// g.DrawRectangle(DrawPen, x, y, width, height);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public void Circle(int x, int y, int width, int height)
|
||||
// {
|
||||
// if (!noFill)
|
||||
// {
|
||||
// g.FillEllipse(fillBrush, x, y, width, height);
|
||||
// }
|
||||
|
||||
// if (!noStroke)
|
||||
// {
|
||||
// g.DrawEllipse(DrawPen, x, y, width, height);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public void Circle(float x, float y, float width, float height)
|
||||
// {
|
||||
// if (!noFill)
|
||||
// {
|
||||
// g.FillRectangle(fillBrush, x, y, width, height);
|
||||
// }
|
||||
|
||||
// if (!noStroke)
|
||||
// {
|
||||
// g.DrawRectangle(DrawPen, x, y, width, height);
|
||||
// }
|
||||
// }
|
||||
|
||||
#region IDisposable
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposedValue) return;
|
||||
|
||||
DrawPen.Dispose();
|
||||
FillBrush.Dispose();
|
||||
TextAlignment.Dispose();
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public enum TextHorizontalAlignment
|
||||
{
|
||||
Unspecified,
|
||||
Center,
|
||||
Left,
|
||||
Right,
|
||||
Default = Left
|
||||
}
|
||||
|
||||
public enum TextVerticalAlignment
|
||||
{
|
||||
Unspecified,
|
||||
Center,
|
||||
Top,
|
||||
Bottom,
|
||||
Default = Center
|
||||
}
|
||||
|
||||
public enum EllipseMode
|
||||
{
|
||||
Center,
|
||||
Radius,
|
||||
Corner,
|
||||
Corners,
|
||||
Default = Center
|
||||
}
|
||||
|
||||
public enum RectMode
|
||||
{
|
||||
Center,
|
||||
Radius,
|
||||
Corner,
|
||||
Corners,
|
||||
Default = Corner
|
||||
}
|
||||
|
||||
private class Context(
|
||||
GraphicsState graphicsState,
|
||||
Pen drawPen,
|
||||
Brush fillBrush,
|
||||
StringFormat sf,
|
||||
EllipseMode ellipseMode,
|
||||
RectMode rectMode,
|
||||
bool noStroke,
|
||||
bool noFill) : IDisposable
|
||||
{
|
||||
public GraphicsState GraphicsState { get; } = graphicsState;
|
||||
public Pen DrawPen { get; } = drawPen;
|
||||
public Brush FillBrush { get; } = fillBrush;
|
||||
public StringFormat StringFormat { get; } = sf;
|
||||
public bool NoStroke { get; } = noStroke;
|
||||
public bool NoFill { get; } = noFill;
|
||||
public EllipseMode EllipseMode { get; } = ellipseMode;
|
||||
public RectMode RectMode { get; } = rectMode;
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
DrawPen.Dispose();
|
||||
FillBrush.Dispose();
|
||||
StringFormat.Dispose();
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/Listener.cs
Normal file
15
src/Listener.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
public static class Listener
|
||||
{
|
||||
public static Listener<T> Create<T>(Action<T> callback) => new(callback);
|
||||
}
|
||||
|
||||
public sealed class Listener<T>(Action<T> callback) : IObserver<T>
|
||||
{
|
||||
public void OnCompleted() { }
|
||||
|
||||
public void OnError(Exception error) { }
|
||||
|
||||
public void OnNext(T value) => callback(value);
|
||||
}
|
||||
16
src/Program.cs
Normal file
16
src/Program.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
// To customize application configuration such as set high DPI settings or default font,
|
||||
// see https://aka.ms/applicationconfiguration.
|
||||
ApplicationConfiguration.Initialize();
|
||||
Application.Run(new App());
|
||||
}
|
||||
}
|
||||
60
src/RectangleExtensions.cs
Normal file
60
src/RectangleExtensions.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
public static class RectangleExtensions
|
||||
{
|
||||
public static (Rectangle left, Rectangle right) SplitVerticallyAt(this Rectangle rect, int x) => (
|
||||
rect with { Width = x - rect.Left }, rect with { X = x, Width = rect.Right - x });
|
||||
|
||||
public static (Rectangle left, Rectangle right) SplitHorizontallyAt(this Rectangle rect, int y) => (
|
||||
rect with { Height = y - rect.Bottom }, rect with { Y = y, Height = rect.Bottom - y });
|
||||
|
||||
public static (Rectangle left, Rectangle right) SplitVertically(this Rectangle rect, int w) => (
|
||||
rect with { Width = w }, rect with { X = rect.X + w, Width = rect.Width - w });
|
||||
|
||||
public static (Rectangle left, Rectangle right) SplitHorizontally(this Rectangle rect, int h) => (
|
||||
rect with { Height = h }, rect with { Y = rect.Y + h, Height = rect.Height - h });
|
||||
|
||||
public static Rectangle[] SplitVerticallyInto(this Rectangle rect, int n)
|
||||
{
|
||||
var result = new Rectangle[n];
|
||||
SplitVerticallyInto(rect, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void SplitVerticallyInto(this Rectangle rect, Span<Rectangle> rects)
|
||||
{
|
||||
var n = rects.Length;
|
||||
var w = (float)rect.Width / n;
|
||||
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
rects[i] = rect with { X = (int)(i * w), Width = (int)w };
|
||||
}
|
||||
}
|
||||
|
||||
public static Rectangle[] SplitHorizontallyInto(this Rectangle rect, int n)
|
||||
{
|
||||
var result = new Rectangle[n];
|
||||
SplitHorizontallyInto(rect, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void SplitHorizontallyInto(this Rectangle rect, Span<Rectangle> rects)
|
||||
{
|
||||
var n = rects.Length;
|
||||
var h = (float)rect.Height / n;
|
||||
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
rects[i] = rect with { Y = (int)(i * h), Height = (int)h };
|
||||
}
|
||||
}
|
||||
|
||||
public static PointF GetCenter(this Rectangle rect) => new(rect.X + rect.Width / 2F, rect.Y + rect.Height / 2F);
|
||||
|
||||
public static Rectangle Centered(Point center, int width, int height) =>
|
||||
Centered(center.X, center.Y, width, height);
|
||||
|
||||
public static Rectangle Centered(int centerX, int centerY, int width, int height) =>
|
||||
new(centerX - width / 2, centerY - height / 2, width, height);
|
||||
}
|
||||
71
src/RectangleFExtensions.cs
Normal file
71
src/RectangleFExtensions.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
public static class RectangleFExtensions
|
||||
{
|
||||
public static (RectangleF left, RectangleF right) SplitVerticallyAt(this RectangleF rect, int x) => (
|
||||
rect with { Width = x - rect.Left }, rect with { X = x, Width = rect.Right - x });
|
||||
|
||||
public static (RectangleF left, RectangleF right) SplitHorizontallyAt(this RectangleF rect, int y) => (
|
||||
rect with { Height = y - rect.Bottom }, rect with { Y = y, Height = rect.Bottom - y });
|
||||
|
||||
public static (RectangleF left, RectangleF right) SplitVertically(this RectangleF rect, int w) => (
|
||||
rect with { Width = w }, rect with { X = rect.X + w, Width = rect.Width - w });
|
||||
|
||||
public static (RectangleF left, RectangleF right) SplitHorizontally(this RectangleF rect, int h) => (
|
||||
rect with { Height = h }, rect with { Y = rect.Y + h, Height = rect.Height - h });
|
||||
|
||||
public static RectangleF[] SplitVerticallyInto(this RectangleF rect, int n)
|
||||
{
|
||||
var result = new RectangleF[n];
|
||||
SplitVerticallyInto(rect, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void SplitVerticallyInto(this RectangleF rect, Span<RectangleF> rects)
|
||||
{
|
||||
var n = rects.Length;
|
||||
var w = rect.Width / n;
|
||||
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
rects[i] = rect with { X = i * w, Width = w };
|
||||
}
|
||||
}
|
||||
|
||||
public static RectangleF[] SplitHorizontallyInto(this RectangleF rect, int n)
|
||||
{
|
||||
var result = new RectangleF[n];
|
||||
SplitHorizontallyInto(rect, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void SplitHorizontallyInto(this RectangleF rect, Span<RectangleF> rects)
|
||||
{
|
||||
var n = rects.Length;
|
||||
var h = rect.Height / n;
|
||||
|
||||
for (var i = 0; i < n; i++)
|
||||
{
|
||||
rects[i] = rect with { Y = i * h, Height = h };
|
||||
}
|
||||
}
|
||||
|
||||
public static float GetCenterX(this RectangleF rect) => rect.X + rect.Width / 2F;
|
||||
public static float GetCenterY(this RectangleF rect) => rect.Y + rect.Height / 2F;
|
||||
public static PointF GetCenter(this RectangleF rect) => new(GetCenterX(rect), GetCenterY(rect));
|
||||
|
||||
public static RectangleF Centered(PointF center, float width, float height) =>
|
||||
Centered(center.X, center.Y, width, height);
|
||||
|
||||
public static RectangleF Centered(float centerX, float centerY, float width, float height) =>
|
||||
new(centerX - width / 2, centerY - height / 2, width, height);
|
||||
|
||||
public static RectangleF Scaled(this RectangleF rect, float scale) => Scaled(rect, scale, scale);
|
||||
public static RectangleF Scaled(this RectangleF rect, SizeF scale) => Scaled(rect, scale.Width, scale.Height);
|
||||
|
||||
public static RectangleF Scaled(this RectangleF rect, float scaleX, float scaleY) => new(rect.X * scaleX,
|
||||
rect.Y * scaleY, rect.Width * scaleX, rect.Height * scaleY);
|
||||
|
||||
public static Rectangle Round(this RectangleF rect) =>
|
||||
Rectangle.FromLTRB((int)rect.Left, (int)rect.Top, (int)rect.Right, (int)rect.Bottom);
|
||||
}
|
||||
33
src/Sample.cs
Normal file
33
src/Sample.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
public class Sample(long timestamp, bool drawTimeTick)
|
||||
{
|
||||
public long Timestamp { get; private set; } = timestamp;
|
||||
public bool DrawTimeTick { get; private set; } = drawTimeTick;
|
||||
public float Proportional { get; set; }
|
||||
public float Integral { get; set; }
|
||||
public float Derivative { get; set; }
|
||||
public float Speed { get; set; }
|
||||
public float Acceleration { get; set; }
|
||||
public float Consigne { get; set; }
|
||||
public float Error { get; set; }
|
||||
public int Servo { get; set; }
|
||||
public int ServoMin { get; set; }
|
||||
public int ServoMax { get; set; }
|
||||
public int ServoNeutre { get; set; }
|
||||
public bool Active { get; set; }
|
||||
public float Kp { get; set; }
|
||||
public float Ki { get; set; }
|
||||
public float Kd { get; set; }
|
||||
public int SpeedMin { get; set; }
|
||||
public int SpeedMax { get; set; }
|
||||
public bool BrakeFlag { get; set; }
|
||||
|
||||
public Sample Copy(long timestamp, bool drawTimeTick)
|
||||
{
|
||||
var copy = (Sample)MemberwiseClone();
|
||||
copy.Timestamp = timestamp;
|
||||
copy.DrawTimeTick = drawTimeTick;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
38
src/Splitter.cs
Normal file
38
src/Splitter.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
public class Splitter(string str)
|
||||
{
|
||||
private const char Delimiter = ',';
|
||||
|
||||
public delegate T ValueReader<out T>(ReadOnlySpan<char> s);
|
||||
|
||||
private int _pos = 0, _charCount = 0, _nextPos = 0;
|
||||
|
||||
private bool MoveNext()
|
||||
{
|
||||
_pos = _nextPos;
|
||||
var i = str.IndexOf(Delimiter, _pos);
|
||||
(_charCount, _nextPos) = i < 0 ? (str.Length - _pos, str.Length) : (i - _pos, i + 1);
|
||||
|
||||
return HasNext;
|
||||
}
|
||||
|
||||
private bool HasNext => _pos < str.Length;
|
||||
|
||||
private T Read<T>(ValueReader<T> reader) => MoveNext() ? reader(str.AsSpan(_pos, _charCount)) : throw new InvalidOperationException();
|
||||
|
||||
public string ReadString() => Read(static s => new string(s));
|
||||
|
||||
public bool ReadBool() => Read(static s => s.Length == 1 ? s[0] switch { '0' => false, '1' => true, _ => throw new InvalidDataException() } : throw new InvalidDataException());
|
||||
|
||||
public int ReadInt() => Read(static s => int.Parse(s, provider: CultureInfo.InvariantCulture));
|
||||
|
||||
public uint ReadUInt() => Read(static s => uint.Parse(s, provider: CultureInfo.InvariantCulture));
|
||||
|
||||
public float ReadFloat() => Read(static s => float.Parse(s, provider: CultureInfo.InvariantCulture));
|
||||
|
||||
public TParsable Read<TParsable>() where TParsable: ISpanParsable<TParsable> => Read(static s => TParsable.Parse(s, provider: CultureInfo.InvariantCulture));
|
||||
}
|
||||
19
src/Utils.cs
Normal file
19
src/Utils.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace CruiseControllerMX5;
|
||||
|
||||
public static class Utils
|
||||
{
|
||||
public static TTo Map<TFrom, TTo>(TFrom value, TFrom fromMin, TFrom fromMax, TTo toMin, TTo toMax)
|
||||
where TFrom : INumber<TFrom> where TTo : INumber<TTo> =>
|
||||
Map<TFrom, TTo, double>(value, fromMin, fromMax, toMin, toMax);
|
||||
|
||||
public static TTo Map<TFrom, TTo, TInt>(TFrom value, TFrom fromMin, TFrom fromMax, TTo toMin, TTo toMax)
|
||||
where TFrom : INumber<TFrom> where TTo : INumber<TTo> where TInt : INumber<TInt> => TTo.CreateChecked(
|
||||
TInt.CreateChecked(value - fromMin) / TInt.CreateChecked(fromMax - fromMin) *
|
||||
TInt.CreateChecked(toMax - toMin) + TInt.CreateChecked(toMin));
|
||||
|
||||
public static bool IntToBool(string value) => value.Equals("1", StringComparison.Ordinal);
|
||||
|
||||
public static int BoolToInt(bool value) => value ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user