是什么阻止我的事件处理程序方法完成?
What is preventing my event handler method from completing?
我正在使用 SerialPort、用于用户界面的 WPF、用于处理应用程序逻辑的 'ui' 对象以及 SerialPort 的包装器。
当触发 SerialPort.DataReceived 事件时调用相关方法。它开始 运行,然后在读取数据后,似乎就退出了,尽管它还有很多事情要做。
它似乎没有抛出任何异常,它不像卡在循环中一样(同步读取应该超时 + 我会得到大量 "I READ A THING"),而且我我难住了。几乎所有的 GiveFeedback 调用都是我尝试调试正在发生的事情的结果,因为我无法在我正在写这篇文章的机器上进行测试。
'ui' 符号指的是在调用 GiveFeedback(string) 时触发事件的对象,最终通过调用 Dispatcher.BeginInvoke(stuff) 更新文本框的内容。
完整代码如下:
public void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
ui.GiveFeedback("DataReceived... Begin");
List<byte> bytes = new List<byte>();
int r = comm.comPort.ReadByte();
while ( r != -1 )
{
bytes.Add((byte) r);
try
{
r = comm.comPort.ReadByte();
}
catch(Exception ioe)
{
r = -1;
ui.GiveFeedback(ioe.Message);
}
ui.GiveFeedback("read a byte...");
ui.GiveFeedback("read : '" + System.Text.Encoding.ASCII.GetString(bytes.ToArray()) + "'");
}
//It NEVER reaches this line.
//It NEVER throws an exception of any kind.
throw new ApplicationException("I threw myself");
i.GiveFeedback("done read : '" + System.Text.Encoding.ASCII.GetString(bytes.ToArray()) + "'");
string msg = BitConverter.ToString(bytes.ToArray()).Replace("-", " ");
string submsg;
if ( msg.Length > 5 )
submsg = msg.Substring(0, 5);
else
{
submsg = msg.Substring(0, 2);
}
ui.GiveFeedback("msg: " + msg);
ui.GiveFeedback("submsg: " + submsg);
switch ( submsg )
{
case "10":
ui.GiveFeedback("'Incoming -- VMC: Reset - 10' -- CommInterface");
ACK();
break;
case "00":
//DisplayData(MessageType.Incoming, " VMC: ACK - 00\n");
ui.GiveFeedback("'Incoming -- VMC: ACK - 00' -- CommInterface");
break;
case "12":
ui.GiveFeedback("'Incoming -- VMC: Poll - 12' -- CommInterface");
switch ( ui.Stage )
{
case Stages.SessionSelect:
BeginSession();
Poll();
break;
default:
ACK();
break;
}
break;
case "14 01":
//DisplayData(MessageType.Incoming, " VMC: Enable Reader - 14 01\n");
ui.GiveFeedback("'Incoming -- VMC: Enable Reader - 14 01' -- CommInterface");
ACK();
break;
case "14 00":
//DisplayData(MessageType.Incoming, " VMC: Disable Reader - 14 00\n");
ui.GiveFeedback("'Incoming -- VMC: Disable Reader - 14 00' -- CommInterface");
ACK();
break;
case "11 00":
ui.GiveFeedback("'Incoming -- VMC: Setup Config - 11 00' -- CommInterface");
ConfigurationDataLevel01();
break;
case "11 01":
ui.GiveFeedback("'Incoming -- VMC: Setup Max Min Price - 00' -- CommInterface");
SetupMaxMinPrices();
break;
case "13 00":
//DisplayData(MessageType.Incoming, " VMC: Vend Request - 13 00\n");
ui.GiveFeedback("'Incoming -- VMC: Vend Request - 13 00' -- CommInterface");
if ( ui.Stage == Stages.SessionSelect )
{
ui.NextStage();
ApproveVend();
}
else
DenyVend();
break;
case "13 02":
//DisplayData(MessageType.Incoming, " VMC: Vend Success - 13 02\n");
ui.GiveFeedback("'Incoming -- VMC: VendSuccess - 13 02' -- CommInterface");
ui.NextStage();
ACK();
break;
case "13 05":
//DisplayData(MessageType.Incoming, " VMC: Cash Sale - 13 05\n");
ui.GiveFeedback("'Incoming -- VMC: Cash Sale - 13 05' -- CommInterface");
ACK();
break;
case "13 04":
//DisplayData(MessageType.Incoming, " VMC: Session Complete - 13 04\n");
ui.GiveFeedback("'Incoming -- VMC: Session Complete - 13 04' -- CommInterface");
ACK();
break;
case "17 00":
//DisplayData(MessageType.Incoming, " VMC: Expansion Command - 17 00\n");
ui.GiveFeedback("'Incoming -- VMC: Expansion Command - 17 00' -- CommInterface");
break;
default:
//DisplayData(MessageType.Incoming, "unknown\n");
ui.GiveFeedback("'Incoming -- VMC: Unknown - ?? ??' -- CommInterface");
ACK();
break;
}
ui.GiveFeedback("DataReceived... End");
}
catch(Exception ex)
{
ui.GiveFeedback("Exception Thrown!");
ui.GiveFeedback(ex.Message);
ex = ex.InnerException;
while (ex != null)
{
ui.GiveFeedback(ex.Message);
ex = ex.InnerException;
}
}
}
我不知道发生了什么,也找不到任何可以帮助我的资源。我试过 运行 在没有任何 try/catches 的情况下使用它,看看它是否抛出了一些奇怪的东西,我已经尝试 运行 使用特定的异常捕获来使用它,我已经尝试了所有我想做的事情能想到,知道做。
为什么一直没有 运行ning,我该如何解决?即使你有一个有助于调试这个的想法,我也很乐意听到它!拜托,Whosebug,你是我唯一的希望!
这里有很多可能性...
首先,当数据被放入串行缓冲区时,SerialDataReceivedEvent
被触发。这并不意味着整个消息可用,只是串行端口对象已从底层流中缓冲字节。然后,您将使用 while
循环读取字节,直到获得 -1。
ReadByte
方法说它 returns -1 如果已读取流的结尾。这需要仔细解读,因为流的结尾实际上是 Eof
字符,不一定没有更多数据要接收。
除此之外,您正在捕获异常,我假设您可以判断读取何时超时。如果您设置了一个非常非常大的超时,或者将其保留为默认值 SerialPort.InfiniteTimeout
,那么您将永远不会抛出此异常。
最后,当数据被读入缓冲区时会引发事件,这并不是说事件不能被引发多次。因此,例如,当您收到 10 个字节时,它可能会引发事件,而当您循环遍历数据时,它可能会再次引发它,创建您的处理程序的另一个实例,然后它们会相互争夺数据。
我只会使用事件来通知另一个线程读取数据。如果另一个线程已经在读取它,那么它不会做任何事情。当线程无法工作时,它应该挂起。您还应该检查 SerialPort.BytesToRead
属性 以确定是否有更多数据,请参阅 https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.bytestoread(v=vs.110).aspx 我也不确定为什么您可以逐字节循环致电 SerialPort.ReadExisting
一次通话即可获得所有可用信息...?
我正在使用 SerialPort、用于用户界面的 WPF、用于处理应用程序逻辑的 'ui' 对象以及 SerialPort 的包装器。
当触发 SerialPort.DataReceived 事件时调用相关方法。它开始 运行,然后在读取数据后,似乎就退出了,尽管它还有很多事情要做。
它似乎没有抛出任何异常,它不像卡在循环中一样(同步读取应该超时 + 我会得到大量 "I READ A THING"),而且我我难住了。几乎所有的 GiveFeedback 调用都是我尝试调试正在发生的事情的结果,因为我无法在我正在写这篇文章的机器上进行测试。
'ui' 符号指的是在调用 GiveFeedback(string) 时触发事件的对象,最终通过调用 Dispatcher.BeginInvoke(stuff) 更新文本框的内容。
完整代码如下:
public void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
ui.GiveFeedback("DataReceived... Begin");
List<byte> bytes = new List<byte>();
int r = comm.comPort.ReadByte();
while ( r != -1 )
{
bytes.Add((byte) r);
try
{
r = comm.comPort.ReadByte();
}
catch(Exception ioe)
{
r = -1;
ui.GiveFeedback(ioe.Message);
}
ui.GiveFeedback("read a byte...");
ui.GiveFeedback("read : '" + System.Text.Encoding.ASCII.GetString(bytes.ToArray()) + "'");
}
//It NEVER reaches this line.
//It NEVER throws an exception of any kind.
throw new ApplicationException("I threw myself");
i.GiveFeedback("done read : '" + System.Text.Encoding.ASCII.GetString(bytes.ToArray()) + "'");
string msg = BitConverter.ToString(bytes.ToArray()).Replace("-", " ");
string submsg;
if ( msg.Length > 5 )
submsg = msg.Substring(0, 5);
else
{
submsg = msg.Substring(0, 2);
}
ui.GiveFeedback("msg: " + msg);
ui.GiveFeedback("submsg: " + submsg);
switch ( submsg )
{
case "10":
ui.GiveFeedback("'Incoming -- VMC: Reset - 10' -- CommInterface");
ACK();
break;
case "00":
//DisplayData(MessageType.Incoming, " VMC: ACK - 00\n");
ui.GiveFeedback("'Incoming -- VMC: ACK - 00' -- CommInterface");
break;
case "12":
ui.GiveFeedback("'Incoming -- VMC: Poll - 12' -- CommInterface");
switch ( ui.Stage )
{
case Stages.SessionSelect:
BeginSession();
Poll();
break;
default:
ACK();
break;
}
break;
case "14 01":
//DisplayData(MessageType.Incoming, " VMC: Enable Reader - 14 01\n");
ui.GiveFeedback("'Incoming -- VMC: Enable Reader - 14 01' -- CommInterface");
ACK();
break;
case "14 00":
//DisplayData(MessageType.Incoming, " VMC: Disable Reader - 14 00\n");
ui.GiveFeedback("'Incoming -- VMC: Disable Reader - 14 00' -- CommInterface");
ACK();
break;
case "11 00":
ui.GiveFeedback("'Incoming -- VMC: Setup Config - 11 00' -- CommInterface");
ConfigurationDataLevel01();
break;
case "11 01":
ui.GiveFeedback("'Incoming -- VMC: Setup Max Min Price - 00' -- CommInterface");
SetupMaxMinPrices();
break;
case "13 00":
//DisplayData(MessageType.Incoming, " VMC: Vend Request - 13 00\n");
ui.GiveFeedback("'Incoming -- VMC: Vend Request - 13 00' -- CommInterface");
if ( ui.Stage == Stages.SessionSelect )
{
ui.NextStage();
ApproveVend();
}
else
DenyVend();
break;
case "13 02":
//DisplayData(MessageType.Incoming, " VMC: Vend Success - 13 02\n");
ui.GiveFeedback("'Incoming -- VMC: VendSuccess - 13 02' -- CommInterface");
ui.NextStage();
ACK();
break;
case "13 05":
//DisplayData(MessageType.Incoming, " VMC: Cash Sale - 13 05\n");
ui.GiveFeedback("'Incoming -- VMC: Cash Sale - 13 05' -- CommInterface");
ACK();
break;
case "13 04":
//DisplayData(MessageType.Incoming, " VMC: Session Complete - 13 04\n");
ui.GiveFeedback("'Incoming -- VMC: Session Complete - 13 04' -- CommInterface");
ACK();
break;
case "17 00":
//DisplayData(MessageType.Incoming, " VMC: Expansion Command - 17 00\n");
ui.GiveFeedback("'Incoming -- VMC: Expansion Command - 17 00' -- CommInterface");
break;
default:
//DisplayData(MessageType.Incoming, "unknown\n");
ui.GiveFeedback("'Incoming -- VMC: Unknown - ?? ??' -- CommInterface");
ACK();
break;
}
ui.GiveFeedback("DataReceived... End");
}
catch(Exception ex)
{
ui.GiveFeedback("Exception Thrown!");
ui.GiveFeedback(ex.Message);
ex = ex.InnerException;
while (ex != null)
{
ui.GiveFeedback(ex.Message);
ex = ex.InnerException;
}
}
}
我不知道发生了什么,也找不到任何可以帮助我的资源。我试过 运行 在没有任何 try/catches 的情况下使用它,看看它是否抛出了一些奇怪的东西,我已经尝试 运行 使用特定的异常捕获来使用它,我已经尝试了所有我想做的事情能想到,知道做。
为什么一直没有 运行ning,我该如何解决?即使你有一个有助于调试这个的想法,我也很乐意听到它!拜托,Whosebug,你是我唯一的希望!
这里有很多可能性...
首先,当数据被放入串行缓冲区时,SerialDataReceivedEvent
被触发。这并不意味着整个消息可用,只是串行端口对象已从底层流中缓冲字节。然后,您将使用 while
循环读取字节,直到获得 -1。
ReadByte
方法说它 returns -1 如果已读取流的结尾。这需要仔细解读,因为流的结尾实际上是 Eof
字符,不一定没有更多数据要接收。
除此之外,您正在捕获异常,我假设您可以判断读取何时超时。如果您设置了一个非常非常大的超时,或者将其保留为默认值 SerialPort.InfiniteTimeout
,那么您将永远不会抛出此异常。
最后,当数据被读入缓冲区时会引发事件,这并不是说事件不能被引发多次。因此,例如,当您收到 10 个字节时,它可能会引发事件,而当您循环遍历数据时,它可能会再次引发它,创建您的处理程序的另一个实例,然后它们会相互争夺数据。
我只会使用事件来通知另一个线程读取数据。如果另一个线程已经在读取它,那么它不会做任何事情。当线程无法工作时,它应该挂起。您还应该检查 SerialPort.BytesToRead
属性 以确定是否有更多数据,请参阅 https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.bytestoread(v=vs.110).aspx 我也不确定为什么您可以逐字节循环致电 SerialPort.ReadExisting
一次通话即可获得所有可用信息...?