This commit is contained in:
10
ModuleArduinoCompile/MainWindow.axaml
Normal file
10
ModuleArduinoCompile/MainWindow.axaml
Normal file
@@ -0,0 +1,10 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="ModuleWeather.WeatherView">
|
||||
<StackPanel Margin="20" Spacing="10" Background="#2b2b2b">
|
||||
<Button Content="Обновить" Click="Update"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
|
||||
<TextBlock Name="StatusText" Text="Выберите порт" Foreground="White"/>
|
||||
<ComboBox Name="PortComboBox" SelectionChanged="OnPortChanged"/>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
21
ModuleArduinoCompile/MainWindow.axaml.cs
Normal file
21
ModuleArduinoCompile/MainWindow.axaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ModuleWeather;
|
||||
|
||||
public partial class WeatherView : UserControl
|
||||
{
|
||||
public WeatherView() => InitializeComponent();
|
||||
|
||||
private void Update(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
private void OnPortChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
213
ModuleArduinoCompile/Module.cs
Normal file
213
ModuleArduinoCompile/Module.cs
Normal file
@@ -0,0 +1,213 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using VisionAsist.SDK;
|
||||
|
||||
namespace ModuleArduino;
|
||||
|
||||
public class ArduinoModule : IModule
|
||||
{
|
||||
public string Name => "ArduinoModule";
|
||||
public string Description => "Модуль для работы с COM-портами и прямой прошивки кода в Arduino";
|
||||
|
||||
public void Settings(object[] args) { }
|
||||
|
||||
public List<ToolDefinition> GetTools()
|
||||
{
|
||||
return new List<ToolDefinition>
|
||||
{
|
||||
new ToolDefinition
|
||||
{
|
||||
Name = "list_com_ports",
|
||||
Description = "Получает список всех доступных COM-портов в системе",
|
||||
ParametersSchema = "{\"type\": \"object\", \"properties\": {}}"
|
||||
},
|
||||
new ToolDefinition
|
||||
{
|
||||
Name = "send_serial_data",
|
||||
Description = "Отправляет строку в указанный COM-порт",
|
||||
ParametersSchema = JsonSerializer.Serialize(new
|
||||
{
|
||||
type = "object",
|
||||
properties = new
|
||||
{
|
||||
port = new { type = "string", description = "Имя порта (например, COM3)" },
|
||||
baudRate = new { type = "integer", description = "Скорость передачи (по умолчанию 9600)", @default = 9600 },
|
||||
data = new { type = "string", description = "Данные для отправки" }
|
||||
},
|
||||
required = new[] { "port", "data" }
|
||||
})
|
||||
},
|
||||
new ToolDefinition
|
||||
{
|
||||
Name = "read_serial_data",
|
||||
Description = "Читает любые доступные данные из указанного COM-порта",
|
||||
ParametersSchema = JsonSerializer.Serialize(new
|
||||
{
|
||||
type = "object",
|
||||
properties = new
|
||||
{
|
||||
port = new { type = "string", description = "Имя порта (например, COM3)" },
|
||||
baudRate = new { type = "integer", description = "Скорость передачи (по умолчанию 9600)", @default = 9600 },
|
||||
timeoutMs = new { type = "integer", description = "Максимальное время ожидания данных в миллисекундах (по умолчанию 3000)", @default = 3000 }
|
||||
},
|
||||
required = new[] { "port" }
|
||||
})
|
||||
},
|
||||
new ToolDefinition
|
||||
{
|
||||
Name = "compile_upload_code",
|
||||
Description = "Принимает исходный код C++ (Arduino), компилирует его и загружает на плату",
|
||||
ParametersSchema = JsonSerializer.Serialize(new
|
||||
{
|
||||
type = "object",
|
||||
properties = new
|
||||
{
|
||||
code = new { type = "string", description = "Полный текст скетча .ino (включая setup и loop)" },
|
||||
port = new { type = "string", description = "Имя порта (например, COM3)" },
|
||||
boardType = new { type = "string", description = "Тип платы (например, arduino:avr:uno)" }
|
||||
},
|
||||
required = new[] { "code", "port", "boardType" }
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public string Execute(string toolName, string argumentsJson)
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = JsonDocument.Parse(argumentsJson);
|
||||
var root = doc.RootElement;
|
||||
|
||||
switch (toolName)
|
||||
{
|
||||
case "list_com_ports":
|
||||
var ports = SerialPort.GetPortNames();
|
||||
return ports.Length > 0 ? string.Join(", ", ports) : "Порты не найдены";
|
||||
|
||||
case "send_serial_data":
|
||||
string portName = root.GetProperty("port").GetString()!;
|
||||
string data = root.GetProperty("data").GetString()!;
|
||||
int baud = root.TryGetProperty("baudRate", out var b) ? b.GetInt32() : 9600;
|
||||
|
||||
using (var serial = new SerialPort(portName, baud))
|
||||
{
|
||||
serial.DtrEnable = true; // Важно для многих плат Arduino
|
||||
serial.RtsEnable = true;
|
||||
serial.Open();
|
||||
serial.WriteLine(data);
|
||||
Thread.Sleep(100); // Даем время на отправку
|
||||
serial.Close();
|
||||
}
|
||||
return $"Отправлено в {portName}: {data}";
|
||||
|
||||
case "read_serial_data":
|
||||
string rPortName = root.GetProperty("port").GetString()!;
|
||||
int rBaud = root.TryGetProperty("baudRate", out var rb) ? rb.GetInt32() : 9600;
|
||||
int timeout = root.TryGetProperty("timeoutMs", out var rt) ? rt.GetInt32() : 3000;
|
||||
|
||||
using (var serial = new SerialPort(rPortName, rBaud))
|
||||
{
|
||||
serial.DtrEnable = true; // Без этого Arduino может не слать данные
|
||||
serial.RtsEnable = true;
|
||||
serial.Open();
|
||||
|
||||
// После открытия порта Arduino может перезагрузиться,
|
||||
// дадим ей немного времени прийти в себя
|
||||
Thread.Sleep(500);
|
||||
|
||||
int waited = 500;
|
||||
while (serial.BytesToRead == 0 && waited < timeout)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
waited += 100;
|
||||
}
|
||||
|
||||
if (serial.BytesToRead > 0)
|
||||
{
|
||||
string received = serial.ReadExisting();
|
||||
serial.Close();
|
||||
return $"Получено из {rPortName}: {received}";
|
||||
}
|
||||
|
||||
serial.Close();
|
||||
return $"Данные из {rPortName} не поступили за {timeout}мс.";
|
||||
}
|
||||
|
||||
case "compile_upload_code":
|
||||
string code = root.GetProperty("code").GetString()!;
|
||||
string p = root.GetProperty("port").GetString()!;
|
||||
string board = root.GetProperty("boardType").GetString()!;
|
||||
return HandleCompileAndUpload(code, p, board);
|
||||
|
||||
default:
|
||||
return "Инструмент не найден";
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { return $"Ошибка: {ex.Message}"; }
|
||||
}
|
||||
|
||||
private string HandleCompileAndUpload(string code, string port, string board)
|
||||
{
|
||||
string tempDir = Path.Combine(Path.GetTempPath(), "VisionAsist_Arduino_" + Guid.NewGuid().ToString("N"));
|
||||
string sketchName = "Sketch";
|
||||
string sketchDir = Path.Combine(tempDir, sketchName);
|
||||
string sketchPath = Path.Combine(sketchDir, sketchName + ".ino");
|
||||
|
||||
string modulePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
|
||||
string arduinoCliPath = Path.Combine(modulePath, "arduino-cli.exe");
|
||||
if (!File.Exists(arduinoCliPath)) arduinoCliPath = "arduino-cli";
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(sketchDir);
|
||||
File.WriteAllText(sketchPath, code);
|
||||
|
||||
var compileResult = RunCommand(arduinoCliPath, $"compile --fqbn {board} \"{sketchDir}\"");
|
||||
if (compileResult.ExitCode != 0) return $"Ошибка компиляции:\n{compileResult.Error}";
|
||||
|
||||
var uploadResult = RunCommand(arduinoCliPath, $"upload -p {port} --fqbn {board} \"{sketchDir}\"");
|
||||
if (uploadResult.ExitCode != 0) return $"Ошибка загрузки:\n{uploadResult.Error}";
|
||||
|
||||
return "Код успешно скомпилирован и загружен в Arduino!";
|
||||
}
|
||||
catch (Exception ex) { return $"Критическая ошибка: {ex.Message}"; }
|
||||
finally
|
||||
{
|
||||
try { if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private (int ExitCode, string Output, string Error) RunCommand(string cmd, string args)
|
||||
{
|
||||
try
|
||||
{
|
||||
var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = cmd,
|
||||
Arguments = args,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
});
|
||||
|
||||
string output = process?.StandardOutput.ReadToEnd() ?? "";
|
||||
string error = process?.StandardError.ReadToEnd() ?? "";
|
||||
process?.WaitForExit();
|
||||
|
||||
return (process?.ExitCode ?? -1, output, error);
|
||||
}
|
||||
catch (System.ComponentModel.Win32Exception)
|
||||
{
|
||||
return (-1, "", $"Ошибка: Исполняемый файл '{cmd}' не найден в папке модуля или в системе.");
|
||||
}
|
||||
}
|
||||
}
|
||||
38
ModuleArduinoCompile/ModuleArduinoCompile.csproj
Normal file
38
ModuleArduinoCompile/ModuleArduinoCompile.csproj
Normal file
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AssemblyName>ArduinoModule</AssemblyName>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VisionAsist.SDK\VisionAsist.SDK.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.3.12" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.3.12" />
|
||||
<PackageReference Include="System.IO.Ports" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
<Target Name="CopyModuleToCore" AfterTargets="PostBuildEvent">
|
||||
<ItemGroup>
|
||||
<!-- Копируем ВСЕ DLL и PDB рекурсивно, чтобы не потерять зависимости NuGet -->
|
||||
<ModuleFiles Include="$(TargetDir)**\*.dll" />
|
||||
<ModuleFiles Include="$(TargetDir)**\*.pdb" />
|
||||
</ItemGroup>
|
||||
|
||||
<Message Text="Копирую файлы модуля и все зависимости..." Importance="high" />
|
||||
|
||||
<Copy SourceFiles="@(ModuleFiles)"
|
||||
DestinationFolder="E:\Project\Visual\VisionAsist\VisionAsist\bin\Debug\net10.0\Modules\ArduinoModule"
|
||||
OverwriteReadOnlyFiles="true" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<Compile Update="MainWindow.axaml.cs">
|
||||
<DependentUpon>MainWindow.axaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user