Невозможно использовать источники отправки GCD для чтения из дескрипторов файлов последовательного порта
У меня возникли проблемы с использованием событий источника Grand Central Dispatch при чтении из последовательных портов.
Я использую dispatch_source_create с DISPATCH_SOURCE_TYPE_READ, чтобы ОС запускала мой блок кода, когда есть данные для чтения из fileDescriptor, который связан с последовательным портом. Вот мой код
- (void) receiveThread
{
    globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
                                                       [self fileDescriptor],
                                                       0,
                                                       globalQueue);
    dispatch_source_set_event_handler(readSource, ^{
        char buffer[512];
        NSString *bar;
        ssize_t numBytes;
        int expected;
        expected = dispatch_source_get_data(readSource);
        printf("expected:%dn",expected);
        do {
            numBytes = read([self fileDescriptor], buffer, 512);
            buffer[numBytes] = 'x000'; //make sure that the string is terminated.
            printf("bytes:%ldn",numBytes);
            if (numBytes != -1)
            {
                bar = [NSString stringWithCString:&buffer];
                //printf("bytes:%ldn",numBytes);
                NSLog(@"String:%@n",bar);
                [[NSNotificationCenter defaultCenter] postNotificationName:EISerialTextDidArrive object:bar];
            }
        } while (numBytes > 0);
    });
    dispatch_resume(readSource);
}
При запуске программы блок вызывается при первой передаче последовательных данных на порт. Затем я получаю сообщение в консоли
[Switching to process 11969 thread 0x6603]
Когда больше символы отправляются на последовательный порт, блок кода не вызывается. Я все еще могу отправлять символы из последовательного порта и могу подтвердить, что символы отправляются, но блок не запускается во второй раз.
Из документации и примеров в Интернете я ожидаю, что блок будет вызываться повторно, пока в последовательном буфере есть символы.
2 ответа:
@KazukiSakamoto правильно указывает, что файловый дескриптор должен иметь
Так или иначе, я написал самое тривиальное маленькое приложение, а затем закоротил контакты 2 и 3 моего последовательного порта, так что все, что было записано, будет эхом возвращаться, а затем подключил кнопку в моем приложении, чтобы отправить некоторые данные. Сработало как заклинание! Вот код:O_NONBLOCK, установленный на нем. Я нашел несколько других проблем, которые, возможно, мешали вам: вы использовали&buffer, Когда вы должны были просто использоватьbuffer. Кроме того, у вас был буфер 512 байт, затем вы читали до 512 байт в него и устанавливали следующий 0 (для завершения null). В случае, если вы действительно прочитали 512 байт, это вызвало бы переполнение буфера. Кроме того, оказывается, чтоreadSource- это Ивар, и вы ссылаетесь наselfв блок. Это, вероятно, создаст цикл удержания, и его следует избегать.@implementation SOAppDelegate { int fd; dispatch_source_t readSrc; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { fd = open("/dev/mySerialPort", O_RDWR | O_NONBLOCK); __block dispatch_source_t blockReadSrc = readSrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue()); dispatch_source_set_event_handler(readSrc, ^{ NSLog(@"expected: %lu\n", dispatch_source_get_data(blockReadSrc)); ssize_t numBytes; do { char buffer[513]; numBytes = read((int)dispatch_source_get_handle(blockReadSrc), buffer, 512); buffer[numBytes] = '\x000'; //make sure that the string is terminated. NSLog(@"numBytes: %ld\n",numBytes); if (numBytes != -1) { NSLog(@"String:%@\n", [NSString stringWithUTF8String: buffer]); } } while (numBytes > 0); }); dispatch_resume(readSrc); } - (IBAction)sendData: (id)sender { write(fd, "foobar", 6); } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { if (fd > 0) close(fd); fd = 0; if (readSrc) dispatch_release(readSrc); readSrc = nil; return NSTerminateNow; } @end