Невозможно использовать источники диспетчеризации GCD для чтения из файловых дескрипторов последовательного порта. - PullRequest
4 голосов
/ 14 марта 2011

У меня проблемы с использованием событий Grand Central Dispatch Source при чтении с последовательных портов.

Я использую 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:%d\n",expected);

        do {
            numBytes = read([self fileDescriptor], buffer, 512);
            buffer[numBytes] = '\x000'; //make sure that the string is terminated.
            printf("bytes:%ld\n",numBytes);
            if (numBytes != -1)
            {
                bar = [NSString stringWithCString:&buffer];
                //printf("bytes:%ld\n",numBytes);
                NSLog(@"String:%@\n",bar);
                [[NSNotificationCenter defaultCenter] postNotificationName:EISerialTextDidArrive object:bar];
            }
        } while (numBytes > 0);

    });
    dispatch_resume(readSource);
}

Когда программа запускается, блок вызывается в первый раз, когда последовательные данные отправляются в порт.Затем я получаю сообщение в консоли

[Switching to process 11969 thread 0x6603]

Когда в последовательный порт отправляется больше символов, блок кода не вызывается.Я все еще могу отправлять символы из последовательного порта, и я могу подтвердить, что символы отправляются, но блок не запускается второй раз.

Из документации и примеров в Интернете я ожидаю блокавызываться повторно, если в последовательном буфере есть символы.

Ответы [ 2 ]

3 голосов
/ 12 января 2013

@ KazukiSakamoto правильно указывать, что в дескрипторе файла должно быть установлено O_NONBLOCK. Я обнаружил несколько других проблем, которые могли помешать вам: вы использовали &buffer, тогда как вы просто должны использовать buffer. Кроме того, у вас был 512-байтовый буфер, затем вы считали до 512 байт в него и установили следующий в 0 (для нулевого завершения). Если вы действительно прочитали 512 байт, это вызвало бы переполнение буфера. Кроме того, кажется, readSource является iVar, и вы ссылаетесь на self в блоке. Это может создать цикл сохранения, и его следует избегать.

Во всяком случае, я написал самое тривиальное маленькое приложение, а затем замкнул контакты 2 и 3 моего последовательного порта, чтобы все записанное было отражено обратно, а затем подключил кнопку в моем приложении для отправки некоторых данных. Работал как шарм! Вот код:

@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
1 голос
/ 07 апреля 2011

AFAIK, [self fileDescriptor] должен быть неблокированным.Вы уверены в этом?

fcntl([self fileDescriptor], F_SETFL, O_NONBLOCK);
...