Правильные методы реализации функционального клиентского доступа к асинхронному последовательному интерфейсу?
Это вопрос не для новичков.
Я реализую функциональный интерфейс для асинхронного последовательного устройства, подключенного к порту Serial1 на mega.
Чтобы обеспечить ясность, я хочу реализовать ряд функций таким образом:
{param} CallInterface({param1},{param2},...) {
sendRequestPacket();
....{await Response or timeout}....
return Response;
}
Очевидно, что когда мы "ожидаем ответа", мы блокируем операционный поток и должны разрешить доступ к дополнительному процессору потока, чтобы получить и проанализировать ответ.
На многопоточной платформе это было бы тривиально реализовать с помощью семафоров и других многопоточных методов, но на Arduino, AVR решение, возможно, менее очевидно или нет.
Итак, вопрос в том, каков наилучший и наиболее эффективный способ реализации такого шаблона на платформе Arduino?
@Mark, 👍-1
Обсуждение1 ответ
Типичный способ справиться с такими вещами - иметь одну "главную" функцию, которая управляет всем, используя конечный автомат неблокирующим способом.
Эта функция может содержать всю логику для выполнения каких-либо действий, или же она может быть проще и просто обрабатывать базовую коммуникацию, а затем передавать детали функции обратного вызова, указанной в вызове функции действия.
Таким образом, поток может быть:
- Вы вызываете функцию, которая просто устанавливает вещи:
- Он хранит подробную информацию о запросе, который должен быть сделан
- Он записывает адрес функции "обратного вызова".
- Вы многократно выполняете свою функцию "run" из
loop().
- Он посылает команду цели
- Он получает и анализирует ответ, сохраняя его где-то внутри
- Когда ответ завершен он выполняет функцию обратного вызова передавая ей ответ
Не все из 2 будет происходить на каждой итерации loop()
, поэтому напишите его неблокирующим способом (используя .available()
и т. Д.) И вызовите обратный вызов только тогда, когда все будет завершено.
Таким образом, вы можете настроить цепочку событий:
- Вы отправляете запрос 1 с обратным вызовом A.
- Обратный вызов A отправляет запрос 2 с обратным вызовом B.
- Обратный вызов B отправляет запрос 3 с обратным вызовом C.
... и так далее ...
В качестве примера вот как может выглядеть элемент управления модемом:
Modem.command("AT+CREG?", testRegistration);
>>> send AT+CREG?
<<< store +CREG: 0,2
<<< store
<<< identify OK
--- Execute testRegistration(true, "+CREG: 0,2\n\n");
Или, может быть, если что-то пойдет не так:
Modem.command("AT+CROG?", testRegistration); // Ой, опечатка...
>>> send AT+CROG?
<<< identify ERR
--- Execute testRegistration(false, "");
- Как разделить входящую строку?
- Какова максимальная длина провода для последовательной связи между двумя Arduino?
- Последовательная связь между двумя Arduino (запрос и получение)
- Не нашел датчик отпечатков пальцев :( Arduino Mega 2560 Adafruit Fingerprint Sensor
- Модуль SIM808: команда определения местоположения GSM (AT+CIPGSMLOC=1,1) дает неверное значение после выполнения команды отправки сообщения (AT+CMGS=+91xxxxxxxx)
- Как правильно получить MIDI с Arduino, с 6n138?
- Bluetooth-модуль HC-05 не принимает AT-команды
- Дождаться получения ВСЕХ последовательных данных.
Очевидно, что когда мы "ждем ответа", мы блокируем операционный поток
... на самом деле это не очевидно... вы можете использовать неблокирующий код, @jsotolaТрудно сказать, что является “лучшим и наиболее эффективным”, не зная точных требований вашего проекта. Однажды я столкнулся с подобной ситуацией, когда мне нужно было, чтобы мой код был неблокирующим. Затем я добавил параметр “callback” в "CallInterface", на который должен быть доставлен ответ, и метод "update ()" к объекту, реализующему интерфейс, чтобы он перехватил ответ и доставил его в обратный вызов., @Edgar Bonet
@jsotola не могли бы вы проследить за этим примером неблокирующего шаблона кода, который будет работать на платформе Arduino?, @Mark
@EdgarBonet Спасибо Эдгар, да, это аналогичная модель Async Javascript / Node. Первоначальные впечатления таковы, что мне нужно будет реализовать массив обратного вызова в коде получателя, чтобы захватить все потенциальные запросы на эти данные, которые должны быть выполнены, когда и если ответ поступит. Единственная проблема, которую я предвижу, заключается в том, что между запросом и ответом нет никакой "связи", кроме того факта, что ответ происходит вскоре после запроса., @Mark
Невозможно связать конкретный запрос с конкретным ответом, кроме как блокировать запросы до тех пор, пока не будут выполнены все ожидающие запросы или не наступит тайм-аут., @Mark
один из параметров вызова может быть переадресован в обратный вызов. или с помощью лямбд вы можете фиксировать параметры, @Juraj