4

从串行端口读取时,我在使用 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]

当更多字符被发送到串行端口时,不会调用代码块。我仍然可以从串行端口发送字符,并且可以确认正在发送字符,但该块不会再次运行。

从网络上的文档和示例中,我希望只要串行缓冲区中有字符,就会重复调用该块。

4

2 回答 2

3

@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
于 2013-01-12T16:50:16.647 回答
1

AFAIK,[self fileDescriptor] 应该是非阻塞的。你确定吗?

fcntl([self fileDescriptor], F_SETFL, O_NONBLOCK);
于 2011-04-07T00:29:46.813 回答