Перейти к содержанию
    

Плавный переход C -> C++ под МК

22 minutes ago, Arlleex said:

Хорошо, когда вектор прерывания периферии выделен только для нее. Но бывают вектора, которые делят между собой несколько периферийных блоков. Например, TIM6_DAC_IRQHandler. Как здесь поможет делегат?

Бывают мульти-делегаты, тогда на один "вектор" можно повесить сколько угодно делегатов. Такое у меня предусмотрено, но пока что никогда не пользовался. Не было нужды.

 

22 minutes ago, Arlleex said:

А еще, бывает, одна и та же периферия оккупирует несколько векторов, например, TIM8_CC_IRQHandler, TIM8_TRG_COM_TIM14_IRQHandler, TIM8_UP_TIM13_IRQHandler, TIM8_BRK_TIM12_IRQHandler...

Тут еще проще - просто расширяется список методов для подключения всех этих векторов. Достаточно лишь дать осмысленные имена этим методам.

 

 

22 minutes ago, Arlleex said:

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

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

Т.е. таймер является собственностью некого логического блока проекта и уже к этому блоку стучаться другие.

Но я стараюсь всегда каждый аппаратный блок сделать собственностью (private) другого блока/модуля. 

Как правило у меня в проектах запас по аппаратным ресурсах крайне избыточный, т.к. стоимость камня в общей стоимости проектов - капля в море. Даже с учетом последних цен )

 

 

22 minutes ago, Arlleex said:

Грубо говоря, есть вектор TIM2_IRQHandler. И есть N объектов класса nsFIFO::cUARTDMARx, которым нужен аппаратный таймер для отсчитывания 1мс интервалов ("стандартный" механизм DMA + TIM в STM32 для приема неизвестного количества байтов в непрерывном режиме по UART-у).

Для 1мс интервалов есть OS, для микросекундных - таймеры.

Как-то делал некий диспетчер для управления аппаратными таймерами для формирования точных временных отрезков. Так вот этот блок содержал внутри себя все таймеры, доступные для этой цели. И этот блок/модуль распределял какой таймер кому достанется.

А уже снаружи другие модули стучались и просили на время по-пользоваться таким таймером. Т.к. время владения таймера крохотное, то всем просящим хватало доступных 4х таймеров (какой-то древний проц. типа ELAN). 

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

 

 

22 minutes ago, Arlleex said:

Разве делегатом можно "привязаться" к одному аппаратному вектору в нескольких инстанциях?

Мультиделегат. Но я избегаю таких толстых решений. В МК это избыточно, хотя в жирных и мощных вполне реализуемо.

На самом деле если столкнусь, наверняка найду еще более красивое и простое решение )

Остальная часть кода этого даже и не заметит.

 

 

22 minutes ago, Arlleex said:

Т.е. какое здесь решение наиболее изящно? У меня, пока что, кроме как создать публичные методы svcOnDMAIrq() и svcOnTmrIrq(), дергать их из обработчика соответствующего вектора прерывания DMA и таймера, идей нет. Но здесь нужно всегда руками "добавлять" обработку конкретного экземпляра класса в соответствующих векторах. Может, я чего-то не знаю?:blush:

Не совсем понял, скорее вообще не понял ((

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 минуты назад, Forger сказал:

Не совсем понял, скорее вообще не понял ((

class A {
  ...
  public:
    void svcOnDMAIrq();
    void svcOnTmrIrq();
};

...

A obj1;

...

// явно вызываем "обработчики" в объекте

extern "C" void DMA1_Stream0_IRQHandler() {
  obj1.svcOnDMAIrq();
}

extern "C" void TIM2_IRQHandler() {
  obj1.svcOnTmrIrq();
}

Если создать еще obj2, obj3... то для них нужно будет в TIM2_IRQHandler() "добавлять" вызовы svcOnTmrIrq().

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 minutes ago, Arlleex said:

Если создать еще obj2, obj3... то для них нужно будет в TIM2_IRQHandler() "добавлять" вызовы svcOnTmrIrq().

Мульти-делегаты или отдельный диспетчер для управления сторонними подключениями к одному обработчику. Стучаться к диспетчеру, он подключит новый делегат в список. 

Список тогда может быть жесткий, на конкретное число подключения или на край "резиновый" список (мульти-делегат).

В данном случае скорее первое - жесткой список. Не обязательно полностью забивать весь список - пустые делегаты почти не жрут ресурса при вызове.

 

Признаюсь, пока не сталкивался с этой нуждой.

Но стало вдруг интересно попробовать (пока с академической точки зрения) ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кошмар, я ничего не понял:biggrin: Ладно, пока что реализую как понимаю, а дальше будь что будет).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 minutes ago, Arlleex said:

Кошмар, я ничего не понял:biggrin: Ладно, пока что реализую как понимаю, а дальше будь что будет).

Мульти-делегат - это по сути односвязный список других делегатов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 minutes ago, Arlleex said:

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

Ничего подобного ))

Вот вызов делегата с момента входа в обработчик, BX - это уже вызов конкретно user-обработчика, который повешен на делегат (метод-класса):

В r0 записывается соотв. this владельца этого user-метода. В r1 - адрес этого user-метода. Это по сути вызов c++ метода класса. Оптимизация конечно включена. Компилятор конечно v6. Справляется на ура )

 

Вызов делегата.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

35 минут назад, Forger сказал:

Вызов делегата.jpg

И это называется "ничего жирного"???  :shok:

Почти десяток тактов там, где по уму вообще ни одного такта не требуется! А может и больше десятка тактов, может даже все 20 тактов (как с кешем и латентностью флеши повезёт повезёт).

Да ещё ОЗУ требуется (указатели читаются из ОЗУ). Это просто пустое транжиренье ресурсов. Ради шашечек....

 

PS: Да и кроме этих 3-х команд мы видим сверху и снизу ещё некие команды. Про которые вы умолчали. Подозреваю что в реале там ещё больше ресурсов нужно.  :sarcastic:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, jcxz said:

Это просто пустое транжиренье ресурсов. Ради шашечек....

Для вас "шашечки", а для меня - необходимость. Не все способны держать в голове чудовищную кашу и запутанной структуры проекта и горы мудреных макросов ради макросов. Я так не умею. Не расстроен ни разу.

И мне глубоко плевать на немного бОльший расход озу - камни у меня в проектах всегда имеют многократный запас по ресурсам. Впроголодь не живем, как некоторые :)

Читаемость кода на первом месте для меня. К тому же вызов через делегат позволяет избежать вложенного вызова цепочки методов, как этого приходилось делать раньше.

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

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

 

1 hour ago, jcxz said:

Да и кроме этих 3-х команд мы видим сверху и снизу ещё некие команды.

При особо богатой фантазии можно и не такое увидеть :)

Желтым цветом выделена команда, адрес которой вписан в таблицу векторов в соотв. месте. Т.е. это - первая команда, которая вызывается при входе в конкретно взятый обработчик.

Последняя 4я - это безусловный переход на сам метод, адрес которого забит в этот делегат.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Читаю про ссылки. В целом, все понятно, как использовать тоже понятно.

Не понятно одно: зачем они нужны, когда есть указатели? Ну т.е. их же ведь не спроста придумали и ввели в синтаксис языка.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Arlleex сказал:

зачем они нужны, когда есть указатели?

Они нужны для реализации механизма перегрузки операторов. Для него важно, чтобы семантика использования ссылок на объекты была идентична семантике работы с самими объектами.

Вот ещё интересная статья про указатели и ссылки: чем они похожи, а чем различаются.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

20 часов назад, Arlleex сказал:

Не понятно одно: зачем они нужны, когда есть указатели? Ну т.е. их же ведь не спроста придумали и ввели в синтаксис языка.

Их ввели, когда захотели сделать перегрузку операторов. 

 

Upd. Пардон, не рассмотрел предыдущий пост. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12.05.2021 в 13:40, Arlleex сказал:

Т.е. именование становится контекстно-зависимым, а не как в Си - прямым по имени и только лишь.

Линус Товальдс в свое время это свойство поставил в беду с++ - для патч-менеджмента такой код  катастрофа.

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попутать код можно только написав его задней пяткой. ИМХО. А если оно уже написано и отлажено сто раз, то и лазить в реализацию не имеет смысла.

Линус Торвальдс для меня не авторитет, я вообще в авторитеты себе никого не ставлю, особенно в программировании. Слишком много в нем религиозных предубеждений, которые мешают адекватной индивидуальной оценке всяких "за" и "против" каких-то подходов, которые, вообще-то, нужно "прочувствовать" на собственной шкуре. Но и изолироваться от внешнего мира нельзя, т.к. это путь в никуда, поэтому я и задаю здесь свои тупые вопросы, получаю ответы и пропускаю их через свои субъективные фильтры "это правильно, а это не правильно нифига, т.к. не ложится на мое видение удобства пользования инструмента (языка C++)". Я считаю, что катастрофа - это когда физический объем кода настолько большой, что время на его освоение другим разработчиком просто не вписывается ни в какие рамки. А на плюсах писать основную логику программы куда лаконичнее и понятнее, ИМХО (в этом удалось убедиться на нескольких чужих проектах), чем на Си.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

58 минут назад, Arlleex сказал:

Я считаю, что катастрофа - это когда физический объем кода настолько большой, что время на его освоение другим разработчиком просто не вписывается ни в какие рамки.

Если речь про работу в команде, то работа там должна быть организована так, чтобы не было необходимости освоения другим разработчиком кода соседа. Это достигается построением API взаимодействия разных модулей программы (ведомых разными разработчиками).

А если речь про какой-то чужой код, который вы берёте и встраиваете в свой проект (или изучаете), то тут, имхо, играет роль не си/си++, а стиль написания того чужого кода. Чем он ближе к вашему - тем понятнее. Плюсовость тут по-моему не играет ни какой роли. Может даже наоборот - осложнять освоение (вам например удобнее для какой-то операции перегрузить оператор '+=' для своего класса, а другой человек будет всё время на этом спотыкаться; ему удобнее и понятнее - через член-функции).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...