Files
2026-07-13 13:13:17 +08:00

97 lines
4.9 KiB
C#

#nullable enable
using T3.Core.IO;
using T3.IoServices;
namespace Lib.io.serial;
[Guid("B469D554-A69F-44A0-A03F-331853B82199")]
internal sealed class SerialOutput : Instance<SerialOutput>, IStatusProvider, ICustomDropdownHolder, IDisposable
{
[Output(Guid = "26C9848A-7067-4592-AE8D-26496F435017")] public readonly Slot<Command> Result = new();
[Output(Guid = "1B91E3A7-92F6-44A2-B086-A82FDEE9426D")] public readonly Slot<bool> IsConnected = new();
public SerialOutput() { Result.UpdateAction = Update; IsConnected.UpdateAction = Update; }
private string? _lastPortName;
private int _lastBaudRate;
private bool _lastConnectState;
private string? _lastSentMessage;
private void Update(EvaluationContext context)
{
var shouldConnect = Connect.GetValue(context);
var portName = PortName.GetValue(context) ?? string.Empty;
var baudRate = BaudRate.GetValue(context);
var settingsChanged = portName != _lastPortName || baudRate != _lastBaudRate || shouldConnect != _lastConnectState;
if (settingsChanged)
{
SerialConnectionManager.Unregister(this, _lastPortName);
if (shouldConnect)
{
try
{
SerialConnectionManager.Register(this, portName, baudRate, null, PortModes.Standard);
SetStatus($"Connected to {portName}", IStatusProvider.StatusLevel.Success);
}
catch (Exception e) { SetStatus($"Failed to connect: {e.Message}", IStatusProvider.StatusLevel.Error); }
}
else { SetStatus("Disconnected", IStatusProvider.StatusLevel.Notice); }
_lastPortName = portName;
_lastBaudRate = baudRate;
_lastConnectState = shouldConnect;
}
var isConnected = SerialConnectionManager.IsPortOpen(portName);
IsConnected.Value = isConnected;
var sendOnChange = SendOnChange.GetValue(context);
var separator = Separator.GetValue(context) ?? "";
var messageParts = MessageParts.GetCollectedTypedInputs().Select(p => p.GetValue(context));
var currentMessage = string.Join(separator, messageParts);
var hasMessageChanged = currentMessage != _lastSentMessage;
var manualTrigger = SendTrigger.GetValue(context);
var shouldSend = manualTrigger || (sendOnChange && hasMessageChanged);
if (isConnected && shouldSend)
{
if (manualTrigger) SendTrigger.SetTypedInputValue(false);
if (!string.IsNullOrEmpty(currentMessage) && !string.IsNullOrEmpty(portName))
{
if (AddLineEnding.GetValue(context))
{
SerialConnectionManager.WriteLine(portName, currentMessage);
}
else
{
SerialConnectionManager.Write(portName, currentMessage);
}
_lastSentMessage = currentMessage;
}
}
}
public void Dispose() { SerialConnectionManager.Unregister(this, PortName.Value); }
private string? _lastErrorMessage;
private IStatusProvider.StatusLevel _statusLevel = IStatusProvider.StatusLevel.Notice;
public void SetStatus(string m, IStatusProvider.StatusLevel l) { _lastErrorMessage = m; _statusLevel = l; }
public IStatusProvider.StatusLevel GetStatusLevel() => _statusLevel;
public string? GetStatusMessage() => _lastErrorMessage;
string ICustomDropdownHolder.GetValueForInput(Guid id) => id == PortName.Id ? PortName.Value ?? string.Empty : string.Empty;
IEnumerable<string> ICustomDropdownHolder.GetOptionsForInput(Guid id) => id == PortName.Id ? SerialConnectionManager.GetAvailableSerialPortsWithDescriptions() : Enumerable.Empty<string>();
void ICustomDropdownHolder.HandleResultForInput(Guid id, string? s, bool i)
{
if (string.IsNullOrEmpty(s) || !i || id != PortName.Id) return;
PortName.SetTypedInputValue(SerialConnectionManager.GetPortNameFromDeviceDescription(s));
}
[Input(Guid = "3F9E404B-993A-427E-8367-9A9772F76426")] public readonly InputSlot<string> PortName = new();
[Input(Guid = "262D4A18-354A-4835-9B22-458DB18579E7")] public readonly InputSlot<int> BaudRate = new(9600);
[Input(Guid = "AA199834-537D-4C67-9ECB-88358252D263")] public readonly MultiInputSlot<string> MessageParts = new();
[Input(Guid = "B9C6837C-4AD3-424C-976E-1E4552A85523")] public readonly InputSlot<string> Separator = new(" ");
[Input(Guid = "C796590A-335B-4C21-8898-356D3B69601F")] public readonly InputSlot<bool> SendTrigger = new();
[Input(Guid = "A0E35517-337A-4770-985A-34CAC95B5B5F")] public readonly InputSlot<bool> SendOnChange = new(true);
[Input(Guid = "DAF8E832-6D55-4424-AEF9-A92543B1A796")] public readonly InputSlot<bool> AddLineEnding = new(true);
[Input(Guid = "7414A929-8A33-405D-A466-933E31972B57")] public readonly InputSlot<bool> Connect = new();
}