4

シリアル ポートから読み取るときに、Grand Central Dispatch Source イベントの使用に問題があります。

シリアル ポートに関連付けられている fileDescriptor から読み取るデータがある場合に、OS がコード ブロックを実行するように、dispatch_source_create を DISPATCH_SOURCE_TYPE_READ と共に使用します。これが私のコードです

- (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 回目に実行されません。

Web 上のドキュメントと例から、シリアル バッファに文字がある限り、ブロックが繰り返し呼び出されることを期待しています。

4

2 に答える 2

3

O_NONBLOCK@KazukiSakamotoは、ファイル記述子が設定されている必要があることを指摘するのは正しいです。私はあなたを妨害しているかもしれない他のいくつかの問題を見つけました:あなたは&bufferちょうどあなたが使うべきであるときにあなたが使っていましたbuffer。また、512バイトのバッファがあり、最大512バイトを読み込んで、次のバッファを0に設定します(ヌル終了の場合)。実際に512バイトを読み取った場合は、バッファオーバーランが発生します。また、readSourceiVarであるように見え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 に答える