113 lines
3.0 KiB
C#
113 lines
3.0 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using System.IO.Ports;
|
|
using System.Reactive.Linq;
|
|
using CliWrap;
|
|
using InnovEnergy.Lib.Utils;
|
|
|
|
namespace InnovEnergy.Lib.Protocols.Modbus.Connections;
|
|
|
|
public class RemoteSerialConnection : ModbusConnection
|
|
{
|
|
private readonly Command _Command;
|
|
private ObservableProcess? _ObservableProcess;
|
|
private Func<Int32, Task<IReadOnlyList<Byte>>>? _Read;
|
|
|
|
|
|
public RemoteSerialConnection(SshHost host,
|
|
String tty,
|
|
Int32 baudRate,
|
|
Parity parity,
|
|
Int32 stopBits,
|
|
Int32 dataBits)
|
|
{
|
|
tty = tty.EnsureStartsWith("/dev/");
|
|
|
|
var configure = ConfigureTty(tty, baudRate, parity, stopBits, dataBits);
|
|
|
|
// https://unix.stackexchange.com/questions/19604/all-about-ssh-proxycommand
|
|
|
|
var call = $"{configure}; " +
|
|
$"exec 3<>{tty}; " +
|
|
$"cat <&3 & cat >&3; " +
|
|
$"kill $!";
|
|
|
|
_Command = host
|
|
.Command
|
|
.AppendArgument(call);
|
|
|
|
_Command.WriteLine();
|
|
}
|
|
|
|
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
|
private static String ConfigureTty(String tty, Int32 baudRate, Parity parity, Int32 stopBits, Int32 dataBits)
|
|
{
|
|
var oParity = parity switch
|
|
{
|
|
Parity.Even => "parenb -parodd",
|
|
Parity.Odd => "parenb parodd",
|
|
Parity.None => "-parenb",
|
|
_ => throw new NotImplementedException()
|
|
};
|
|
|
|
var oStopBits = stopBits switch
|
|
{
|
|
1 => "-cstopb",
|
|
2 => "cstopb",
|
|
_ => throw new NotImplementedException()
|
|
};
|
|
|
|
var oDataBits = "cs" + dataBits;
|
|
|
|
return $"stty -F {tty} {baudRate} {oDataBits} {oStopBits} {oParity}";
|
|
}
|
|
|
|
public override IReadOnlyList<Byte> Receive(UInt16 bytesToRead)
|
|
{
|
|
Open();
|
|
|
|
return _Read!(bytesToRead).Result;
|
|
}
|
|
|
|
public override void Transmit(IEnumerable<Byte> bytes)
|
|
{
|
|
Open();
|
|
try
|
|
{
|
|
_ObservableProcess!.StdIn.OnNext(bytes.ToArray());
|
|
}
|
|
catch
|
|
{
|
|
Close();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
|
|
public override void Open()
|
|
{
|
|
if (_ObservableProcess is not null)
|
|
return;
|
|
|
|
_ObservableProcess = new ObservableProcess(_Command);
|
|
|
|
_ObservableProcess.Start();
|
|
|
|
_Read = _ObservableProcess
|
|
.StdOut
|
|
.Select(b => b.ToArray())
|
|
.SelectMany(t => t)
|
|
.PushToPull();
|
|
}
|
|
|
|
public override void Close()
|
|
{
|
|
throw new NotImplementedException();
|
|
|
|
// if (_ObservableProcess is null)
|
|
// return;
|
|
|
|
// https://stackoverflow.com/questions/6960520/when-to-dispose-cancellationtokensource
|
|
|
|
|
|
}
|
|
} |