EDIT: This answer is old now, and these days ORSSerialPort includes built in API to handle exactly the scenario described here. You can now do something like:
@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
}
Original answer below:
What I do is to keep a queue of commands to be sent. After I receive a proper reply to the most recently sent command (or timeout waiting for a reply), I send the next command in the queue.
You should be able to do something like this:
@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
A couple notes about this code/approach. It's not very smart about errors. As currently written, it will never time out, so if the Arduino fails to respond to a command for whatever reason, -updateItems
will run forever. You can fix that by adding a real timeout. Basically, you take note of the time you sent the command, then if waitingForAck
hasn't been set to YES within 1 second (or whatever) of the time you sent the command, you break out of -updateItems
and handle the error appropriately.
There is no multithreading involved in this code, everything is done on the main thread (ORSSerialPort uses background threads internally, but you don't need to care about that).
Spinning the run loop in -updateItems
means that other parts of your code will continue to run. The code that calls updateItems
will block waiting for it to return, but your UI will continue to respond, etc. If you need to prevent that, you should disable the relevant parts of your UI at the beginning of -updateItems
, perhaps showing a progress indicator, then reenable them after it finishes.