編集:この回答は現在古く、最近の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
、進行状況インジケーターを表示する必要があります。終了したら、それらを再度有効にします。