c++ - OSX蓝牙openRFCOMMChannelAsync声称已连接但未建立连接并且从未调用委托
问题描述
我为 OSX 的 objc 蓝牙框架编写了一个 C++ 包装器。包装器工作至今,它可以 a) 获取所有配对设备的列表,b) 获取一个设备,c) 打印其名称,d) 打开通道。这一切都有效,没有任何报告的错误。但是,我的蓝牙设备(一个 RFComm 盒子)从不报告连接。它保持离线状态。我在 openRFCOMMChannelAsync 注册的委托永远不会被调用。
由于它是 C++ 包装器,因此标头是标准 C++ 类:
class IosBT {
public:
//IosBT();
void clearText();
void sendMessage(char* dataToSend, int len);
void log(const char *text);
void discover();
void closeConnection();
private:
void *mRFCOMMChannel;
};
该类的实现被编写为一个 .mm 文件。我分两块解释。首先是保留指向 C++ 类的指针的委托:
@interface AsyncCommDelegate : NSObject <IOBluetoothRFCOMMChannelDelegate> {
@public
IosBT* delegateCPP;
}
@end
@implementation AsyncCommDelegate {
}
-(void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel *)rfcommChannel status:(IOReturn)error
{
if ( error != kIOReturnSuccess ) {
delegateCPP->log("Error - failed to open the RFCOMM channel with error %08lx.\n");
return;
}
else{
delegateCPP->log("Connected. Yeah!\n");
}
}
-(void)rfcommChannelData:(IOBluetoothRFCOMMChannel *)rfcommChannel data:(void *)dataPointer length:(size_t)dataLength
{
NSString *message = [[NSString alloc] initWithBytes:dataPointer length:dataLength encoding:NSUTF8StringEncoding];
delegateCPP->log([message UTF8String]);
}
@end
.mm 文件的第二个块是建立连接的“发现”方法。在这里,我怀疑有些不对劲:
void IosBT::discover()
{
IOBluetoothSDPUUID *sppServiceUUID;
NSArray *deviceArray;
IOBluetoothRFCOMMChannel *chan;
log("Attempting to connect\n");
sppServiceUUID = [IOBluetoothSDPUUID uuid16:kBluetoothSDPUUID16ServiceClassSerialPort];
deviceArray = [IOBluetoothDevice pairedDevices];
if ( ( deviceArray == nil ) || ( [deviceArray count] == 0 ) ) {
log("Error - no selected device. ***This should never happen.***\n");
return;
}
fprintf(stderr,"%lu devices\n",(unsigned long)deviceArray.count);
IOBluetoothDevice *device = [deviceArray objectAtIndex:0];
fprintf(stderr,"dev=%s\n",[device.name UTF8String]);
IOBluetoothSDPServiceRecord *sppServiceRecord = [device getServiceRecordForUUID:sppServiceUUID];
if ( sppServiceRecord == nil ) {
log("Error - no spp service in selected device. ***This should never happen since the selector forces the user to select only devices with spp.**\
*\n");
return;
}
// To connect we need a device to connect and an RFCOMM channel ID to open on the device:
UInt8 rfcommChannelID;
if ( [sppServiceRecord getRFCOMMChannelID:&rfcommChannelID] != kIOReturnSuccess ) {
log("Error - no SPP device.\n");
return;
}
AsyncCommDelegate* asyncCommDelegate = [[AsyncCommDelegate alloc] init];
asyncCommDelegate->delegateCPP = this;
if ( [device openRFCOMMChannelAsync:&chan withChannelID:rfcommChannelID delegate:asyncCommDelegate] != kIOReturnSuccess ) {
log("Error - open sequence failed.\n");
return;
}
if ( chan == NULL ) {
log("Error - chan == NULL");
return;
}
[chan setDelegate:asyncCommDelegate];
log("Successfully connected");
mRFCOMMChannel = (__bridge void*)chan;
}
我只使用 fprintf 在屏幕上使用“log”方法记录从蓝牙设备接收到的数据。
主程序很简单:
IosBT ad;
ad.discover();
getchar();
ad.closeConnection();
输出是:
Attempting to connect
1 devices
dev=GN-ATTYS1-FB86
Successfully connected
然而,“Channeldata”方法永远不会被调用,而是应该打印从蓝牙设备接收到的数据。蓝牙盒子报告它没有连接。但是,顶部栏右侧的蓝牙图标显示 Mac 已连接到 GN-ATTYS1-FB86。然而,事实并非如此。
此处使用窗口在屏幕上打印的演示适用于我的蓝牙盒:https ://github.com/berndporr/coco-bluetooth-rfcomm 。对我来说,唯一明显的区别是我使用命令行。
问题是:为什么 OSX 报告一个工作连接但实际上没有建立一个?我怎样才能在不报告任何错误的情况下调试它?
解决方案
为了从命令行使用蓝牙,NSRunLoop
需要在线程中重复调用一个对象。由于它是 C++ 包装器,因此我将线程创建为 C++ 线程,然后在循环中调用:
while (running) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
该running
标志是线程中的常用标志,设置为零以停止线程。
整个编码示例在这里:C++ 蓝牙包装器,它打开 RFCOMM 通道,然后将接收到的数据打印到标准输出,直到用户按下返回。
此处的答案如何创建运行事件循环帮助我找到了问题的根源。
推荐阅读
- paypal - Paypal 直接付款 API 参数
- asp.net - Server.Execute() 调用asp文件后再次执行点击处理程序
- javascript - 减少数组js中的条件
- css - 如何从任何页面 CSS Ionic 4 更改菜单背景
- flutter - 如何在颤动的列表中选择一个复选框
- java - 对象相等/哈希码与 JPA/Hibernate 实体相等/哈希码
- azure - 我应该在 Azure AD B2C 中同时注册前端应用和 api 应用吗?
- java - 序列化作为 Object 传递的可序列化对象
- azure - Calico GlobalNetworkPolicy 排除不起作用
- google-apps-script - 复制数据脚本不再起作用