pro3_control_panel_v2/ViewModels/UartConsoleViewModel.cs
2025-12-23 14:12:21 +08:00

168 lines
4.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Input;
using AmebaPro3_ControlPanel.Services.Uart;
using AmebaPro3_ControlPanel.Utilities;
namespace AmebaPro3_ControlPanel.ViewModels;
public class UartConsoleViewModel : ConsolePanelViewModel
{
private string? _selectedPort;
private int _baudRate;
private readonly PythonUartSession _uartSession;
private bool _isConnecting;
public UartConsoleViewModel(string title, int defaultBaudRate) : base(title)
{
_baudRate = defaultBaudRate;
_uartSession = new PythonUartSession(GetUartBridgePath(), SynchronizationContext.Current);
_uartSession.LineReceived += line => LogLines.Add(line);
_uartSession.ErrorReceived += line => LogLines.Add($"[UART ERROR] {line}");
_uartSession.Exited += OnSessionExited;
ConnectCommand = new RelayCommand(_ => ConnectAsync(), _ => !IsConnected && !_isConnecting && !string.IsNullOrWhiteSpace(SelectedPort));
DisconnectCommand = new RelayCommand(_ => Disconnect(), _ => IsConnected);
OpenTeraTermCommand = new RelayCommand(_ => OpenTeraTerm(), _ => !string.IsNullOrWhiteSpace(SelectedPort));
}
public ObservableCollection<string> AvailablePorts { get; } = new();
public string? SelectedPort
{
get => _selectedPort;
set
{
if (SetProperty(ref _selectedPort, value))
{
(ConnectCommand as RelayCommand)?.RaiseCanExecuteChanged();
(OpenTeraTermCommand as RelayCommand)?.RaiseCanExecuteChanged();
}
}
}
public int BaudRate
{
get => _baudRate;
set => SetProperty(ref _baudRate, value);
}
public ICommand ConnectCommand { get; }
public ICommand DisconnectCommand { get; }
public ICommand OpenTeraTermCommand { get; }
public void SetPorts(IEnumerable<string> ports)
{
AvailablePorts.Clear();
foreach (var port in ports)
{
AvailablePorts.Add(port);
}
if (string.IsNullOrWhiteSpace(SelectedPort))
{
SelectedPort = AvailablePorts.FirstOrDefault();
}
}
protected override void SendCurrentCommand(bool addToHistory)
{
if (string.IsNullOrWhiteSpace(CurrentCommand))
{
return;
}
var command = CurrentCommand.Trim();
base.SendCurrentCommand(addToHistory);
if (IsConnected)
{
_ = _uartSession.SendAsync(command);
}
else
{
LogLines.Add("[UART] Not connected.");
}
}
private async void ConnectAsync()
{
if (_isConnecting || string.IsNullOrWhiteSpace(SelectedPort))
{
return;
}
_isConnecting = true;
(ConnectCommand as RelayCommand)?.RaiseCanExecuteChanged();
LogLines.Add($"[UART] Connecting to {SelectedPort} @ {BaudRate}...");
var started = await _uartSession.StartAsync(SelectedPort, BaudRate);
if (started)
{
IsConnected = true;
LogLines.Add($"[UART] Connected to {SelectedPort} @ {BaudRate}.");
}
else
{
LogLines.Add("[UART] Failed to start session. Ensure Python + pyserial are installed.");
}
_isConnecting = false;
(DisconnectCommand as RelayCommand)?.RaiseCanExecuteChanged();
(ConnectCommand as RelayCommand)?.RaiseCanExecuteChanged();
}
private void Disconnect()
{
_ = DisconnectAsync();
}
private async System.Threading.Tasks.Task DisconnectAsync()
{
IsConnected = false;
_isConnecting = false;
(DisconnectCommand as RelayCommand)?.RaiseCanExecuteChanged();
(ConnectCommand as RelayCommand)?.RaiseCanExecuteChanged();
await _uartSession.StopAsync();
LogLines.Add("[UART] Disconnected.");
}
private void OnSessionExited()
{
if (!IsConnected)
{
return;
}
IsConnected = false;
_isConnecting = false;
LogLines.Add("[UART] Session closed.");
(DisconnectCommand as RelayCommand)?.RaiseCanExecuteChanged();
(ConnectCommand as RelayCommand)?.RaiseCanExecuteChanged();
}
private void OpenTeraTerm()
{
if (TeraTermLauncher.TryLaunch(SelectedPort, BaudRate, out var message))
{
LogLines.Add($"[UART] {message}");
}
else
{
LogLines.Add($"[UART] {message}");
}
}
private static string GetUartBridgePath()
{
return Path.Combine(AppContext.BaseDirectory, "Scripts", "uart_bridge.py");
}
}