蓝牙 SPP 错误 - 与其他广播接收器竞争?

发布于 2024-11-01 10:46:30 字数 3149 浏览 0 评论 0原文

我遇到一个有趣的情况,我通过蓝牙 SPP 与第三方设备进行通信,并且间歇性出现问题。

设备背景: 该设备是一个条形码扫描仪,充当蓝牙服务器,使用 SPP over RFCOMM。它始终启动连接,并拒绝传入连接。连接后,它将上传数据,然后等待 ACK。如果收到 ACK,则不会重试相同的传输。如果在(相对较短的)超时时间内没有收到ACK,则将不断重试传输。设备知道数据发送到哪里,因为它扫描包含将接收传输的设备的 BDA 的条形码。扫描仪永远不会被发现,也不会扫描设备。

当进行传输并且没有运行应用程序时,平板电脑上的 Android 系统会显示 toast:“远程设备正在尝试访问您的手机。请检查通知面板。”

我需要什么以及到目前为止有效的: 本质上,我需要接受来自扫描仪的传入数据,然后回复确认。由于它是针对特定设备的特定应用程序,因此自动配对是我的愿望清单。 (设备始终使用“0000”作为其 PIN)。

我有一台 Samsung Galaxy 平板电脑用于开发,不过我也使用 Nexus One (HTC Passion) 和 Samsung Galaxy Vibrant 手机进行了测试。

我从蓝牙聊天示例开始,并在旅途中浏览了许多 Stackoverflow 问题。随着时间的推移,发生了以下情况:

1:我从使用标准 SPP UUID 的基本“createRfcomm...()”开始,然后接着使用“connect()”。尽管存在一些时序问题,但我能够半可靠地创建连接、获取读写流、接收数据并发送确认。

问题是它不可靠,我必须把它放在一个相当紧密的循环中才能得到任何东西。

2:我发现了ACL_CONNECT的BroadcastReceiver。我在 OnResume() 期间注册了它,事情发生了很大的变化。此外,我注册了“PAIRING_REQUEST”来处理我的自动配对,尽管 2.0+ API 不直接支持它。

最值得注意的是,我现在检测传入的连接尝试,然后启动 connect()。然而有趣的是,这似乎有点太晚了——我怀疑这确实是我的主要问题出现的地方。

因此,连接尝试进入,如果未配对,则识别 PAIRING_REQUEST 操作。通过使用“createBond”、“setPin”和“setPairingConfirmation”函数,所有这些都通过反射,我的设备现在已自动配对。它可以在两部手机上无缝运行。然而,在平板电脑上,PIN 输入对话框时不时会弹出一瞬间,然后消失。无论如何,自动配对始终有效。

值得注意的是,即使我的应用程序正在运行,系统通知“远程设备正在尝试访问您的手机...”也会出现。

配对完成后,无论是上一次传输还是当前传输,都会转移到 connect()。第一个问题是:

超过 99% 的时间,第一次 connect() 尝试会超时(大约 12 秒)。失败后,我立即尝试再次连接(),并且大多数时候它都有效。有时需要多试几次,有时会不成功,但一般情况下重试几次就可以了。

有趣的是,无论成功与否,Android都会用toast进行响应:“无法与蓝牙设备配对”。这对我来说真的毫无意义,因为设备已配对,唯一失败的是系统(默认的 BroadcastReceiver?)没有建立连接。

此时我的问题变成了 - 为什么第一个 connect() 总是失败?这与通知和最终失败有关系吗?我可以覆盖这个吗?或者,我还缺少其他什么东西吗?

我尝试的下一件事是设置优先级并中止广播,但我意识到蓝牙广播没有被排序。没有骰子。

我真正想知道的是:

A:我可以指示 Android 忽略此传入连接尝试,并让我的应用程序处理它吗?

B:或者,我可以强制系统中止它正在做的任何事情(也许阻塞通道?)然后让我尝试我自己的 connect() 吗?至少,它不应该只是继续工作,直到它向我提示“无法配对蓝牙设备”(对于已配对的设备)。

C:有没有一种方法可以“打开 COM 端口”,然后在连接发生时对其进行处理?简而言之 - 我可以获得一个带有原始流的开放端口吗?

D:还有其他人认为我遗漏的东西吗?

附加信息:

Nexus 上的问题为零。它每次都一致地工作,没有任何延迟。它正在运行2.3.3。这与此形成鲜明对比:

Nexus One 中的 Android 2.3.3 中的 SPP 蓝牙连接有问题吗?

Samsung Vibrant 是最糟糕的 - 大多数连接失败。它正在运行2.2。该平板电脑也运行 2.2,正如我所说,大多数连接在几次退出后仍能正常工作。

任何关于我如何解决我认为的广播竞争问题的建议将非常感激。为了完整起见,通过 connect() 代码如下:

    try
{
    // Make sure that there is no discovery going on
    btAdapter.cancelDiscovery();

    // Attempt to create the socket
    btSocket = currentBtDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
    btDebugStage = DEBUG_STAGE_HAS_SOCKET;
}
catch (IOException e)
{
    e.printStackTrace();
    return;
}

try
{
    // Attempt to connect to the Bluetooth device
    btDebugStage = DEBUG_STAGE_ATTEMPT_CONNECT;
    btSocket.connect();

    btDebugStage = DEBUG_STAGE_CONNECTED;
    btConnected = true;
}
catch (IOException e)
{
    try
    {
        btSocket.close();
    }
    catch (IOException e2)
    {
        Log.e(TAG, "Unable to close() socket after connection failure", e2);
    }

    // If it doesn't connect then make a note of it
    btConnected = false;
}

I have an interesting situation where I am communicating, via Bluetooth SPP, with a third party device and intermittent problems arise.

Background on the device:
The device is a barcode scanner acts as a Bluetooth server, using SPP over RFCOMM. It always initiates the connection, and will refuse incoming connections. Upon connection, it will upload data and then wait for an ACK. If the ACK is received, then the same transmission will not be retried. If no ACK is received in the (relatively short) timeout period, then the transmission will be continually retried. The device knows where the data is being sent because it scans a barcode that contains the BDA of the device that will be receiving the transmission. The scanner is never discoverable and never scans for devices.

When a transmission is made and there is no application running, Android on the tablet displays the toast: "Remote device is trying to access your phone. Check in the notifications panel."

What I need and what works up to this point:
Essentially, I need to accept incoming data from the scanner and then reply with an acknowledgment. Since it is a specific app for a specific device, automatic pairing was on my wishlist. (The device always uses "0000" as its PIN).

I have a Samsung Galaxy Tablet for development, although I have also tested with a Nexus One (HTC Passion) and a Samsung Galaxy Vibrant phone.

I started with the Bluetooth chat sample, and have browsed many Stackoverflow questions in my travels. Over time, this is what happened:

1: I started with a basic "createRfcomm...()" using the standard SPP UUID, and then followed up with a "connect()". Although there were some timing issues, I was able to semi-reliably create a connection, obtain read and write streams, receive the data and send the acknowledgement.

The problem was that it was unreliable, and I had to put it in a rather tight loop just to get anything.

2: I discovered the BroadcastReceiver for ACL_CONNECT. I register it during my OnResume(), and things changed considerably. In addition, I registered the the "PAIRING_REQUEST" to handle my automatic pairing, even though it isn't supported directly by the 2.0+ API.

Most notably, I now detect incoming connection attempts and then start the connect(). Interestingly, however, it seems that this may be a little too late - which is really, I suspect, where my main problem arises.

So - the connection attempt comes in and if it is not paired, the PAIRING_REQUEST action is recognized. By using the "createBond", "setPin", and "setPairingConfirmation" functions, all through reflexion, my device is now automatically paired. It works seamlessly on the two mobile phones. However, on the tablet, every now and again the PIN entry dialog will pop up for a split second before it disappears. In any event, the automatic pairing always works.

It is important to note that even while my app is running, the system notification "Remote device is trying to access your phone..." comes up.

After the pairing is complete, whether during a previous transmission or the current one, it moves to the connect(). The first problem is this:

More than 99% of the time, the first connect() attempt times out (approximately 12 seconds). Immediately upon failure, I attempt to connect() again, and most of the time it works. Sometimes, it takes a few more tries, and sometimes it is unsuccessful, but normally it works after a few retries.

Interestingly, whether it succeeds or not, Android will respond with the toast: "Unable to pair with Bluetooth device". This really makes no sense to me because the device is paired, and the only thing that is failing is the system (default BroadcastReceiver?) is not making a connection.

At this point my question became - Why does the first connect() always fail? Does it have to do with the notification and the eventual failure? Can I override this? Or, is it something else that I am missing?

The next thing that I tried was setting the priority and aborting the broadcast, but I realized that the Bluetooth broadcast was not ordered. No dice.

What I would really like to know is:

A: Can I instruct Android to ignore this incoming connection attempt, and let my app handle it?

B: Alternatively, can I force the system to abort whatever it is doing (perhaps blocking the channel?) and then let me try my own connect()? At the very minimum, it shouldn't just continuing working until it toasts me with "Unable to pair Bluetooth device" for a device that is already paired.

C: Is there a way just to "Open a COM port" and then deal with connections as they happen? Simply put - can I just get an open port with a raw stream?

D: Is there anything else that anybody thinks that I'm missing?

Additional info:

There are zero problems on the Nexus. It works consistently, every time, with no delay whatsoever. It is running 2.3.3. This is very much in contrast to this:

Problem in Bluetooth connection over SPP in Android 2.3.3 in Nexus One?

The Samsung Vibrant is the worst - most connections fail. It is running 2.2. The tablet is also running 2.2, and as I stated, the majority of connections work after a couple of retires.

Any suggestions on how I might tackle what I think is competition for the broadcast would be very much appreciated. For the sake of completeness, by connect() code follows:

    try
{
    // Make sure that there is no discovery going on
    btAdapter.cancelDiscovery();

    // Attempt to create the socket
    btSocket = currentBtDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
    btDebugStage = DEBUG_STAGE_HAS_SOCKET;
}
catch (IOException e)
{
    e.printStackTrace();
    return;
}

try
{
    // Attempt to connect to the Bluetooth device
    btDebugStage = DEBUG_STAGE_ATTEMPT_CONNECT;
    btSocket.connect();

    btDebugStage = DEBUG_STAGE_CONNECTED;
    btConnected = true;
}
catch (IOException e)
{
    try
    {
        btSocket.close();
    }
    catch (IOException e2)
    {
        Log.e(TAG, "Unable to close() socket after connection failure", e2);
    }

    // If it doesn't connect then make a note of it
    btConnected = false;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

雨的味道风的声音 2024-11-08 10:46:30

Android 的蓝牙可能仍然存在一些故障,但是,在这种情况下,您写了有关远程 BT 设备的信息:

它总是发起连接,并拒绝传入连接。

在您的代码片段中,您尝试了不应该起作用的方法:启动从 Android 设备到远程设备的连接。

我现在检测传入的连接尝试,然后启动 connect()

这几乎肯定是完全错误的方法 - 实际上,它根本不应该工作。如果它在某些设备上间歇性地出现,那么这更像是这些设备中的错误,而不是未记录的功能。

因此,在 Android 上处理传入蓝牙连接时,请使用以下描述的监听服务器方法:

http://developer.android.com/guide/topics/wireless/bluetooth.html#ConnectingAsAServer

使用 listenUsingRfcommWithServiceRecord()< /a>.

至于 Android 设备上的配对: 每个远程设备只需配对一次。设备配对后,Android 会存储配对信息,并允许将来连接,而不会再次提示输入 PIN 码进行配对。

Android's Bluetooth may still have some glitches, however, in this case you wrote about the remote BT-Device:

It always initiates the connection, and will refuse incoming connections.

In your code snippet, you try just what should not work: Initiate a connection from the Android device to the remote device.

I now detect incoming connection attempts and then start the connect()

This is almost certainly the completely wrong approach - and, actually, it should not work at all. If it does intermittently on some devices this is more of a bug in those devices than an undocumented feature.

So, when dealing with incoming Bluetooth connections on Android, use the listening server approach described e.g. in:

http://developer.android.com/guide/topics/wireless/bluetooth.html#ConnectingAsAServer

using listenUsingRfcommWithServiceRecord().

As for the pairing on Android devices: Pairing should be necessary only once for each remote device. Once the device is paired, Android stores the pairing information and will allow future connections without prompting for a PIN for pairing again.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文