2

http://playground.arduino.cc/Interfacing/Cocoa ( IOKit/ioctl method )で提供されているコードに従って、Arduino から Cocoa アプリケーションにデータを送信するために、シリアル通信の例を実行しようとしています。動作しますが、一度開始した受信スレッドを停止することはできません。

開始時にシリアル ポートを開き、レシーバー スレッドを起動するスイッチ ボタン ( Start/Stop ) を実装しました。

- (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の状態変化を受信スレッドが認識していないようです。

4

1 に答える 1

0

それで、startButton:ポートを開き、スレッドを生成してそこから読み取りを開始し、すぐにポートを閉じますか?それはうまくいきません。

startButton:ポートを閉じないでください。読み取りスレッドが完了したときに実行するためにそれを残し、他の理由(終了など)でポートを閉じる必要がある場合にのみメインスレッドで実行します。

グローバル変数は、定義上、プログラム全体で表示されます。これには、スレッドの境界を越えたものも含まれます。readThreadRunningがに設定されていない場合FALSE(これは、エキゾチックなものに定義されていないことを前提としFALSEています)、読み取りスレッドのループはまだ実行されている必要があります。まだデータを読み取っている、またはreadブロックされている(さらにデータを待機している)。

readさらにデータがあるかどうかを知る方法がないことに注意してください。コード内のコメントにあるように、返されるデータあるか、ポートが閉じられるまでブロックされます。読み取る必要のあるデータの量を事前に把握し、その量を読み取ったら停止する方法を検討するか、すべてが送信されたときに反対側のポートを閉じることができるかどうかを確認する必要があります。受け取った。

于 2013-02-19T20:51:32.787 に答える