为什么 /dev/rfcomm0 会给 PySerial 带来问题?

为什么 /dev/rfcomm0 会给 PySerial 带来问题?

我正在通过蓝牙将我的 Ubuntu 盒子连接到无线读出设置。我编写了一个 Python 脚本,通过 /dev/rfcomm0 发送串行信息。该脚本连接良好并工作了几分钟,但随后 Python 将开始使用 100% 的 CPU,并且消息停止流动。

我可以在串行终端中打开 rfcomm0 并通过它手动进行通信。当我通过终端打开它时,它似乎可以无限期地工作。此外,我可以将蓝牙接收器换成 USB 电缆,并将端口更改为 /dev/ttyUSB0,而且随着时间的推移我不会遇到任何问题。

看来要么是我对 rfcomm0 的操作有误,要么是 PySerial 不能很好地处理它。

脚本如下:

import psutil
import serial
import string
import time

sampleTime = 1
numSamples = 5
lastTemp = 0

TEMP_CHAR = 't'
USAGE_CHAR = 'u'
SENSOR_NAME = 'TC0D'

gauges = serial.Serial()
gauges.port = '/dev/rfcomm0'
gauges.baudrate = 9600
gauges.parity = 'N'
gauges.writeTimeout = 0
gauges.open()

print("Connected to " + gauges.portstr)

filename = '/sys/bus/platform/devices/applesmc.768/temp2_input'

def parseSensorsOutputLinux(output):
    return int(round(float(output) / 1000))

while(1):
    usage = psutil.cpu_percent(interval=sampleTime)
    gauges.write(USAGE_CHAR)
    gauges.write(chr(int(usage))) #write the first byte
    #print("Wrote usage: " + str(int(usage)))

    sensorFile = open(filename)
    temp = parseSensorsOutputLinux(sensorFile.read())
    gauges.write(TEMP_CHAR)
    gauges.write(chr(temp))
    #print("Wrote temp: " + str(temp))

有什么想法吗?

谢谢。

编辑:这是修改后的代码,使用 Python-BlueZ 而不是 PySerial:

import psutil
import serial
import string
import time
import bluetooth

sampleTime = 1
numSamples = 5
lastTemp = 0

TEMP_CHAR = 't'
USAGE_CHAR = 'u'
SENSOR_NAME = 'TC0D'

#gauges = serial.Serial()
#gauges.port = '/dev/rfcomm0'
#gauges.baudrate = 9600
#gauges.parity = 'N'
#gauges.writeTimeout = 0
#gauges.open()

gaugeSocket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
gaugeSocket.connect(('00:06:66:42:22:96', 1))

filename = '/sys/bus/platform/devices/applesmc.768/temp2_input'

def parseSensorsOutputLinux(output):
    return int(round(float(output) / 1000))

while(1):
    usage = psutil.cpu_percent(interval=sampleTime)
    #gauges.write(USAGE_CHAR)
    gaugeSocket.send(USAGE_CHAR)
    #gauges.write(chr(int(usage))) #write the first byte
    gaugeSocket.send(chr(int(usage)))
    #print("Wrote usage: " + str(int(usage)))

    sensorFile = open(filename)
    temp = parseSensorsOutputLinux(sensorFile.read())
    #gauges.write(TEMP_CHAR)
    gaugeSocket.send(TEMP_CHAR)
    #gauges.write(chr(temp))
    gaugeSocket.send(chr(temp))
    #print("Wrote temp: " + str(temp))

看来要么是 Ubuntu 在一段时间后关闭了 /dev/rfcomm0,要么是我的蓝牙接收器出了问题。即使出现 BluetoothError,接收器上的“已连接”指示灯仍亮着,直到我关闭接收器电源后才能重新连接。

我不知道该如何解决这个问题。奇怪的是,连接可以正常工作几分钟(似乎是随机的时间),然后就卡住了。

如果有帮助的话,蓝牙接收器是一个BlueSmirf 银色来自 Sparkfun。我是否需要尝试从接收器端维持连接或采取其他措施?

答案1

事实证明,PC 上的蓝牙缓冲区溢出了,因为我从未在 Python 脚本中调用 recv()。

蓝牙配件正在向 PC 发送字符,但脚本忽略了这些字符,这不可避免地导致了缓冲区溢出。这种溢出显然会导致 rfcomm 通道锁定,直到读取缓冲区为止。

以下是工作脚本,供将来参考:

import psutil
import serial
import string
import time
import bluetooth

sampleTime = 1
numSamples = 5
lastTemp = 0

TEMP_CHAR = 't'
USAGE_CHAR = 'u'
SENSOR_NAME = 'TC0D'

filename = '/sys/bus/platform/devices/applesmc.768/temp2_input'


def parseSensorsOutputLinux(output):
    return int(round(float(output) / 1000))

def connect():
    while(True):    
        try:
            gaugeSocket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
            gaugeSocket.connect(('00:06:66:42:22:96', 1))
            break;
        except bluetooth.btcommon.BluetoothError as error:
            gaugeSocket.close()
            print "Could not connect: ", error, "; Retrying in 10s..."
            time.sleep(10)
    return gaugeSocket;

gaugeSocket = connect()
while(True):
    usage = psutil.cpu_percent(interval=sampleTime)
    sensorFile = open(filename)
    temp = parseSensorsOutputLinux(sensorFile.read())
    try:
        gaugeSocket.send(USAGE_CHAR)
        gaugeSocket.send(chr(int(usage)))
        #print("Wrote usage: " + str(int(usage)))

        gaugeSocket.send(TEMP_CHAR)
        gaugeSocket.send(chr(temp))
        print gaugeSocket.recv(1024)
        #print("Wrote temp: " + str(temp))
    except bluetooth.btcommon.BluetoothError as error:
        print "Caught BluetoothError: ", error
        time.sleep(5)
        gaugeSocket = connect()
        pass

gaugeSocket.close()

关键的变化是增加了

gaugeSocket.recv(1024)

它将清除从远程设备发回的“okay”消息的缓冲区。

相关内容