1

ORSSerialPort (Objective C) を使用して Arduino に命令を送信しています。問題は、私が送信した命令が多すぎて arduino が一度に処理できず、バッファーがオーバーフローすることでした (私が知る限り)。もともとは、各命令の後に遅延を追加して処理できるようにしていましたが、次の命令の準備ができていることを確認できるように、各命令を処理した後に応答を受け取りたいです。

ただし、arduino からの応答メッセージは、ORSSerialPortDelegate によって取得される必要があります。これは、メイン ループが arduino にさらに命令を送信し続けるのを止めないことを意味します。

このようなものを機能させるための最良の方法は何ですか? 次のコードは、メインスレッドをブロックしないようにメインスレッドとは別のスレッドにある必要がありますが、アイテムの更新を継続するシグナルを受け取るまで updateItems ループをブロックしたいと思います。

-(void)updateItems
{
//Loop through each item.
   //Get the next instruction in the item's buffer
   //execute (send via serial to arduino)
   //wait for acknowledged reply --How do I wait for an acknowledgement?

}

- (void)serialPort:(ORSSerialPort *)serialPort didReceiveData:(NSData *)data
{
    NSLog(@"Received Data");

    NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    if([string isEqualTo:@"0\r\n"]) //ack signal
    {
        //Serial port is now ready to accept another instruction

    }

}
4

1 に答える 1

1

編集:この回答は現在古く、最近のORSSerialPortには、ここで説明するシナリオを正確に処理するための組み込みAPIが含まれています。これで、次のようなことができます。

@implementation MyClass

- (void)updateItems
{
    // We can just send these all in a for loop. ORSSerialPort will handle 
    // queuing them and waiting for a response to each before going on to the next request
    for (NSData *command in self.commands) {
        ORSSerialPacketDescriptor *response = 
            [[ORSSerialPacketDescriptor alloc] initWithPacketData:[@"foo" dataUsingEncoding:NSASCIIStringEncoding] userInfo:nil];
        ORSSerialRequest *request = [ORSSerialRequest requestWithDataToSend:command userInfo:nil timeoutInterval:1.0 responseDescriptor:response];
        [self.serialPort sendRequest:request];
    }
}

- (void)serialPort:(ORSSerialPort *)serialPort didReceiveResponse:(NSData *)data toRequest:(ORSSerialRequest *)request
{
    NSLog(@"Received response: %@ to request: %@", data, request.dataToSend);
    if (serialPort.queuedRequests.count == 0) {
        // All done! Do whatever comes next.
    }
}

- (void)serialPort:(ORSSerialPort *)serialPort requestDidTimeout:(ORSSerialRequest *)request
{
    // Something went wrong!
    [self.serialPort cancelAllQueuedRequests]; // Stop sending the rest of the commands
}

以下の元の答え:

私がしていることは、送信されるコマンドのキューを保持することです。最後に送信されたコマンドへの適切な応答を受信した後(または応答を待機するタイムアウト)、キュー内の次のコマンドを送信します。

あなたはこのようなことをすることができるはずです:

@interface MyClass ()
    @property BOOL waitingForAck;
@end

@implementation MyClass

- (void)updateItems
{
    for (NSData *command in self.commands) {
        [self.serialPort sendData:command];
        self.waitingForAck = YES;
        while (self.waitingForAck) {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                             beforeDate:[NSDate distantFuture]];
        }
    }
}

- (void)serialPort:(ORSSerialPort *)serialPort didReceiveData:(NSData *)data
{
    NSLog(@"Received Data");

    NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    if([string isEqualTo:@"0\r\n"]) //ack signal
    {
        //Serial port is now ready to accept another instruction
        self.waitingForAck = NO;
    }
}

@end

このコード/アプローチに関するいくつかのメモ。エラーについてはあまり賢くありません。現在書かれているように、タイムアウトになることはないので、何らかの理由でArduinoがコマンドに応答しなかった場合、-updateItems永久に実行されます。実際のタイムアウトを追加することで、これを修正できます。基本的には、コマンドを送信した時刻に注意し、コマンドを送信してwaitingForAckから1秒(またはそれ以降)以内にYESに設定されていない場合は、エラーから抜け出し-updateItems、エラーを適切に処理します。

このコードにはマルチスレッドは含まれていません。すべてがメインスレッドで実行されます(ORSSerialPortは内部でバックグラウンドスレッドを使用しますが、それについて気にする必要はありません)。

実行ループをスピンインする-updateItemsと、コードの他の部分が引き続き実行されます。呼び出すコードは、コードがupdateItems戻るのを待つのをブロックしますが、UIは引き続き応答します。これを防ぐ必要がある場合は、最初にUIの関連部分を無効にして-updateItems、進行状況インジケーターを表示する必要があります。終了したら、それらを再度有効にします。

于 2013-02-08T16:58:40.207 に答える