Здесь я выполняю миссию спровоцировать аневризму у хардкорных разработчиков микроконтроллеров C/ASM. На этом фронте несколько месяцев назад я опубликовал первую статью в серии, в которой объясняется метод использования магии шаблонов C++ с небольшим количеством наследования для архивирования истинно типобезопасных и проверенных контейнеров во время компиляции без использования динамических выделение памяти.

В этой статье я объясню, как использовать эти контейнеры для использования классов Delegate и Signal, которые можно использовать со следующими требованиями:

  • нет кучи
  • без исключений
  • нет внешних библиотек
  • C++x03

Все эти требования необходимы, чтобы иметь возможность втиснуть класс в микроконтроллер.

В этот момент, возможно, вы спросите: «Но почему?, почему во имя всего хорошего я буду использовать такую ​​штуку во встраиваемом устройстве?

Для микроконтроллера с оперативной памятью 1 КБ, которому нужно только следить за уровнем напряжения и переключать PIN-код по какой-либо причине, я бы сказал, что вам понадобится только компилятор C для вашей архитектуры, но с появлением архитектуры ARM Cortex-M мы наблюдая рост гигантов, таких как семейство микроконтроллеров STM32H7, с большим количеством периферийных устройств, которые вам понадобятся, и большим объемом памяти, которую вы сможете использовать на простом C без каких-либо проблем.

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

Практически невозможно масштабировать ваше приложение, если в его основе лежат макросы и простые обратные вызовы функций C, которые, конечно, являются примерами превосходной кодовой базы C, такой как ядро ​​Linux, но давайте смотреть правде в глаза, средний разработчик не так квалифицирован и дисциплинирован, как разработчик ядра Linux.

Теперь вы могли бы сказать: Но ведь и в C можно реализовать высокоуровневые абстракции, посмотрите на библиотеки «GTK!!!»

Итак, проект GTK представляет собой отличный набор библиотек для разработки приложений с графическим интерфейсом на C, и почти никто не использует его на простом C. Большинство разработчиков используют привязки к другим языкам для взаимодействия с GTK, такие как PyGTK или Vala, из-за церемония / боль использования GTK в простом C влечет за собой.

Используйте Qt,….кашель, кашель……используйте Qt.

делегат

В приведенном ниже коде показан пример класса Delegate, связывающего каждый тип… «вещи»…. которые могут быть ограничены в C++.

Класс может связываться:

  • глобальная функция
  • метод статического класса
  • метод класса

Ограничено только одним методом за раз и нулем (void) или одним параметром (передается по значению). В классе есть оператор вызова функции (), перегруженный для вызова связанного метода (если он есть). Он спроектирован так, чтобы быть наименее навязчивым, и если он вызывается без привязки к методу, он просто ничего не делает. Если у него есть связанный метод, и вы хотите связать другой, он позволит вам это сделать. Также имеет служебные функции, такие как isBinded(), isUnbinded() и clear(), и они делают то, что, по вашему мнению, должны делать.

Сигнал

Класс Signal, который многое заимствует из концепции сигнал и слоты Qt, я большой поклонник Qt, для меня это единственный способ программировать на C++ без слез.

Этот класс содержит внутренний массив делегатов, размер которого необходимо указать во время компиляции.

В примере создаются два сигнала, один из которых может быть связан с четырьмя функциями, а другой имеет параметр int и может быть связан с двумя функциями.

Подключенные методы/функции вызываются в том же порядке, в котором они подключены. Соединения могут быть перезаписаны, они должны быть отключены явным образом.

Помните, что эти классы предназначены для использования в среде, где никакие объекты никогда не уничтожаются, поэтому вы должны быть уверены, что экземпляр, к которому подключен de signal, жив, когда вызывается метод notify(). Если подключенный экземпляр будет уничтожен, а сигнал сработает, тогда… Kaput!!

Реализация Delegate and Signal Pattern упростит разработку приложений микроконтроллеров, которые должны выполнять несколько задач и, что, возможно, более важно, должны поддерживаться в течение нескольких лет.

Эти два класса являются частью иерархической библиотеки конечного автомата, которую можно найти здесь.

Следующая статья в этой серии будет о том, что такое иерархическая библиотека конечных автоматов и как и какие проблемы она решает.

Переиздано с linkedin.