|
call back, обменяемся мнениями |
|
|
|
Oct 25 2007, 10:25
|
Участник

Группа: Свой
Сообщений: 54
Регистрация: 25-11-04
Из: Тула
Пользователь №: 1 228

|
Как известно в С++ можно получить адрес функции члена только конкретного класса, что не затрудняет реализовать обмен событиями между объектами через callback. Обсуждений этой темы было уже много, повторяться не буду: http://www.rsdn.ru/article/cpp/fastdelegate.xmlhttp://forum.developing.ru/showthread.php?p=12952#post12952http://alenacpp.blogspot.com/http://www.newty.de/fpt/index.htmlhttp://dobrokot.nm.ru/cpp/CppMethodsCallback.htmlИз специфики встраиваемых вытикают следующие ограничения: мин. потребление памяти, минимальное время вызова, использование кучи не жалательно, переносимость. Я лично остановился на варианте интерфейсов, плюсы и минусы: + прозрачная реализация в стиле ООП + для вызова храним только один указатель, для 32бит проц. соответственно 4 байта + не использем кучу + можно объеденить однотипные события в один интерфейс (экономим память) - нужна потдержка множественного наследования в компиляторе - дополнительные расходы на размер кода при множественном наследовании (но вполне допустимые) - для каждого типа/группы событий приходиться описывать класс интерфейса - обработка событий от разных объектов и классов получается в одном методе, приходиться использовать switch (если это кретично, то можно обрабатывать события во вложенном классе слушателе который объявлен как друг) Выглядет это примерно так: //Интерфейс события мыши class IMouseEvent { private: protected: public: virtual void OnMouseDown(void); virtual void OnMouseUp(void); virtual void OnClick(void); }; //Интерфейс события клавиатуры class IKeyEvent { private: protected: public: virtual void OnKeyDown(void); virtual void OnKeyUp(void); virtual void OnKeyPress(void); }; //Базовый класс class TControl { private: protected: public: IMouseEvent* OnMouseEvent; IKeyEvent* OnKeyEvent; }; //Окно class TWindow: public TControl { private: protected: public: }; //Конкретное окно, добавлены инетерфейсы для обработки события class TConcreteWindow: public IMouseEvent, public IKeyEvent, public TForm{ private: protected: public: void OnClick(void); virtual void OnKeyPress(void); };
|
|
|
|
|
Oct 25 2007, 13:16
|
Участник

Группа: Свой
Сообщений: 54
Регистрация: 25-11-04
Из: Тула
Пользователь №: 1 228

|
ну да это не вопрос, я предлагую обсудить возможные реализации. ARM... я сейчас для армов пишу.
|
|
|
|
|
Oct 26 2007, 06:14
|
Участник

Группа: Новичок
Сообщений: 15
Регистрация: 28-08-07
Пользователь №: 30 105

|
Цитата(HEX @ Oct 25 2007, 14:25)  Как известно в С++ можно получить адрес функции члена только конкретного класса, что не затрудняет реализовать обмен событиями между объектами через callback. Захотел сделать работу с периферией посредством классов. Но возникло два вопроса: как написать один код для каждого типа периферии, но чтоб он работал независимо от ее количества (к примеру UART0, UART1..) и как потом прерывания обрабатывать. Ответ был найден в параметризации шаблона класса базовым адресом в памяти. что-то вроде template<unsigned Adr> class CUart {..}; Соответственно в нем уже работать только по смещению. Но тут возник интересный ньюанс: а как делать обработчик прерывания? Ведь его адрес надо записать в контроллер? Сделал так: все наследуются от одного базового сласса с виртуальной функцией Isr. В конструкторе все экземпляры регистрируются в глобальном массиве. Для каждого класса (читай номера устройства) делается статическая функция, которая и регистрируется в контроллере прерываний. А уже она по своему вызову выбирает из массива адрес соответствующего ей экзепляра и дергает его Isr. Так к чему все это? Казалось бы работает, и не надо трогать.. Но нет! Ведь можно же еще уменьшить текст кода! А именно: сделать эту статическую функцию параметризируемой номером периферии и записать всего один раз template<unsigned N> void IsrExe(){ Array[N]->Isr();} Так вот мой Keil Arm не хочет адрес так описанной функции помещать в котроллер, а под MS VC проверяю - все в порядке. Так что речь, пока, к сожалению, можно вести не о том, как хотелось бы, а о том, что позволяет выбранный инструментарий..
|
|
|
|
|
Oct 26 2007, 06:26
|
Бывалый
    
Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615

|
Цитата(Shkn @ Oct 26 2007, 10:14)  Захотел сделать работу с периферией посредством классов. Но возникло два вопроса: как написать один код для каждого типа периферии, но чтоб он работал независимо от ее количества (к примеру UART0, UART1..) и как потом прерывания обрабатывать. Ответ был найден в параметризации шаблона класса базовым адресом в памяти. что-то вроде template<unsigned Adr> class CUart {..}; Это логично. Цитата(Shkn @ Oct 26 2007, 10:14)  Но тут возник интересный ньюанс: а как делать обработчик прерывания? Ведь его адрес надо записать в контроллер? Сделал так: все наследуются от одного базового сласса с виртуальной функцией Isr. В конструкторе все экземпляры регистрируются в глобальном массиве. Для каждого класса (читай номера устройства) делается статическая функция, которая и регистрируется в контроллере прерываний. А уже она по своему вызову выбирает из массива адрес соответствующего ей экзепляра и дергает его Isr.
Так к чему все это? Казалось бы работает, и не надо трогать.. Но нет! Ведь можно же еще уменьшить текст кода! А именно: сделать эту статическую функцию параметризируемой номером периферии и записать всего один раз template<unsigned N> void IsrExe(){ Array[N]->Isr();} Так вот мой Keil Arm не хочет адрес так описанной функции помещать в котроллер, а под MS VC проверяю - все в порядке. Цитата(Shkn @ Oct 26 2007, 10:14)  Так что речь, пока, к сожалению, можно вести не о том, как хотелось бы, а о том, что позволяет выбранный инструментарий.. Добавлю, и желательно знать глюки и фичи используемого компилятора.
|
|
|
|
|
Oct 26 2007, 07:37
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
Цитата(Shkn @ Oct 26 2007, 12:14)  template<unsigned Adr> class CUart {..}; Или я чёта не понимаю или это оверхед по коду экономящий по одному слову RAM-a на экземпляр...
|
|
|
|
|
Oct 26 2007, 09:12
|

Участник

Группа: Участник
Сообщений: 49
Регистрация: 3-02-05
Пользователь №: 2 390

|
Цитата(Alex03 @ Oct 26 2007, 11:37)  Или я чёта не понимаю или это оверхед по коду экономящий по одному слову RAM-a на экземпляр... Следует обратить внимание на фразу "что-то вроде". Такая обертка используется для определения класса каждого регистра. Код template <unsigned A> class CRxBufReg{ public: CBitsRO <A, 0, 8> Data; CMixRegRO_Macro; }; Внутри класса устройства периферии определяется через typedef Код typedef CRxBufReg <ECurBaseAdr + 0x00> CRxBufReg_t; соответсвенно, базовый адрес хранит сам класс устройства Код template<unsigned N> class CUartDevice : public IUartDeviceBase { ... enum {ECurBaseAdr = ERegBaseAdr + N*ERegStepAdr}; }; ну и как все это выглядит в использовании: Код template<unsigned N> BYTE CUartDevice<N>::Take() { CRxBufReg_t RxBufReg; BYTE Ret = RxBufReg; return Ret; };
|
|
|
|
|
Oct 29 2007, 08:10
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
Вот я и не понимаю зачем для 3-х одинаковых UART-ов иметь в коде по три набора функций. для той же Код template<unsigned N> BYTE CUartDevice<N>::Take() будет три её реализации отличающихся одним числом - адресом регистра. Ну и ИМХО применение шаблонов тут ведёт только к усложнению понимания кода. Мож я чего не вижу? Просвятите?
|
|
|
|
|
Oct 29 2007, 08:28
|

Участник

Группа: Участник
Сообщений: 49
Регистрация: 3-02-05
Пользователь №: 2 390

|
Цитата(Alex03 @ Oct 29 2007, 12:10)  Вот я и не понимаю зачем для 3-х одинаковых UART-ов иметь в коде по три набора функций. для той же Код template<unsigned N> BYTE CUartDevice<N>::Take() будет три её реализации отличающихся одним числом - адресом регистра. А какая альтернатива? Делать switch внутри функции? Вычислять адрес во время исполнения? И еще стоит отметить, что шаблоны превращаются в код только если их вызвать явно. Т.е. если один из Uart-ов, к примеру, не используется, то кода для него и не сгенерируется. Это, кстати, является весьма трудной задачей для Keil. Он может просто не заметить такого вызова, а потом сиди-ищи, куда код делся. А еще он не любит прерывания на параметризируемые классы в IDE ставить, хотя по asm-коду ходит Цитата(Alex03 @ Oct 29 2007, 12:10)  Ну и ИМХО применение шаблонов тут ведёт только к усложнению понимания кода. Мож я чего не вижу? Просвятите? Пример использования: CUartDevice<0> _Uart; _Uart.Start(); А все остальное пользователя уже и не касается.
|
|
|
|
|
Oct 29 2007, 09:25
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
Цитата(grau @ Oct 29 2007, 13:28)  А какая альтернатива? Делать switch внутри функции? Вычислять адрес во время исполнения? Зачем свич? Например храним в экземпляре класса базовый адрес, вычисления не такие уж громоздкие, а учитывая как ARM грузит константы в регистры и оверхеда на вычисления может не понадобиться.  А код переделываем в такой: CUartDevice _Uart(0); _Uart.Start(); И также все остальное пользователя уже и не касается. Впрочем спорить не собираюсь, думал мож я чего не вижу/замечаю/понимаю.
|
|
|
|
|
Nov 30 2007, 10:48
|
Частый гость
 
Группа: Свой
Сообщений: 120
Регистрация: 4-01-06
Из: Москва
Пользователь №: 12 837

|
Читал архивы и наткнулся... Стало интересно, прочитал, кое - что взял на вооружение. Но непонятен один момент - как устроен класс "CBitsRO", а конкретно каким образом он осуществляет доступ к регистру с адресом, определяемым параметром шаблона? Цитата template <unsigned A> class CRxBufReg{ public: CBitsRO <A, 0, 8> Data; CMixRegRO_Macro; };
--------------------
То, что неясно, следует выяснить. То, что трудно творить, следует делать с великой настойчивостью. Конфуций
|
|
|
|
|
Feb 17 2008, 13:09
|
Группа: Участник
Сообщений: 14
Регистрация: 10-11-07
Из: Харьков
Пользователь №: 32 220

|
Цитата(scout @ Nov 30 2007, 13:48)  Читал архивы и наткнулся... Стало интересно, прочитал, кое - что взял на вооружение. Но непонятен один момент - как устроен класс "CBitsRO", а конкретно каким образом он осуществляет доступ к регистру с адресом, определяемым параметром шаблона? Меня тоже заинтересовала эта тема! Уважаемый grau, нельзя ли поподробней? Вот пишу (IAR AVR): Код typedef uint8_t volatile __tiny IO_REG;
template <IO_REG &r> void f(uint8_t mask) { r |= mask; }
int main() { f<PORTB>(0x77); return 0; } На это ругается компилятор: Internal Error: [any]: Unexpected exception Что я неправильно написал?
Сообщение отредактировал landrey - Feb 17 2008, 13:11
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|