ORSSerialPort ждет ответа

Я использую ORSSerialPort (Цель 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 ответ

Решение

РЕДАКТИРОВАТЬ: Этот ответ уже устарел, и в наши дни 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 не было установлено значение YES в течение 1 секунды (или чего-либо другого) после того, как вы отправили команду, вы выходите из -updateItems и обработать ошибку соответствующим образом.

В этом коде нет многопоточности, все выполняется в основном потоке (ORSSerialPort использует фоновые потоки внутри, но вам не нужно об этом заботиться).

Вращение цикла запуска в -updateItems означает, что другие части вашего кода будут продолжать работать. Код, который вызывает updateItems будет блокировать ожидание его возвращения, но ваш пользовательский интерфейс будет продолжать отвечать и т. д. Если вам нужно это предотвратить, вы должны отключить соответствующие части вашего пользовательского интерфейса в начале -updateItems, возможно, показывая индикатор прогресса, а затем включите их после его завершения.

Другие вопросы по тегам