在调用串行端口通信时,应用程序有时会冻结/崩溃。如何解决?

时间:2018-01-31 14:54:14

标签: c# uwp win-universal-app windows-10-universal windowsiot

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

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

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

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

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

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

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

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

我正在使用的一些代码:

这是包含我的数据的块:

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;
    }
}

这是我的读写操作的类:

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;
    }
}

1 个答案:

答案 0 :(得分:1)

我自己找到答案......

我使用后必须处理dataReader。 我想我在阅读器上的流量只是溢出或其他什么。

在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;
        }
    }