应用在调用串口通讯时有时会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;
}
}
我目前正在为 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;
}
}