2013-02-08 3 views
1

ORSSerialPort (Objective C)를 사용하여 Arduino에게 지침을 보냅니다. 문제는 내가 보내고있는 지시가 arduino가 즉시 처리 할 수있을만큼 너무 많아서 버퍼를 오버플로한다는 것입니다 (내가 말할 수있는 한). 나는 원래 각 명령 다음에 지연을 추가하여 처리 할 수 ​​있었지만 각 명령을 처리 한 후에 응답을 수신하여 다음 명령에 대한 준비가되었음을 알리고 싶습니다.ORSSerialPort는 응답을 기다립니다.

그러나 arduino의 회신 메시지는 ORDSerialPortDelegate에 의해 선택되어야합니다. 즉, 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

편집 :이 답변은 이제 오래된, 요즘 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이 영원히 돌아갑니다. 실시간 시간 제한을 추가하여 문제를 해결할 수 있습니다. 기본적으로 명령을 보낸 시간을 기록한 다음 waitingForAck이 명령을 보낸 시간의 1 초 (또는 그 이상) 내에 YES로 설정되지 않은 경우 -updateItems에서 벗어나 오류를 적절하게 처리합니다.

이 코드에는 멀티 스레드가 포함되어 있지 않으며 모든 것이 주 스레드에서 수행됩니다 (ORSSerialPort는 내부적으로 백그라운드 스레드를 사용하지만 사용자는 신경 쓸 필요가 없습니다).

실행 루프를 -updateItems으로 돌리면 코드의 다른 부분이 계속 실행됩니다. updateItems을 호출하는 코드는 반환되기를 기다리는 것을 차단하지만 UI는 계속 응답합니다.이를 방지하려면 -updateItems의 시작 부분에 UI의 관련 부분을 사용 중지해야합니다. 예를 들어 진행 표시기 완료된 후에 다시 활성화하십시오.

관련 문제