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
, возможно, показывая индикатор прогресса, а затем включите их после его завершения.