ORSSerialPort等待回复

时间:2013-02-08 11:09:20

标签: objective-c delegates serial-port nsthread orsserialport

我正在使用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

    }

}

1 个答案:

答案 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的相关部分可能会显示进度指示器,然后在完成后重新启用它们。