应用在调用串口通讯时有时会freezes/crashes。如何解决?

App sometimes freezes/crashes when invoking serial port communication. How to fix that?

我目前正在为 Raspberry Pi 开发一个 WIn IoT 应用程序,我在那里遇到了一个严重的问题......我真的需要一些帮助来解决这个......

我遇到的问题是我通过串行端口发送了不同的命令,并且每个命令收到不同的响应。

发送几条命令后(可以是一条,也可以是 15 条...基本上是随机的 -.-)我的应用程序只是停止接受要发送的命令,或者当我调用其中一条命令时完全崩溃。它是随机发生的,当我重新启动应用程序时它又能正常工作了。 至少大部分时间...有时第一次重启没有任何作用,我必须再次重启...

由于该应用程序可能会用于更大的项目,因此我想保证完美执行。我不想让客户(或我们用来与 Pi 通信的工具)重新启动整个应用程序。它应该只是中止它的非工作操作,记录错误然后备份运行ning。

我认为缓冲区可能出于某种原因溢出...但我不知道有什么方法可以从 UWP 中的代码中清除缓冲区。我似乎找不到任何相关信息。

如果你能帮助我,我会很高兴。我试图让它工作将近一个星期,但我找不到问题...

我的同事上周重写了我的一些代码。我最初通过元组传递我需要的所有信息,但他告诉我这不好。所以他为我写了包含信息的class。但是从那以后我运行陷入了很多问题。但是我真的不知道为什么不...

如果您想了解更多关于我的代码的信息,请随时询问。我真的需要这个来工作:/

我使用的一些代码:

这是包含我的数据的块:

public class InfoBlock
{
    public List<InfoBlockValue> Names { get; set; }

    public byte[] ReceivedCrcSum { get; set; }

    public byte[] CalculatedCrcSum { get; set; }

    public bool IsChecksumEqual { get; set; } = false;
}

public class InfoBlockValue
{
    public string InfoString { get; set; }

    public InfoBlockValue(string info)
    {
        this.InfoString = info;
    }

    public override string ToString()
    {
        return InfoString;
    }
}

这是我的读写操作的class:

public class GetInfoBlock
{
    public string SendCommand { get; set; } = "##getnames";

    public async Task<uint> Write()
    {
        byte CarriageReturn = 0x0D;

        byte[] WriteArray = StringToByteArray(SendCommand);

        byte[] WriteArrayCR = new byte[WriteArray.Length + 1];
        WriteArray.CopyTo(WriteArrayCR, 0);
        WriteArrayCR[WriteArray.Length] = CarriageReturn;

        return await ReadWriteAdapter.Current.WriteAsync(WriteArrayCR);
    }

    public async Task<InfoBlock> Read()
    {
        InfoBlock block = new InfoBlock();

        byte[] ListenOut = await ReadWriteAdapter.Current.Listen(5802);

        byte[] NameCrcSource = new byte[5800];
        byte[] NameCrc16 = new byte[2];

        Array.Copy(ListenOut, 0, NameCrcSource, 0, 5800);

        block.Names = ConvertFromBytes(NameCrcSource);
        block.ReceivedCrcSum = new byte[] { ListenOut[5801], ListenOut[5800] };

        block.CalculatedCrcSum = Crc16Ccitt.ComputeChecksumBytes(NameCrcSource);
        block.IsChecksumEqual = ValidateDataCRC.ValidateData(NameCrcSource, block.ReceivedCrcSum);

        return block;
    }

    public List<InfoBlockValue> ConvertFromBytes(byte[] dataFromDrive)
    {
        List<InfoBlockValue> InfoValue = new List<InfoBlockValue>();

        string[] allConvertedIntegers = new String[100];

        int lastReadByte = 0;
        int parameterIndex = 0;
        int parameterByteIndex = 0;

        for (parameterIndex = 0; parameterIndex < 99; parameterIndex++)
        {
            byte[] allBytesOfOneParameter = new byte[28];                                

            Array.Copy(dataFromDrive, lastReadByte + 1, allBytesOfOneParameter, 0, 28);

            InfoValue.Add(new InfoBlockValue(System.Text.Encoding.UTF8.GetString(allBytesOfOneParameter)));

            parameterByteIndex = 0;
            lastReadByte += 29;
        }

        return InfoValue;
    }

    public byte[] StringToByteArray(string str)
    {
        System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
        return enc.GetBytes(str);
    }
}

这是我使用操作的代码:

public class ReadInfo
{
    private GetInfoBlock InfoBlock = null;

    public async Task<Tuple<string, InfoBlock>> ReadNamesBlock()
    {
        if (InfoBlock == null)
        {
            InfoBlock = new GetInfoBlock();
        }

        await ReadWriteAdapter.semaphore.WaitAsync();

        string returnString = string.Empty;

        uint writeTuple = await InfoBlock.Write();

        try
        {
            InfoBlock readTuple = await NamesBlock.Read();

            bool validationResult = readTuple.IsChecksumEqual;

            if (validationResult)
            {
                returnString += $"Checksum {BitConverter.ToString(readTuple.CalculatedCrcSum)} ReceivedCrcSum: {BitConverter.ToString(readTuple.ReceivedCrcSum)}";

                //await ValidateDataCRC.SendAck();

            }
            else
            {
                returnString += "Checksum error";

                await ValidateDataCRC.SendNack();
            }

            return new Tuple<string, InfoBlock>(returnString, readTuple);
        }
        catch (Exception ex)
        {
            string exception = $"Error while reading the parameternames from the device: {ex.Message}";

            return new Tuple<string, InfoBlock>(exception, null);
        }
        finally
        {
            NamesBlock = null;
            ReadWriteAdapter.semaphore.Release();
        }
    }
}

最后一个是我的 ReadWriteAdapter:

public class ReadWriteAdapter
{
    public static SemaphoreSlim semaphore = new SemaphoreSlim(1);

    private static readonly Object lockObject = new object();
    private static ReadWriteAdapter instance;

    public static ReadWriteAdapter Current
    {
        get
        {
            if (instance == null)
            {
                lock (lockObject)
                {
                    if (instance == null)
                    {
                        instance = new ReadWriteAdapter();
                    }
                }
            }
            return instance;
        }
    }


    private DataWriter dataWriter = null;
    private DataReader dataReader = null;

    private CancellationTokenSource ReadCancellationTokenSource;
    private SerialDevice serialPort = null;

    public bool IsDeviceInitialized()
    {
        return serialPort != null;
    }


    public async Task<string> Init()
    {
        try
        {
            string aqs = SerialDevice.GetDeviceSelector();

            DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(aqs, null);

            if (devices.Any())
            {
                if (devices[0].Id.Contains("FTDI"))
                {
                    string deviceId = devices[0].Id;
                    await OpenPort(deviceId);
                }
                else
                {
                    string deviceId = devices[1].Id;
                    await OpenPort(deviceId);
                }

                ReadCancellationTokenSource = new CancellationTokenSource();

                dataWriter = new DataWriter(serialPort.OutputStream);
                dataReader = new DataReader(serialPort.InputStream);
                return "found port";
            }
            return "nodevices";
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }

    private async Task OpenPort(string deviceId)
    {
        serialPort = await SerialDevice.FromIdAsync(deviceId);

        if (serialPort != null)
        {
            serialPort.WriteTimeout = TimeSpan.FromMilliseconds(500);
            serialPort.ReadTimeout = TimeSpan.FromMilliseconds(500);
            serialPort.BaudRate = 19200;
            serialPort.Parity = SerialParity.None;
            serialPort.StopBits = SerialStopBitCount.One;
            serialPort.DataBits = 8;
            serialPort.Handshake = SerialHandshake.None;
        }
    }


    private async Task<byte[]> ReadAsync(CancellationToken cancellationToken, uint ReadBufferLength)
    {
        Task<uint> loadAsyncTask;
        byte[] returnArray = new byte[ReadBufferLength];

        dataReader.InputStreamOptions = InputStreamOptions.Partial;

        loadAsyncTask = dataReader.LoadAsync(ReadBufferLength).AsTask(cancellationToken);   // Create a task object

        uint bytesRead = await loadAsyncTask;    // Launch the task and wait until buffer would be full

        if (bytesRead > 0)
        {
            dataReader.ReadBytes(returnArray);
        }

        return returnArray;
    }

    public async Task<uint> WriteAsync(byte[] data)
    {
        if (serialPort == null)
        {
            throw new ArgumentNullException("device");
        }
        if (dataWriter == null)
        {
            throw new ArgumentNullException("device");
        }

        if (data.Length != 0)
        {                
            dataWriter.WriteBytes(data);

            // Launch an async task to complete the write operation
            Task<uint> storeAsyncTask = dataWriter.StoreAsync().AsTask();

            return await storeAsyncTask;
        }
        else
        {
            return 0;
        }
    }

    public async Task<byte[]> Listen(uint BufferLength)
    {
        byte[] listen = new byte[BufferLength];

        try
        {
            if (serialPort != null)
            {
                dataReader = new DataReader(serialPort.InputStream);

                listen = await ReadAsync(ReadCancellationTokenSource.Token, BufferLength);
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            if (dataReader != null)    // Cleanup once complete
            {
                dataReader.DetachStream();
                dataReader = null;
            }
        }

        return listen;
    }
}

自己找到了答案...

我不得不在使用完 dataReader 后对其进行处理。 我想我在 reader 上的流数量刚刚溢出或其他什么。

在 ReadWriteAdapter 中更改了此项:

finally
    {
        if (dataReader != null)    // Cleanup once complete
        {
            dataReader.DetachStream();
            dataReader = null;
        }
    }

为此:

finally
    {
        if (dataReader != null)    // Cleanup once complete
        {
            dataReader.DetachStream();
            dataReader.Dispose();  //Added this part
            dataReader = null;
        }
    }