Changing serial port configurations programmatically in c#

后端 未结 1 1915
旧时难觅i
旧时难觅i 2020-12-11 07:11

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

相关标签:
1条回答
  • 2020-12-11 07:49

    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.");
        }        
    }
    
    0 讨论(0)
提交回复
热议问题