以下是我正在尝试做的一些背景知识:
- 打开从移动设备到蓝牙打印机的串行端口。
- 将EPL / 2表格发送到蓝牙打印机,以便它了解如何处理它将要接收的数据。
- 收到表格后,将一些数据发送到打印机,打印机将打印在标签纸上。
- 根据需要对每个要打印的标签重复步骤3。
第2步仅在第一次发生,因为表单不需要在每个标签之前。我的问题是,当我发送表单时,如果我发送标签数据太快,它将无法打印。有时我会在标签上打印“Bluetooth Failure:Radio Non-Operational”而不是我发送的数据。
通过执行以下操作,我找到了解决问题的方法:
for (int attempt = 0; attempt < 3; attempt++)
{
try
{
serialPort.Write(labelData);
break;
}
catch (TimeoutException ex)
{
// Log info or display info based on ex.Message
Thread.Sleep(3000);
}
}
所以基本上,我可以捕获一个TimeoutException并在等待一定时间后重试write方法(三秒似乎一直在工作,但是更少,似乎每次尝试都抛出异常)。经过三次尝试,我只是假设串口有问题,让用户知道。
这种方式似乎工作正常,但我确信有更好的方法来处理这个问题。我认为我需要使用SerialPort类中的一些属性,但我找不到任何好的文档或如何使用它们的示例。我试过玩一些属性,但它们似乎都没有做我想要达到的目标。
这是我玩过的属性列表:
- CDHolding
- CtsHolding
- DsrHolding
- DtrEnable
- 握手
- RtsEnable
我相信这些的一些组合将处理我想要更优雅地做的事情。
我正在使用C#(2.0框架),Zebra QL 220+蓝牙打印机和Windows Mobile 6手持设备,如果这对解决方案有任何影响。
任何建议,将不胜感激。
[UPDATE]
我还应该注意到移动设备使用的是蓝牙2.0,而打印机仅使用1.1版本。我假设速度差异是导致打印机在接收数据方面落后的原因。
流量控制是正确的答案,它可能不会出现/实施/适用于您的蓝牙连接。
查看Zebra规范并查看它们是否实现,或者是否可以打开软件流控制(xon,xoff),这将允许您查看各种缓冲区何时变满。
此外,蓝牙无线电不可能最大传输速度超过250k。您可以考虑人为地将其限制为9,600bps - 这将使无线电为重传,纠错,检测和自身的流量控制留出很大的喘息空间。
如果所有其他方法都失败了,你现在正在使用的黑客也不错,但我会在放弃之前给Zebra技术支持打电话并找出他们推荐的内容。
-亚当
我已经根据已经给出的两个建议找到了一种方法。我需要使用以下内容设置我的串口对象:
serialPort.Handshake = Handshake.RequestToSendXOnXOff;
serialPort.WriteTimeout = 10000; // Could use a lower value here.
然后我只需要进行写调用:
serialPort.Write(labelData);
由于Zebra打印机支持软件流控制,因此当缓冲区接近满时,它将向移动设备发送XOff值。这使得移动设备等待从打印机发送XOn值,有效地通知移动设备它可以继续发送。
通过设置写入超时属性,我将在抛出写入超时异常之前给出传输所允许的总时间。您仍然希望捕获写入超时,就像我在问题中的示例代码中所做的那样。但是,由于软件流控制将启动和停止串行端口写入传输,因此没有必要循环3次(或任意数量)次,尝试每次写入。
问题可能不在于串口代码,而在于底层蓝牙堆栈。您正在使用的端口纯粹是虚拟的,并且任何握手都不可能实现(因为它几乎没有意义)。 CTS / RTS DTR / DSR根本不适用于您正在处理的内容。
根本问题是,当您创建虚拟端口时,它必须绑定到蓝牙堆栈并连接到配对的串行设备。端口本身不知道可能需要多长时间,并且可能设置为异步执行此操作(尽管这完全取决于设备OEM如何完成)以防止调用者长时间锁定(如果没有)配对设备或配对设备超出范围。
虽然你的代码可能感觉像是一个黑客,但它可能是你做你正在做的最好,最便携的方式。
您可以使用蓝牙堆栈API在连接之前尝试查看设备是否存在并处于活动状态,但是没有堆栈API的标准化,因此Widcom和Microsoft API在如何实现这一点方面存在差异,Widcom是专有的,昂贵。你最终得到的是试图发现堆栈类型,动态加载适当的验证器类,让它调用堆栈并查找设备。鉴于此,您的简单轮询似乎更清晰,您不必为Widcom SDK支付几美元。