我正在使用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
}
}
答案 0 :(得分:1)
编辑:这个答案现在已经过时了,现在ORSSerialPort包含built in 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
将永远运行。您可以通过添加实际超时来解决此问题。基本上,您注意到发送命令的时间,然后如果在发送命令的1秒(或其他)时间内waitingForAck
未设置为YES,则会突破{{1}并适当地处理错误。
此代码中没有涉及多线程,一切都在主线程上完成(ORSSerialPort在内部使用后台线程,但您不需要关心它)。
在-updateItems
中旋转运行循环意味着代码的其他部分将继续运行。调用-updateItems
的代码将阻止等待它返回,但您的UI将继续响应,等等。如果您需要阻止它,您应该在{{1}的开头禁用UI的相关部分可能会显示进度指示器,然后在完成后重新启用它们。