cocoa - 如何关闭Cocoa后台线程中的串行通信

标签 cocoa serial-port arduino

我正在尝试运行一个串行通信示例,以便按照 http://playground.arduino.cc/Interfacing/Cocoa 中提供的代码将数据从 Arduino 发送到 Cocoa 应用程序(IOKit/ioctl 方法)。它有效,但一旦启动我就无法停止接收器线程。

我实现了一个开关按钮(开始/停止),它在启动时打开串行端口并启动接收器线程:

- (IBAction) startButton: (NSButton *) btn {
(…)
error = [self openSerialPort: [SelectPort titleOfSelectedItem] baud:[Baud intValue]];
(…)
[self refreshSerialList:[SelectPort titleOfSelectedItem]];
[self performSelectorInBackground:@selector(incomingTextUpdateThread:) withObject:[NSThread currentThread]];
(…)
}

线程代码实际上与示例中的相同,只是我包含了从接收的缓冲区重建串行数据包并将其保存到 SQLite 数据库的代码:

- (void)incomingTextUpdateThread: (NSThread *) parentThread {

// mark that the thread is running
readThreadRunning = TRUE;

const int BUFFER_SIZE = 100;
char byte_buffer[BUFFER_SIZE];  // buffer for holding incoming data
int numBytes=0;                 // number of bytes read during read

(…)

// assign a high priority to this thread
[NSThread setThreadPriority:1.0];

// this will loop until the serial port closes
while(TRUE) {
    // read() blocks until some data is available or the port is closed
    numBytes = (int) read(serialFileDescriptor, byte_buffer, BUFFER_SIZE); // read up to the size of the buffer
    if(numBytes>0) {
        // format serial data into packets, but first append at start the end of last read
        buffer = [[NSMutableString alloc] initWithBytes:byte_buffer length:numBytes encoding:NSASCIIStringEncoding];
        if (status == 1 && [ipacket length] != 0) {
           [buffer insertString:ipacket atIndex:0];
           numBytes = (int) [buffer length];
        }
        ipacket = [self processSerialData:buffer length:numBytes];   // Recompose data and save to database.
    } else {
        break; // Stop the thread if there is an error
    }
}

// make sure the serial port is closed
if (serialFileDescriptor != -1) {
    close(serialFileDescriptor);
    serialFileDescriptor = -1;
}

// mark that the thread has quit
readThreadRunning = FALSE;

}

我尝试使用以下代码关闭主线程中的端口,该代码也是 startButton 选择器的一部分,遵循提供的示例:

if (serialFileDescriptor != -1) {
    [self appendToIncomingText:@"Trying to close the serial port...\n"];
    close(serialFileDescriptor);
    serialFileDescriptor = -1;

    // Revisar... crec que el thread no s'adona que s'ha tancat el file descriptor...
    // wait for the reading thread to die
    while(readThreadRunning);
    // re-opening the same port REALLY fast will fail spectacularly... better to sleep a sec
    sleep(0.5);

    //[btn setTitle:@"Start"];
    [Start setTitle:@"Start"];
}

但是接收线程似乎不知道全局变量serialFileDescriptor的状态变化。

最佳答案

那么,startButton: 打开端口,生成一个线程以开始从中读取数据,然后立即关闭端口?结果不会很好。

startButton: 不应关闭端口。完成后将其留给读取线程执行,仅当您因其他原因(例如退出)需要关闭端口时才在主线程上执行此操作。

根据定义,全局变量在整个程序中都是可见的,这包括跨线程边界。如果 readThreadRunning 未设置为 FALSE(假设 FALSE 尚未定义为外来的东西),那么您的读取线程的循环必须仍在运行。要么仍在读取数据,要么读取被阻塞(正在等待更多数据)。

请注意,read无法知道是否会有更多数据。正如代码中的注释所述,它将阻塞,直到它有一些数据要返回或端口关闭为止。您应该想出一种方法来提前知道需要读取多少数据,并在读完那么多数据后停止,或者看看是否可以在所有内容都发送完毕后关闭另一端的端口,已收到。

关于cocoa - 如何关闭Cocoa后台线程中的串行通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14957463/

相关文章:

objective-c - TextView 文本追加

xcode - 从脚本创建 DMG 时出现一些问题

swift - 背景清晰的 NSProgressIndicator

c++ - 模拟串口

c - 如何在字节变量中设置位(Arduino)

objective-c - 如何更改 mp3 中的元数据

c - 如何在 PC 上访问我的 9 位数据串口?

C# 打开虚拟串口抛出 ArgumentException

c# - 串口+C#数据接收问题

php - 通过以太网发布 arduino 数据以显示到 php