从串行端口读取时,我在使用 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]
当更多字符发送到串行端口时,不会调用代码块。我仍然可以从串行端口发送字符,我可以确认正在发送字符但块不会第二次运行。
从网络上的文档和示例中,我希望只要串行缓冲区中有字符,就会重复调用该块。
最佳答案
@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
关于cocoa - 无法使用 GCD 调度源读取串行端口文件描述符,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5298412/