【问题标题】:Ruby Serialport Timeout exceptionRuby Serialport 超时异常
【发布时间】:2014-06-22 18:40:49
【问题描述】:

我正在使用SerialPort Ruby gem 使用Ruby 脚本“驱动程序”从串行端口写入和读取。

我想从 Windows 和 Linux 操作系统运行应用程序; 顺便说一句,下面的代码已经在 Windows 7 上测试过。

具体来说,我必须在热敏打印机上打印 ESC/POS 文本数据, 通过串行线(COM/USB 端口)连接到主机。

我在打印机上写入数据没有任何问题(极好的廉价 Epson TM-T20)!

但我必须管理错误/连接状态读取设备中的数据,

通过示例查看打印机是否开机(在线),我会使用一些 ESC/POS commnads 向打印机设备询问打印机状态。

出现问题的原因是,即使我设置了串行端口超时(我的意思是设置 SerialPort 类初始化程序的超时参数),但没有异常处理,gem 似乎没有预见到这一点:-(,我无法理解是否打印机处于活动状态或已关闭。查看代码块:

begin
  printer = SerialPort.new PRINTER_SERIALPORT_NAME, BAUDRATE 

  # http://curiosity.roguepenguin.net/?p=35
  # timeouts are in milliseconds
  printer.read_timeout = 2000
  printer.write_timeout = 2000

  puts "Success for SerialPort: #{ printer.inspect }"

rescue => e
  puts "Failed to open as SerialPort: #{ e.inspect }"
end

使用上面的代码,printer.read 实际上会在 2000 毫秒后退出 .. 但我不知道是因为我返回的 (0) 字节数少于预期.. 还是因为设备已关机..

所以,我尝试使用 Ruby Timeout (http://ruby-doc.org/stdlib-2.0.0/libdoc/timeout/rdoc/Timeout.html),从 Winows 7 shell 运行脚本,但不幸的是下面的代码没有按预期运行(如果打印机关闭,printer.read HANG,我的意思是这样做根本不退出:-(,而且我没有预期的Timeout::Error);不是吗?

begin
  Timeout.timeout(2) do
     puts printer.read
  end
rescue Timeout::Error
  puts "SerialPort timeout."
rescue => e
  puts "Serialport ERROR: Failed to open: #{ e.inspect }"
end

有什么办法解决这个问题吗?

谢谢

乔治

【问题讨论】:

  • 您使用的是哪个 Ruby 版本?
  • 我使用 Ruby 2.0 版(在 Windows 上:2.0.0p195)
  • 好吧 - 如果您使用的是旧版 Ruby,在某些情况下超时不可靠,这只是一个长镜头。
  • 是的,我会使用 Ruby 版本 >= 2.0

标签: ruby serial-port timeout usb thermal-printer


【解决方案1】:

根据我收集的文档,当指定 read_timeout 时,读取操作将立即返回(非阻塞),因此不会像您期望的那样导致 Timeout::Error

您可以尝试将超时设置为 0,根据文档,它将阻塞直到一个字节可用,看看 Ruby 是否会引发Timeout::Error

或者尝试完全不设置超时,看看是否有效。

或者,您可以指定一个负超时,该超时会立即返回任何可用数据,并据此做出决定。

【讨论】:

  • 感谢 Rkon!明天我会按照你的正确建议做更多的测试,你会在这里反馈
【解决方案2】:

很抱歉回答我自己的问题,只是为了分享一些测试,也遵循 rkhon 的建议:

前提: 我现在正在 Windows 7 上使用 Ruby 2.0 进行测试,其中 Epson TM-T20 打印机通过 USB 连接(和串行端口 - USB Epson“匹配器”)连接到 PC

关于 SerialPort(读取)超时测试:

如果我设置:
printer.read_timeout <= 0

串口读取挂起(不返回控制)

如果我设置: printer.read_timeout > 0

# read 1 byte 
printer.read(1)

如果读取缓冲区中没有可用字节,则在 read_timeout 毫秒后返回,否则立即返回读取的字节。 没关系!

顺便说一句,serialport gem Timeouts 似乎优先运行(WINs),而不是 Ruby 语言 Timeouts 支持;这意味着如果我设置 printer.read_timeout = 2000 然后我会这样做

 # 1000 msecs
 Timeout.timeout(1) do
     puts printer.read
  end

尽管如此,我在 2000 毫秒后重新获得了控制权......

管理错误/连接状态: 即使我不能使用异常超时,我也可以在没有明确超时异常的情况下检查打印机的开机/连接状态...

我验证了如果我向打印机发送(写入)一个 DLE EOT m(状态请求) 我回来(读)没有数据(零)

希望报告有用...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 2015-01-28
    • 2015-11-29
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多