А если имеете в виду, что ТОЛЬКО по by-path устройства идентифицировать не получится, потому что к порту может быть подключено что угодно, то да, упустил этот момент. Тогда один из вариантов: by-path + VID/PID. Потому как серийник нового устройства надо прописывать, а на это не каждый способен, да и не всегда есть такая возможность
Я вижу несколько способов идентификации устройств (прописание алиасов, как в случае с by-path, в расчет не беру)
VID/PID: очень широко, притом, если свои делать, либо дорого, либо есть риск на чужие VID/PID нарваться, если совместимость с другими девайсами отбрасываем. А использовать общие VID/PID приводит к случаю как с USB/UART: непонятно, что за устройство
По сериийному номеру: можем отличать разные экземпляры, но роботу надо прописать серийник устройства, чтобы он правильно с девайсом работал. Усложняет ремонт в полях. С другой стороны, если работать с однотипными девайсами, то так можно один от другого отличать в программе, и притом, ни с кем не перепутать
По строками Vendor/Model: годится для флешеров, например, или для программ настройки девайсов. Если использовать только их, то есть риск перепутать передние и задние лидары, например
Или что имеете в виду? Комбинации, которые дадут возможность однозначно идентифицировать девайсы?
Если чего-то не хватает, просто задайте уточняющий вопрос.
Если лишь бы перейти на личности, то я базар сворачиваю
Тем, что by-path гарантирует, что на определённом порту датчик/актуатор будет правильно определён, даже если у него нет явных идентов по USB, и робототехническая логика подхватит устройство правильно.
Удобство для быстрого ремонта. Достаточно заменить засбоивший датчик/актуатор, без необходимости прописывать
При этом не защищает от ошибок, например, в случае, если подключили камеру туда, где должен быть лидар. Там уже дополнительный механизм нужен
По by_path без привязки к серийнику появляется возможность быстро заменить модуль в полях или соревнованиях, не залезая в консоль, или проводя там меньше времени
И если проект изначально писался на ESP-IDF (без надстроек типа Platformio), то уже не важно, какая IDE использовалась, можно работать в любой, рекомендую VSCode (а может я просто к нему прикипел).
Расширение для Visual Studio Code (не Visual Studio!) для ESP-IDF тоже даёт возможности и конфижить проект, и прошивать, и мониторить плату, и если навести фокус на окно с терминалом монитора, то всякий ввод с клавиатуры будет на железку пробрасываться, удобно, если сделаешь на железке еще и CLI (текстовую консоль).
Согласен, это есть, и в демо-проекте как раз там храню флаг пробуждения. Однако пробуждение из DeepSleep без явной архитектуры выглядить для МК также, как и включение, и будет пытаться, например, переинициировать модем, а этого не нужно.
Хорошо, можем использовать этот флаг. Но тут добавляются сложности с тем, чтобы правильно устройство выключить. В демо-проекте использую DeepSleep также и для выключения: MP2722 всегда выдает питание при подключенном ЗУ, даже если дана команда на выключение, в документации явно указано, что рубит питание от батареи. Если устройство было запитано от батареи, то до этого DeepSleep выполнение не дойдет, а если была подключена зарядка, то DeepSleep выполнится, с пробуждением по таймеру. И после пробуждения также произойдет инит интерфейсов для контроллера питания кнопки, PowerManagement увидит, что кнопка не нажата, а зарядка подключена, и перейдет в PM_OFF_CHARGER.
Если хранить как набор флагов, то логика управления будет разрозненной, и могут вылезти неочевидные баги, если нет четкого понимания, какие состояния у устройства с точки зрения питания, и как происходят переходы.
Один ноутбук мне сообщал, что батарейка сдохла (Dell Inspiron 1300), точнее, сообщал, что остаточного ресурса в батарее 39,4%, и просил заменить, но это под управлением Ubuntu.
Но это делается по SoH (State of Health), думаю, айфоны и некоторые андроиды тоже так умеют.
По остальным приборам, из-за стремления к удешевлению конечного продукта упрощают схемотехнику и ПО, из-за чего такого поведения не отслеживают
Так такие запросы есть, на выключение, перезагрузку, уход в сон. Но это не те запросы которые МК немедленно выключат/перезагрузят, уведут в сон, а дадут остальной логике к этому приготовиться
Касательно очередей и event_loop: в PowerManagement используется и то, и другое.
Очереди - для запросов самому PowerManagement, например, на задание времени безделья, что делать, если время безделья истекло, выключить/перезагрузить, уйти в сон, обнулить счетчик времени безделья, и другое.
Event-loop используется для рассылки событий как из самого конечного автомата, так и из логики пользователя.
Ещё может быть такое, что на старте батарея с хорошим напряжением, но под нагрузкой напряжение сильно просело, и надо обработать.
Тут согласен, если напряжение сильно просела, то аккум дохлый. И вообще, наиболее точный замер заряда батареи делается не только по напряжению (по модели напряжений батареи на холостом ходу), но и кулонометру. В MP2722 нет встроенного кулонометра, но есть вывод, показывающий ток батареи как на заряд, так и на разряд. Думаю, удастся соорудить программный кулонометр.
P.S. изучив event-loop esp-idf, обнаружил, что там тоже очередь, обработчик которой поочередно запускает делегаты
Ещё момент: запрос на перезагрузку, выключение, уход в сон может быть вызван как из самого конечного автомата, так и из приложения пользователя. При этом, PowerManagement берет на себя и рассылку событий, что устройство скоро уснет/выключится/перезагрузится (и сделает через определенное время), а разработчику остается лишь определить, как этот сигнал будет обработан
Момент №1: модуль хранит статус в массиве статусов только относительно себя и своей логики, если это ведомый модуль
Момент №2: цпу, или ESP32, может потерять состояния, если их хранить в SRAM, а не RTC RAM. Но это ещё полбеды. При просыпании из DeepSleep ESP32 стартует сначала, а не оттуда, где произошло засыпание. Такое умеет LightSleep, но, как оказалось, там тоже свои нюансы по WiFi, и добавлю поддержку и LightSleep. Библиотеку строил с учетом только DeepSleep.
Поэтому, при просыпании из DeepSleep нужно понимать, что стоит таки инициировать заново, а что - нет.
Но я сталкивался с тем, что, например, модем уже инициирован, а устройство надо просто перевести в спящий режим. И при просыпании модем не нужно повторно инициировать. Если бы условий был чуть больше, то это привело бы к спагетти-коду и ненадежной логике обработки состояний питания.
Плюс: если есть контроллер питания, надо опрашивать его состояние, и если надо учитывать пользовательский опыт, то зарядка/кнопка в различных условиях должны обрабатываться по-разному. Например, по-разному отрабатывается подключение/отключение зарядки, когда устройство выключено, в спящем режиме или когда оно работает в активном режиме. Примерно также и с кнопкой. И всё это всё равно приведет к созданию конечного автомата, и я решил собрать этот опыт в библиотеке.
Конкретно по библиотеке, в ней нет привязки к реализации драйвера контроллера питания, а только реализует конечный автомат, и выполнение действий по состояниям может быть реализовано как угодно.
Единственное, что забыл на момент публикации: прямой запрос на включение устройства, если оно запитывается от розетки, аккумулятор как резервный источник, и с розетки подают питание, но добавил позже.
Касательно драйвера в Sony/Nintendo, который допустил, что конкретное поле может быть больше, чем в спецификации SMBus, в моем демо-проекте драйвер к MP2722, который я писал, при запросе значений регистров забирает не более, чем требуется по спецификации (если взлом строился на выходе за пределы массива). ЕМНИП в каждом регистре MP2722 1 байт значения, и оно либо состоит из флагов, либо наборное значение (например, 80+160+1000 мА).
И заметил любопытную вещь: если открывать страницу из России, и в репозитории есть README_RU.md, то он отображается по умолчанию, но как-то можно вызвать и README.md, пока не понял как, но вызвал🙂🙃
На одном из проектов применял схему с генерацией уникальных ключей на каждое устройство, но с шифрованием на борту. Но оно длится долго (около 1-2 минут), и легко забраковать устройство на производстве. А ведь потом еще заводское тестирование запускать.
На следующем проекте доработал схему: подготовка, шифрование частей флешки и сборка в полный бинарник идет на компьютере, а в ESP32 сначала идет прошивка полного шифрованного бинаря, потом прожиг ключа шифрования, и только потом прожиг фьюзов на то, чтобы работал с флешкой, как с шифрованной.
Насколько помню, необходимо и достаточно выставить нечетное количество бит SPI_CRYPT_CNT, чтобы флешка воспринималась как шифрованная. Остальное выставляется в целях безопасности.
Сгенерированные пакеты при этом сохраняю на заводе или на "фабрике устройств" (виртуальная машина, где идет сборка прошивки и подготовка пакетов для устройств с готовыми реквизитами, только прошить). Это нужно для дальнейшего обслуживания.
Естественно, UART Download mode не отключал наглухо. Даже при выставлении Secure Boot UART Download mode ограничивается: esptool.py на чтение/запись не будет работать без флага —no-stub (этот флаг отключает попытку загрузить микропрограмму в оперативку и взаимодействует прямо с флешкой), со stub ESP32 в Download mode настраивается на обмен данными с кешированием.
Погодите, где именно я топлю против udev и топлю за мифический золотой молоток? Я только ЗА udev, но это только одно из средств.
Я топил против жёсткого прописания уникальных идентификаторов для каждого девайса прямо в конфиг-файлы udev, иначе это усложняет замену устройств.
Это в контексте робототехники, где важно иметь возможность быстро заменить девайсину, и так, чтобы другой инженер тоже смог это сделать.
Инженеру по ремонту проще понять из инструкции, что ЭТОТ датчик втыкать ТОЛЬКО в этот порт, а то работать не будет, а то еще и в конфиги лезть.
Для самоделок пофиг, Вы, возможно, и скорректируете и не видите ничего сложного. А что если сыну поручить? Коллеге?
А если имеете в виду, что ТОЛЬКО по by-path устройства идентифицировать не получится, потому что к порту может быть подключено что угодно, то да, упустил этот момент. Тогда один из вариантов: by-path + VID/PID. Потому как серийник нового устройства надо прописывать, а на это не каждый способен, да и не всегда есть такая возможность
Подождите, что имеете в виду под ТОЛЬКО?
Я вижу несколько способов идентификации устройств (прописание алиасов, как в случае с by-path, в расчет не беру)
VID/PID: очень широко, притом, если свои делать, либо дорого, либо есть риск на чужие VID/PID нарваться, если совместимость с другими девайсами отбрасываем. А использовать общие VID/PID приводит к случаю как с USB/UART: непонятно, что за устройство
По сериийному номеру: можем отличать разные экземпляры, но роботу надо прописать серийник устройства, чтобы он правильно с девайсом работал. Усложняет ремонт в полях. С другой стороны, если работать с однотипными девайсами, то так можно один от другого отличать в программе, и притом, ни с кем не перепутать
По строками Vendor/Model: годится для флешеров, например, или для программ настройки девайсов. Если использовать только их, то есть риск перепутать передние и задние лидары, например
Или что имеете в виду? Комбинации, которые дадут возможность однозначно идентифицировать девайсы?
Если чего-то не хватает, просто задайте уточняющий вопрос.
Если лишь бы перейти на личности, то я базар сворачиваю
Тем, что by-path гарантирует, что на определённом порту датчик/актуатор будет правильно определён, даже если у него нет явных идентов по USB, и робототехническая логика подхватит устройство правильно.
Удобство для быстрого ремонта. Достаточно заменить засбоивший датчик/актуатор, без необходимости прописывать
При этом не защищает от ошибок, например, в случае, если подключили камеру туда, где должен быть лидар. Там уже дополнительный механизм нужен
По by_path без привязки к серийнику появляется возможность быстро заменить модуль в полях или соревнованиях, не залезая в консоль, или проводя там меньше времени
И если проект изначально писался на ESP-IDF (без надстроек типа Platformio), то уже не важно, какая IDE использовалась, можно работать в любой, рекомендую VSCode (а может я просто к нему прикипел).
И при том весь проект переписывать не нужно
Расширение для Visual Studio Code (не Visual Studio!) для ESP-IDF тоже даёт возможности и конфижить проект, и прошивать, и мониторить плату, и если навести фокус на окно с терминалом монитора, то всякий ввод с клавиатуры будет на железку пробрасываться, удобно, если сделаешь на железке еще и CLI (текстовую консоль).
И при том без обходных путей для ESP32x
Согласен, это есть, и в демо-проекте как раз там храню флаг пробуждения. Однако пробуждение из DeepSleep без явной архитектуры выглядить для МК также, как и включение, и будет пытаться, например, переинициировать модем, а этого не нужно.
Хорошо, можем использовать этот флаг. Но тут добавляются сложности с тем, чтобы правильно устройство выключить. В демо-проекте использую DeepSleep также и для выключения: MP2722 всегда выдает питание при подключенном ЗУ, даже если дана команда на выключение, в документации явно указано, что рубит питание от батареи. Если устройство было запитано от батареи, то до этого DeepSleep выполнение не дойдет, а если была подключена зарядка, то DeepSleep выполнится, с пробуждением по таймеру. И после пробуждения также произойдет инит интерфейсов для контроллера питания кнопки, PowerManagement увидит, что кнопка не нажата, а зарядка подключена, и перейдет в PM_OFF_CHARGER.
Если хранить как набор флагов, то логика управления будет разрозненной, и могут вылезти неочевидные баги, если нет четкого понимания, какие состояния у устройства с точки зрения питания, и как происходят переходы.
Плюс, в дешевой электронике аккум подыхает чаще всего после окончания срока гарантии, и ты не понесешь в сервис - ты купишь новый девайс.
Если ты рукастый (и если время/желание ремонтировать), то сможешь сам заменить аккумулятор, а если нет, то выставишь на продажу или выкинешь
Один ноутбук мне сообщал, что батарейка сдохла (Dell Inspiron 1300), точнее, сообщал, что остаточного ресурса в батарее 39,4%, и просил заменить, но это под управлением Ubuntu.
Но это делается по SoH (State of Health), думаю, айфоны и некоторые андроиды тоже так умеют.
По остальным приборам, из-за стремления к удешевлению конечного продукта упрощают схемотехнику и ПО, из-за чего такого поведения не отслеживают
Как раз с таким в демо-проекте сталкиваюсь, но из-за старения аккумулятора. Тут разница в подходах:
Просто мониторить напряжение на батарее
Еще и считать кулоны, ну и по напряжению корректировать кулонометр (ну или просто флаг зарядки)
Так такие запросы есть, на выключение, перезагрузку, уход в сон. Но это не те запросы которые МК немедленно выключат/перезагрузят, уведут в сон, а дадут остальной логике к этому приготовиться
Касательно очередей и event_loop: в PowerManagement используется и то, и другое.
Очереди - для запросов самому PowerManagement, например, на задание времени безделья, что делать, если время безделья истекло, выключить/перезагрузить, уйти в сон, обнулить счетчик времени безделья, и другое.
Event-loop используется для рассылки событий как из самого конечного автомата, так и из логики пользователя.
Ещё может быть такое, что на старте батарея с хорошим напряжением, но под нагрузкой напряжение сильно просело, и надо обработать.
Тут согласен, если напряжение сильно просела, то аккум дохлый. И вообще, наиболее точный замер заряда батареи делается не только по напряжению (по модели напряжений батареи на холостом ходу), но и кулонометру. В MP2722 нет встроенного кулонометра, но есть вывод, показывающий ток батареи как на заряд, так и на разряд. Думаю, удастся соорудить программный кулонометр.
P.S. изучив event-loop esp-idf, обнаружил, что там тоже очередь, обработчик которой поочередно запускает делегаты
Ещё момент: запрос на перезагрузку, выключение, уход в сон может быть вызван как из самого конечного автомата, так и из приложения пользователя. При этом, PowerManagement берет на себя и рассылку событий, что устройство скоро уснет/выключится/перезагрузится (и сделает через определенное время), а разработчику остается лишь определить, как этот сигнал будет обработан
Момент №1: модуль хранит статус в массиве статусов только относительно себя и своей логики, если это ведомый модуль
Момент №2: цпу, или ESP32, может потерять состояния, если их хранить в SRAM, а не RTC RAM. Но это ещё полбеды. При просыпании из DeepSleep ESP32 стартует сначала, а не оттуда, где произошло засыпание. Такое умеет LightSleep, но, как оказалось, там тоже свои нюансы по WiFi, и добавлю поддержку и LightSleep. Библиотеку строил с учетом только DeepSleep.
Поэтому, при просыпании из DeepSleep нужно понимать, что стоит таки инициировать заново, а что - нет.
Можно и так, если логика позволяет.
Но я сталкивался с тем, что, например, модем уже инициирован, а устройство надо просто перевести в спящий режим. И при просыпании модем не нужно повторно инициировать. Если бы условий был чуть больше, то это привело бы к спагетти-коду и ненадежной логике обработки состояний питания.
Плюс: если есть контроллер питания, надо опрашивать его состояние, и если надо учитывать пользовательский опыт, то зарядка/кнопка в различных условиях должны обрабатываться по-разному. Например, по-разному отрабатывается подключение/отключение зарядки, когда устройство выключено, в спящем режиме или когда оно работает в активном режиме. Примерно также и с кнопкой. И всё это всё равно приведет к созданию конечного автомата, и я решил собрать этот опыт в библиотеке.
Конкретно по библиотеке, в ней нет привязки к реализации драйвера контроллера питания, а только реализует конечный автомат, и выполнение действий по состояниям может быть реализовано как угодно.
Единственное, что забыл на момент публикации: прямой запрос на включение устройства, если оно запитывается от розетки, аккумулятор как резервный источник, и с розетки подают питание, но добавил позже.
Касательно драйвера в Sony/Nintendo, который допустил, что конкретное поле может быть больше, чем в спецификации SMBus, в моем демо-проекте драйвер к MP2722, который я писал, при запросе значений регистров забирает не более, чем требуется по спецификации (если взлом строился на выходе за пределы массива). ЕМНИП в каждом регистре MP2722 1 байт значения, и оно либо состоит из флагов, либо наборное значение (например, 80+160+1000 мА).
Опубликовал компонент на IDF Components registry
И заметил любопытную вещь: если открывать страницу из России, и в репозитории есть README_RU.md, то он отображается по умолчанию, но как-то можно вызвать и README.md, пока не понял как, но вызвал🙂🙃
Ссылка на компонент в статье, скоро обновлю
Один из голосов напомнил озвучку некоторых игр серии "Нэнси Дрю"
На одном из проектов применял схему с генерацией уникальных ключей на каждое устройство, но с шифрованием на борту. Но оно длится долго (около 1-2 минут), и легко забраковать устройство на производстве. А ведь потом еще заводское тестирование запускать.
На следующем проекте доработал схему: подготовка, шифрование частей флешки и сборка в полный бинарник идет на компьютере, а в ESP32 сначала идет прошивка полного шифрованного бинаря, потом прожиг ключа шифрования, и только потом прожиг фьюзов на то, чтобы работал с флешкой, как с шифрованной.
Насколько помню, необходимо и достаточно выставить нечетное количество бит SPI_CRYPT_CNT, чтобы флешка воспринималась как шифрованная. Остальное выставляется в целях безопасности.
Сгенерированные пакеты при этом сохраняю на заводе или на "фабрике устройств" (виртуальная машина, где идет сборка прошивки и подготовка пакетов для устройств с готовыми реквизитами, только прошить). Это нужно для дальнейшего обслуживания.
Естественно, UART Download mode не отключал наглухо. Даже при выставлении Secure Boot UART Download mode ограничивается: esptool.py на чтение/запись не будет работать без флага —no-stub (этот флаг отключает попытку загрузить микропрограмму в оперативку и взаимодействует прямо с флешкой), со stub ESP32 в Download mode настраивается на обмен данными с кешированием.