Правильные методы реализации функционального клиентского доступа к асинхронному последовательному интерфейсу?
Это вопрос не для новичков.
Я реализую функциональный интерфейс для асинхронного последовательного устройства, подключенного к порту 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-команды
- Сбой Arduino во время последовательной печати без очевидной причины
Очевидно, что когда мы "ждем ответа", мы блокируем операционный поток
... на самом деле это не очевидно... вы можете использовать неблокирующий код, @jsotolaТрудно сказать, что является “лучшим и наиболее эффективным”, не зная точных требований вашего проекта. Однажды я столкнулся с подобной ситуацией, когда мне нужно было, чтобы мой код был неблокирующим. Затем я добавил параметр “callback” в "CallInterface", на который должен быть доставлен ответ, и метод "update ()" к объекту, реализующему интерфейс, чтобы он перехватил ответ и доставил его в обратный вызов., @Edgar Bonet
@jsotola не могли бы вы проследить за этим примером неблокирующего шаблона кода, который будет работать на платформе Arduino?, @Mark
@EdgarBonet Спасибо Эдгар, да, это аналогичная модель Async Javascript / Node. Первоначальные впечатления таковы, что мне нужно будет реализовать массив обратного вызова в коде получателя, чтобы захватить все потенциальные запросы на эти данные, которые должны быть выполнены, когда и если ответ поступит. Единственная проблема, которую я предвижу, заключается в том, что между запросом и ответом нет никакой "связи", кроме того факта, что ответ происходит вскоре после запроса., @Mark
Невозможно связать конкретный запрос с конкретным ответом, кроме как блокировать запросы до тех пор, пока не будут выполнены все ожидающие запросы или не наступит тайм-аут., @Mark
один из параметров вызова может быть переадресован в обратный вызов. или с помощью лямбд вы можете фиксировать параметры, @Juraj