I have 2
types of devices that have different protocols and are connected with a single serial port. By protocol, I mean that serial port configurations are dif
The main problem with the last revision of your code is that you are calling Work()
without await
, so the call just creates an asynchronous background task and doesn't wait for its completion. Also, this functionality should not exist inside the constructor, but in a separate async
method.
Second suggestion is to remove the if
/switch
statements from the loop, and place the data needed to differentiate these protocols in a separate class. You could place any additional properties needed for each protocol inside this class:
// contains specific settings for each ProtocolId
class ProtocolCfg
{
public string ProtocolId { get; set; }
public string PortName { get; set; }
public int BaudRate { get; set; }
public Parity Parity { get; set; }
public int DataBits { get; set; }
public StopBits StopBits { get; set; }
public ProtocolCfg(string id, string port, int baud, Parity parity, int bits, StopBits stop)
{
ProtocolId = id; PortName = port; BaudRate = baud; Parity = parity;
DataBits = bits; StopBits = stop;
}
}
With this in place, your for
loop doesn't need to differentiate between these protocols:
class CombinedEngine
{
readonly ProtocolCfg[] _portConfigs;
public CombinedEngine(ProtocolCfg[] portConfigs)
{
// just assign the field and do nothing else
_portConfigs = portConfigs;
}
public async Task Run(CancellationToken cancelToken)
{
// repeat indefinitely
while (!cancelToken.IsCancellationRequested)
{
// run all protocols
foreach (var portcfg in _portConfigs)
{
SerialPort serialPort = null;
try
{
// init using current config
serialPort = new SerialPort(
portcfg.PortName, portcfg.BaudRate, portcfg.Parity,
portcfg.DataBits, portcfg.StopBits);
serialPort.ReadTimeout = 500;
// await data
var data = await serialPort.ReadAsync(4096);
// do something with this data
Console.WriteLine($"P{portcfg.ProtocolId}: {data.Length}B received");
// do other stuff here
// wait between protocol changes if needed?
await Task.Delay(500, cancelToken);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
serialPort?.Close();
serialPort?.Dispose();
}
}
// wait between iterations?
await Task.Delay(500, cancelToken);
}
}
}
When calling the Run
function, remember that it's async, so you need to call await
. However, you also may want to wait for a keypress inside the console, so in that case you would store the returned Task
in a variable, and cancel it when needed:
class Program
{
static void Main(string[] args)
{
// define all possible protocols
var protocols = new[]
{
new ProtocolCfg("01", "COM8", 9600, Parity.Even, 8, StopBits.One),
new ProtocolCfg("02", "COM8", 38400, Parity.None, 8, StopBits.One)
};
// we will need this to tell the async task to end
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
// note that this constructor does not do anything of importance
var engine = new CombinedEngine(protocols);
// this is where all the work is done, pass the cancellation token
var task = engine.Run(token);
// wait until Q is pressed
Console.WriteLine("Running, press Q to quit... ");
ConsoleKey k;
do { k = Console.ReadKey().Key; }
while (k != ConsoleKey.Q);
// shutdown
tokenSource.Cancel();
task.Wait();
Console.WriteLine("Done.");
}
}