问题 如何强制串口写入方法在发送数据之前等待线路清除?


以下是我正在尝试做的一些背景知识:

  1. 打开从移动设备到蓝牙打印机的串行端口。
  2. 将EPL / 2表格发送到蓝牙打印机,以便它了解如何处理它将要接收的数据。
  3. 收到表格后,将一些数据发送到打印机,打印机将打印在标签纸上。
  4. 根据需要对每个要打印的标签重复步骤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版本。我假设速度差异是导致打印机在接收数据方面落后的原因。


3259
2017-10-21 16:10


起源

杰森,你和Zebra有什么联系,他们说了什么?我很想知道这个故事是怎么发现的...... - Adam Davis
这是一段时间了...我只记得他们推荐软件流控制,我们已经确定这是最好的方法。我不记得他们提到限制传输速度或沿着那些线路的任何东西。 - Jason Down


答案:


流量控制是正确的答案,它可能不会出现/实施/适用于您的蓝牙连接。

查看Zebra规范并查看它们是否实现,或者是否可以打开软件流控制(xon,xoff),这将允许您查看各种缓冲区何时变满。

此外,蓝牙无线电不可能最大传输速度超过250k。您可以考虑人为地将其限制为9,600bps - 这将使无线电为重传,纠错,检测和自身的流量控制留出很大的喘息空间。

如果所有其他方法都失败了,你现在正在使用的黑客也不错,但我会在放弃之前给Zebra技术支持打电话并找出他们推荐的内容。

-亚当


5
2017-10-21 16:33



谢谢亚当。我会看看Zebra说的是什么。 - Jason Down


我已经根据已经给出的两个建议找到了一种方法。我需要使用以下内容设置我的串口对象:

serialPort.Handshake = Handshake.RequestToSendXOnXOff;
serialPort.WriteTimeout = 10000; // Could use a lower value here.

然后我只需要进行写调用:

serialPort.Write(labelData);

由于Zebra打印机支持软件流控制,因此当缓冲区接近满时,它将向移动设备发送XOff值。这使得移动设备等待从打印机发送XOn值,有效地通知移动设备它可以继续发送。

通过设置写入超时属性,我将在抛出写入超时异常之前给出传输所允许的总时间。您仍然希望捕获写入超时,就像我在问题中的示例代码中所做的那样。但是,由于软件流控制将启动和停止串行端口写入传输,因此没有必要循环3次(或任意数量)次,尝试每次写入。


7
2017-10-31 15:57





问题可能不在于串口代码,而在于底层蓝牙堆栈。您正在使用的端口纯粹是虚拟的,并且任何握手都不可能实现(因为它几乎没有意义)。 CTS / RTS DTR / DSR根本不适用于您正在处理的内容。

根本问题是,当您创建虚拟端口时,它必须绑定到蓝牙堆栈并连接到配对的串行设备。端口本身不知道可能需要多长时间,并且可能设置为异步执行此操作(尽管这完全取决于设备OEM如何完成)以防止调用者长时间锁定(如果没有)配对设备或配对设备超出范围。

虽然你的代码可能感觉像是一个黑客,但它可能是你做你正在做的最好,最便携的方式。

您可以使用蓝牙堆栈API在连接之前尝试查看设备是否存在并处于活动状态,但是没有堆栈API的标准化,因此Widcom和Microsoft API在如何实现这一点方面存在差异,Widcom是专有的,昂贵。你最终得到的是试图发现堆栈类型,动态加载适当的验证器类,让它调用堆栈并查找设备。鉴于此,您的简单轮询似乎更清晰,您不必为Widcom SDK支付几美元。


2
2017-10-21 16:21



好答案。我将它归档于“何时黑客实际上不是黑客”。 - endian
这可以解释为什么使用任何clear-to-send,request-to-send选项似乎没有效果。 - Jason Down
移动开发有一段时间,你会倾向于收集几个“什么时候是黑客实际上不是一个黑客”位。事实上,你可能会创建一个小型库。这是使桌面开发和设备开发完全相同的信念之一 - ctacke
ctacke - 我注意到有很多问题试图将代码从桌面应用程序移植到移动应用程序。似乎Compact Framework永远不会有一个对象需要的方法或属性,而它在常规.NET框架中可用。 GRRRR。 - Jason Down