开发者

Unable to use GCD dispatch sources for reading from Serial Port file descriptors

开发者 https://www.devze.com 2023-02-16 13:06 出处:网络
I\'m having trouble using Grand Central Dispatch Source events when reading from serial ports. I use dispatch_source_create with DISPATCH_SOURCE_TYPE_READ so that the OS will run my block of code whe

I'm having trouble using Grand Central Dispatch Source events when reading from serial ports.

I use dispatch_source_create with DISPATCH_SOURCE_TYPE_READ so that the OS will run my block of code when there is data to be read from the fileDescriptor that is associated with a s开发者_C百科erial port. Here is my code

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

When the program runs the block is called the first time serial data is sent to the port. I then get a message in the console

[Switching to process 11969 thread 0x6603]

When more characters are sent to the serial port the block of code is not called. I can still send characters out of the serial port and I can confirm that characters are being sent in but the block doesn't run a second time.

From the documentation and examples on the web I am expecting the block to be called repeatedly so long as there are characters in the serial buffer.


@KazukiSakamoto is correct to point out that the file descriptor should have O_NONBLOCK set on it. I found a few other issues that may have been jamming you up: You were using &buffer when you should just be using buffer. Also, you had a 512 byte buffer, then you read up to 512 bytes into it and set the next one to 0 (for null termination). In the event you actually did read 512 bytes, that would have caused a buffer overrun. Also, it appears readSource is an iVar, and you reference self in the block. This is likely to create a retain cycle and should be avoided.

Anyhow, I wrote the most trivial little application, and then shorted pins 2 and 3 of my serial port, so anything written out would be echoed back in, then hooked up a button in my app to send some data. Worked like a charm! Here's the code:

@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


AFAIK, [self fileDescriptor] should be nonblock. Are you sure of it?

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

精彩评论

暂无评论...
验证码 换一张
取 消