编辑:这个答案现在已经过时了,现在 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 秒(或其他时间)内没有设置为“是”,则您会中断-updateItems
并适当地处理错误。
这段代码没有涉及多线程,一切都在主线程上完成(ORSSerialPort 在内部使用后台线程,但你不需要关心)。
旋转运行循环-updateItems
意味着代码的其他部分将继续运行。调用的代码updateItems
会阻塞等待它返回,但你的 UI 会继续响应,等等。如果你需要阻止这种情况,你应该在开头禁用 UI 的相关部分-updateItems
,也许显示一个进度指示器,然后完成后重新启用它们。