OSX bluetooth openRFCOMMChannelAsyn c утверждает, что подключился, но соединение не установлено и делегат никогда не вызывается - PullRequest
0 голосов
/ 13 февраля 2020

Я написал оболочку C ++ для bluetooth-фреймворка obj c для OSX. Оболочка работает так далеко, что может: а) получить список всех сопряженных устройств, б) получить одно устройство, c) напечатать его имя, г) открыть канал. Это все работает без каких-либо сообщений об ошибках. Однако мое устройство Bluetooth (коробка RFComm) никогда не сообщает о соединении. Он остается в автономном режиме. Делегат, который я зарегистрировал в openRFCOMMChannelAsyn c, никогда не вызывается.

Поскольку это оболочка 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 - это метод «Discover», который устанавливает соединение. Здесь я подозреваю, что что-то не так:

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;
}

Я только регистрирую полученные данные от устройства Bluetooth с помощью метода «log» на экране с помощью fprintf.

Основная программа просто:

IosBT ad;
ad.discover();
getchar();
ad.closeConnection();

Вывод:

Attempting to connect

1 devices
dev=GN-ATTYS1-FB86
Successfully connected

Однако метод "Channeldata" никогда не вызывается, но должен печатать данные, полученные от устройства Bluetooth. Блютуз бокс сообщает, что он не подключен. Однако правый значок Bluetooth на верхней панели показывает, что Ma c подключен к GN-ATTYS1-FB86. Тем не менее, это не так.

Демонстрация, использующая окно для печати на экране, прекрасно работает с моей коробкой Bluetooth: https://github.com/berndporr/coco-bluetooth-rfcomm. Для меня единственное очевидное отличие состоит в том, что я использую командную строку.

Вопрос: почему OSX сообщает о работающем соединении, но не устанавливает его? Как я могу отладить это без сообщения об ошибке?

1 Ответ

0 голосов
/ 14 февраля 2020

Чтобы использовать Bluetooth из командной строки, объект NSRunLoop должен вызываться в потоке несколько раз. Поскольку это оболочка C ++, я создал поток как поток C ++, а затем вызвал его в al oop:

while (running) {
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}

Флаг running - это обычный флаг в потоке, который установлен в ноль чтобы остановить поток.

Весь пример кодирования приведен здесь: C ++ bluetooth wrapper , который открывает канал RFCOMM и затем печатает полученные данные в стандартный вывод до тех пор, пока пользователь не нажмет return.

Ответ здесь, как создать событие run l oop, помог мне разобраться в проблеме.

...