Проблема получения данных из SerialPort в службе C#

287
21 декабря 2017, 23:15

Цель - создать службу в windows которая считывает данные из COM порта обрабатывает и в данном случае будет писать в текстовый файл. Собственно проблема в следующем, не могу получить данные из SerialPort знаю точно что порт открыт,знаю точно что порт отправляет данные. При попытке прочитать строку ReadLine() не получает ничего.

Как решить эту проблему?

public partial class Service1 : ServiceBase
{
    public Service1()
    {
        InitializeComponent();
        this.CanStop = true;
        this.CanPauseAndContinue = true;
        this.AutoLog = true;
    }
    comWatcher cWatch;
    protected override void OnStart(string[] args)
    {
        cWatch = new comWatcher();
        Thread watcher = new Thread(new ThreadStart(cWatch.Start));
        watcher.Start();
    }
    protected override void OnStop()
    {
        cWatch.Stop();
        Thread.Sleep(1000);
    }
}
class comWatcher
{
    SerialPort port;
    bool enabled = true;
    public comWatcher()
    {
        Log("start");
        this.port = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
        this.port.DataReceived += port_DataReceived;
    }
    void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        Log(port.ReadLine());
    }
    public void Start()
    {
        try
        {
            this.port.Open();
        }
        catch (IOException io)
        {
            Log(io.Message);
        }
        while (enabled)
        {
            Thread.Sleep(1000);
        }
    }
    public void Stop()
    {
        port.Close();
        enabled = false;
    }
    public void Log(string message)
    {
        File.AppendAllText(@"C:\\log.txt", message);
    }
}
Answer 1

Вы делаете неправильно.

Приход сообщения DataReceived означает лишь, что в порту появились данные, но не означает, что их набралось на целую строку. То, что в порт данные записываются построчно, вовсе не даёт гарантии, что они будут и приходить построчно тоже.

Если вы хотите вычитать все имеющиеся данные, имеет смысл использовать port.ReadExisting() вместо ReadLine.

Но более хорошей альтернативой мне кажется получение у порта BaseStream и работа с ним, как с потоком (не со строками, а с байтами):

class ComWatcher
{
    SerialPort port;
    bool enabled = true;
    CancellationTokenSource cts;
    public ComWatcher()
    {
        this.port = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
    }
    public async void Start()
    {
        if (cts != null)
            throw new InvalidOperationException("Already started");
        cts = new CancellationTokenSource();
        var ct = cts.Token;
        try
        {
            port.Open();
            byte[] buf = new byte[256];
            var stream = port.BaseStream;
            using (var outf = File.OpenWrite(@"C:\\log.txt"))
            while (!ct.IsCancellationRequested)
            {
                var actuallyRead = await stream.ReadAsync(buf, 0, buf.Length, ct);
                if (actuallyRead == 0) // end of stream
                    return;
                await outf.WriteAsync(buf, 0, actuallyRead);
            }
        }
        catch (IOException io)
        {
            if (!ct.IsCancellationRequested)
                LogError(io.Message);
        }
    }
    public void Stop()
    {
        var cts = this.cts;
        this.cts = null;
        if (cts == null)
            throw new InvalidOperationException("Not started");
        port.Close();
        cts.Cancel();
    }
}
READ ALSO
Как сериализовать два объекта

Как сериализовать два объекта

Как сериализовать два объекта (Контейнеры)? Пример

233
ViewModel - одна или несколько вложенных

ViewModel - одна или несколько вложенных

Имеется (c# wpf) окно, в котором динамически показываются разные контролы (фреймы)Набор показываемых контролов определяется в главной vm

225
Построение Master/Slave системы сервисов на базе WCF

Построение Master/Slave системы сервисов на базе WCF

Я понимаю общие принципы Master/Slave, но как это красиво наложить на WCF очень туманно вижу

201
Переопределение функций свойств get/set

Переопределение функций свойств get/set

Задача: слияние узлов XML и классов, где свойства помеченные атрибутом ToXmlAttribute, являются атрибутами Xml (Node Name=""):

432