HEX 0 25 октября, 2007 Опубликовано 25 октября, 2007 · Жалоба Как известно в С++ можно получить адрес функции члена только конкретного класса, что не затрудняет реализовать обмен событиями между объектами через callback. Обсуждений этой темы было уже много, повторяться не буду: http://www.rsdn.ru/article/cpp/fastdelegate.xml http://forum.developing.ru/showthread.php?p=12952#post12952 http://alenacpp.blogspot.com/ http://www.newty.de/fpt/index.html http://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); }; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DASM 0 25 октября, 2007 Опубликовано 25 октября, 2007 · Жалоба Замечательно. Я так понял вопроса в посте не содержится. Это хорошо. А при чем тут ARM ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
HEX 0 25 октября, 2007 Опубликовано 25 октября, 2007 · Жалоба ну да это не вопрос, я предлагую обсудить возможные реализации. ARM... я сейчас для армов пишу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tahoe 0 25 октября, 2007 Опубликовано 25 октября, 2007 · Жалоба ну да это не вопрос, я предлагую обсудить возможные реализации. ARM... я сейчас для армов пишу. Ну тогда можно просто взять, например, Атмеловский USB Framework и посмотреть, как там сделаны коллбэки на чистых Сях. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
defunct 0 25 октября, 2007 Опубликовано 25 октября, 2007 · Жалоба Дурное дело нехитрое - вызвать функцию по указателю. Что тут обсуждать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexander55 0 26 октября, 2007 Опубликовано 26 октября, 2007 · Жалоба class TConcreteWindow: public IMouseEvent, public IKeyEvent, public TForm{ ... }; Этот вариант прекрасно будет работать в IAR в eec++. Проверено. PS. Что накосячили БГ и компания лучше обсудить в форумах по VC++ и C++Builder, а вопросы по дальнейщей стандартизвции C++ лучше направлять Герберту Шилдту (если нужны явки и пароли, я Вам помогу). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
shkn 0 26 октября, 2007 Опубликовано 26 октября, 2007 · Жалоба Как известно в С++ можно получить адрес функции члена только конкретного класса, что не затрудняет реализовать обмен событиями между объектами через callback. Захотел сделать работу с периферией посредством классов. Но возникло два вопроса: как написать один код для каждого типа периферии, но чтоб он работал независимо от ее количества (к примеру UART0, UART1..) и как потом прерывания обрабатывать. Ответ был найден в параметризации шаблона класса базовым адресом в памяти. что-то вроде template<unsigned Adr> class CUart {..}; Соответственно в нем уже работать только по смещению. Но тут возник интересный ньюанс: а как делать обработчик прерывания? Ведь его адрес надо записать в контроллер? Сделал так: все наследуются от одного базового сласса с виртуальной функцией Isr. В конструкторе все экземпляры регистрируются в глобальном массиве. Для каждого класса (читай номера устройства) делается статическая функция, которая и регистрируется в контроллере прерываний. А уже она по своему вызову выбирает из массива адрес соответствующего ей экзепляра и дергает его Isr. Так к чему все это? Казалось бы работает, и не надо трогать.. Но нет! Ведь можно же еще уменьшить текст кода! А именно: сделать эту статическую функцию параметризируемой номером периферии и записать всего один раз template<unsigned N> void IsrExe(){ Array[N]->Isr();} Так вот мой Keil Arm не хочет адрес так описанной функции помещать в котроллер, а под MS VC проверяю - все в порядке. Так что речь, пока, к сожалению, можно вести не о том, как хотелось бы, а о том, что позволяет выбранный инструментарий.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexander55 0 26 октября, 2007 Опубликовано 26 октября, 2007 · Жалоба Захотел сделать работу с периферией посредством классов. Но возникло два вопроса: как написать один код для каждого типа периферии, но чтоб он работал независимо от ее количества (к примеру UART0, UART1..) и как потом прерывания обрабатывать. Ответ был найден в параметризации шаблона класса базовым адресом в памяти. что-то вроде template<unsigned Adr> class CUart {..}; Это логично. Но тут возник интересный ньюанс: а как делать обработчик прерывания? Ведь его адрес надо записать в контроллер? Сделал так: все наследуются от одного базового сласса с виртуальной функцией Isr. В конструкторе все экземпляры регистрируются в глобальном массиве. Для каждого класса (читай номера устройства) делается статическая функция, которая и регистрируется в контроллере прерываний. А уже она по своему вызову выбирает из массива адрес соответствующего ей экзепляра и дергает его Isr. Так к чему все это? Казалось бы работает, и не надо трогать.. Но нет! Ведь можно же еще уменьшить текст кода! А именно: сделать эту статическую функцию параметризируемой номером периферии и записать всего один раз template<unsigned N> void IsrExe(){ Array[N]->Isr();} Так вот мой Keil Arm не хочет адрес так описанной функции помещать в котроллер, а под MS VC проверяю - все в порядке. :a14: Так что речь, пока, к сожалению, можно вести не о том, как хотелось бы, а о том, что позволяет выбранный инструментарий.. Добавлю, и желательно знать глюки и фичи используемого компилятора. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alex03 0 26 октября, 2007 Опубликовано 26 октября, 2007 · Жалоба template<unsigned Adr> class CUart {..}; Или я чёта не понимаю или это оверхед по коду экономящий по одному слову RAM-a на экземпляр... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
grau 0 26 октября, 2007 Опубликовано 26 октября, 2007 · Жалоба Или я чёта не понимаю или это оверхед по коду экономящий по одному слову 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; }; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alex03 0 29 октября, 2007 Опубликовано 29 октября, 2007 · Жалоба Вот я и не понимаю зачем для 3-х одинаковых UART-ов иметь в коде по три набора функций. для той же template<unsigned N> BYTE CUartDevice<N>::Take() будет три её реализации отличающихся одним числом - адресом регистра. Ну и ИМХО применение шаблонов тут ведёт только к усложнению понимания кода. Мож я чего не вижу? Просвятите? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
grau 0 29 октября, 2007 Опубликовано 29 октября, 2007 · Жалоба Вот я и не понимаю зачем для 3-х одинаковых UART-ов иметь в коде по три набора функций. для той же template<unsigned N> BYTE CUartDevice<N>::Take() будет три её реализации отличающихся одним числом - адресом регистра. А какая альтернатива? Делать switch внутри функции? Вычислять адрес во время исполнения? И еще стоит отметить, что шаблоны превращаются в код только если их вызвать явно. Т.е. если один из Uart-ов, к примеру, не используется, то кода для него и не сгенерируется. Это, кстати, является весьма трудной задачей для Keil. Он может просто не заметить такого вызова, а потом сиди-ищи, куда код делся. А еще он не любит прерывания на параметризируемые классы в IDE ставить, хотя по asm-коду ходит Ну и ИМХО применение шаблонов тут ведёт только к усложнению понимания кода. Мож я чего не вижу? Просвятите? Пример использования: CUartDevice<0> _Uart; _Uart.Start(); А все остальное пользователя уже и не касается. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alex03 0 29 октября, 2007 Опубликовано 29 октября, 2007 · Жалоба А какая альтернатива? Делать switch внутри функции? Вычислять адрес во время исполнения? Зачем свич? Например храним в экземпляре класса базовый адрес, вычисления не такие уж громоздкие, а учитывая как ARM грузит константы в регистры и оверхеда на вычисления может не понадобиться. :) А код переделываем в такой: CUartDevice _Uart(0); _Uart.Start(); И также все остальное пользователя уже и не касается. Впрочем спорить не собираюсь, думал мож я чего не вижу/замечаю/понимаю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
roman555 0 30 ноября, 2007 Опубликовано 30 ноября, 2007 · Жалоба Читал архивы и наткнулся... Стало интересно, прочитал, кое - что взял на вооружение. Но непонятен один момент - как устроен класс "CBitsRO", а конкретно каким образом он осуществляет доступ к регистру с адресом, определяемым параметром шаблона? template <unsigned A> class CRxBufReg{ public: CBitsRO <A, 0, 8> Data; CMixRegRO_Macro; }; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
landrey 0 17 февраля, 2008 Опубликовано 17 февраля, 2008 (изменено) · Жалоба Читал архивы и наткнулся... Стало интересно, прочитал, кое - что взял на вооружение. Но непонятен один момент - как устроен класс "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 Что я неправильно написал? Изменено 17 февраля, 2008 пользователем landrey Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться