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

С++, обработчик прерывания как статическая ф-я класса.

Пытаюсь сделать следующим образом, но выдаются сообщения об ошибках.

 

h-файл:

class TUSART_Coding : public TUSART
{
    private:
        static OS_INTERRUPT void TXHandler(void); // 39 строка
        static OS_INTERRUPT void RXHandler(void); // 40 строка
...
};

 

cpp-файл:

OS_INTERRUPT interrupt(USART_RX_vect) TUSART_Coding::RXHandler(void)
{
    OS::TISRW_SS ISRW;
    Read_Next_Byte();
};

OS_INTERRUPT interrupt(USART_TX_vect) TUSART_Coding::TXHandler(void)
{
    OS::TISRW_SS ISRW;
    Write_Next_Byte();
};

 

39 error: expected unqualified-id before string constant

40 error: expected unqualified-id before string constant

 

В чём может быть дело?

Изменено пользователем n_bogoyavlensky

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


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

Скорее всего нет слова #include <scmRTOS.h> до объявления.

Да и не нужен этот атрибут (OS_INTERRUPT) в объявлении функции (в h-файле). Вот в определении (в cpp) - да, нужен.

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


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

Скорее всего нет слова #include <scmRTOS.h> до объявления.

 

В .h было.

В .cpp не было.

 

Да и не нужен этот атрибут (OS_INTERRUPT) в объявлении функции (в h-файле).

 

Убрал. Эти ошибки исчезли, но появились новые...

А что это за атрибут? Нашёл в исходниках, но пока не понял для чего он :(

 

Новые ошибки на код:

 

OS_INTERRUPT interrupt(USART_RX_vect) TUSART_Coding::RXHandler(void) // Строка №284
{
    OS::TISRW_SS ISRW;
    Read_Next_Byte();
};

OS_INTERRUPT interrupt(USART_TX_vect) TUSART_Coding::TXHandler(void) // Строка №297
{
    OS::TISRW_SS ISRW;
    Write_Next_Byte();
};

 

TUSART_Coding.cpp|284|error: expected constructor, destructor, or type conversion before '(' token

TUSART_Coding.cpp|297|error: expected constructor, destructor, or type conversion before '(' token

 

Что это?

 

Кстати, вот здесь вот OS_INTERRUPT есть в описании:

http://electronix.ru/forum/index.php?showt...st&p=511104

Изменено пользователем n_bogoyavlensky

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


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

В .h было.

В .cpp не было.

 

А .h включен в .cpp? :)

 

Убрал. Эти ошибки исчезли, но появились новые...

А что это за атрибут? Нашёл в исходниках, но пока не понял для чего он :(

 

Он содержит дополнительные атрибуты для функции-обработчика прерывания. Например, __arm для АРМов. У вас какой проц? Какой компилятор? И как выглядит объявление OS_INTERRUPT?

 

Что это?

такое чувство, что не хватает слова void:

OS_INTERRUPT interrupt(USART_TX_vect) void TUSART_Coding::TXHandler(void) // Строка №297

 

 

Кстати, вот здесь вот OS_INTERRUPT есть в описании:

http://electronix.ru/forum/index.php?showt...st&p=511104

 

Оно не мешает, просто там в нём нет нужды (имхо).

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


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

А .h включен в .cpp? :)

 

Конечно включен :)

 

Он содержит дополнительные атрибуты для функции-обработчика прерывания. Например, __arm для АРМов. У вас какой проц? Какой компилятор? И как выглядит объявление OS_INTERRUPT?

 

По поводу дополнительных атрибутов понятно уже. Хотелось бы узнать что за атрибуты и для чего конкретно :)

Процессор ATmega168.

Компилятор WinAVR20071221.

 

OS_Target.h:

# define    OS_INTERRUPT    extern "C" __attribute__((__signal__,__INTR_ATTRS))

 

\avr\interrupt.h:

#  define __INTR_ATTRS used, externally_visible

 

такое чувство, что не хватает слова void:

OS_INTERRUPT interrupt(USART_TX_vect) void TUSART_Coding::TXHandler(void) // Строка №297

 

С ним тоже самое :)

 

Оно не мешает, просто там в нём нет нужды (имхо).

 

Получается, что мешает, так как с ним присутствуют ошибки первого типа...

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


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

Процессор ATmega168.

Компилятор WinAVR20071221.

 

Он просто не знает слова interrupt :))))

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


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

Тааак... и как нам быть? :)

 

Я не знаю, как дать имя обработчику прерывания... Надо позвать Редчука, чтоб он сказал :)

 

Или так:

SIGNAL(SIG_UART_RECV)
{
    OS::TISRW_SS ISRW;
    Usart1.RXHandler();
}

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


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

Тааак... и как нам быть? :)
Он знает слово interrupt. Точнее interrupt - это макрос, и содержимое его вы можете легко найти внутри avr/interrupt.h. И то, во что этот макрос разворачивается, делает его несовместимыым с понятием "статическая функция класса". Короче:
.h:
ISR(USART_RXC_vect);
ISR(USART_UDRE_vect);

class uart_t
{
public:
    uart_t() {};
    ...
private:
    friend void USART_RXC_vect();
    friend void USART_UDRE_vect();
    void RXC_Handler();
    void UDRE_Handler();
    ...
}
.cpp:
inline void uart_t::RXC_Handler()
{
    ...
}

OS_INTERRUPT void USART_RXC_vect()
{
    OS::TISRW isr;
    UART.RXC_Handler();
}

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


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

interrupt - это макрос, и содержимое его вы можете легко найти внутри avr/interrupt.h.

 

А я что-то не нашёл... Есть только

define ISR_NOBLOCK    __attribute__((interrupt))

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


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

А я что-то не нашёл...
Ой-ё... С ISR() и SIGNAL() попутал. Откуда же оно появилось в коде у n_bogoyavlensky? Ага, кажется понял: тупой copy-paste из кода от mspgcc, без попытки изучить свой компилятор. В avr-gcc сделать обработчик прерывания статическим членом класса невозможно.

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


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

Я не знаю, как дать имя обработчику прерывания... Надо позвать Редчука, чтоб он сказал :)
А что толку? Всё равно ничего не получится. Там разговор шёл про патч - атрибуту signal дать как аргумент номер прерывания и позволить произвольные имена, но, насколько я понял, до "официальных" версий это так и не дошло.

 

Так что

В avr-gcc сделать обработчик прерывания статическим членом класса невозможно.
приходится так, как уже писалось - с "друзьями" (OS_INTERRUPT из avr-gcc порта scmRTOS)

 

OS_INTERRUPT void INT0_vect(); // имя INT0_vect и подобные - в точности те, что даются макросу ISR() !!!

class foo
{
    friend void INT0_vect();

...

private:
   inline void isr_handler();
};

foo f;

OS_INTERRUPT  // уже не обязательно, но и не мешает
void INT0_vect()
{
    f.isr_handler();
}

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


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

А что толку? Всё равно ничего не получится. Там разговор шёл про патч - атрибуту signal дать как аргумент номер прерывания и позволить произвольные имена, но, насколько я понял, до "официальных" версий это так и не дошло.

Да уж. Который раз убеждаюсь, что avr-gcc выделяется на фоне остальных gcc некоей особой "особостью" :)

 

Так что

приходится так, как уже писалось - с "друзьями" (OS_INTERRUPT из avr-gcc порта scmRTOS)

 

То есть, OS_INTERRUPT из avr-gcc позволяет если не дать обработчику прерывания своё имя, то хотя бы получить хоть какое-то его имя, чтобы можно его было объявить его friend?

Потому что я не вижу других отличий от

SIGNAL(SIG_UART_RECV)
{
     OS::TISRW_SS ISRW;
     Usart1.RXHandler();
}

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


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

То есть, OS_INTERRUPT из avr-gcc
Из avr-gcc - шного порта scmRTOS. Но это не существенно.

позволяет если не дать обработчику прерывания своё имя, то хотя бы получить хоть какое-то его имя, чтобы можно его было объявить его friend?

Потому что я не вижу других отличий от

SIGNAL(SIG_UART_RECV)
{
     OS::TISRW_SS ISRW;
     Usart1.RXHandler();
}

тот #define OS_INTERRUPT просто повторяет все те аттрибуты, которые даёт макрос SIGNAL() (и макрос ISR() по умолчанию), только в форме, которую можно дать префиксом к имени. Имя-то всё равно фиксировано и после подстановки этого SIG_UART_RECV будет превращено в какое-то __vector_XX

Отличия действительно чисто косметические, так как можно вообще так:

// foo.h
#include <avr/io.h>
#include <avr/interrupt.h>

SIGNAL(INT0_vect);
// примитивная наколка - после разворачивания SIGNAL это будет эквивалентно
//   extern "C" void INT0_vect(void) __attribute__ ((signal, __INTR_ATTRS));   void INT0_vect(void);
// второе объявление функции просто ничего не меняет

class foo_t
{
    friend void INT0_vect();
public:
    uint8_t get() { return tick; }
private:
    uint8_t tick;
    inline void isr_handler() { ++tick; }
};

// foo.cpp
#include "foo.h"
foo_t foo;

// а тут наконец-то определяем
SIGNAL(INT0_vect)
{
    foo.isr_handler();
}

 

Но мне такой вариант не очень понравился. Вопрос вкусовой.

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


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

Доброго времени суток! Позвольте вклиниться в разговор...

 

А что толку? Всё равно ничего не получится. Там разговор шёл про патч - атрибуту signal дать как аргумент номер прерывания и позволить произвольные имена, но, насколько я понял, до "официальных" версий это так и не дошло.

 

Так что

приходится так, как уже писалось - с "друзьями" (OS_INTERRUPT из avr-gcc порта scmRTOS) ...

 

Вчера назрел подобный вопрос, пришлось заняться "разборками". Как выяснилось, вопрос вполне решабельный, и после оперативно-разыскных мероприятий по всему инету есть что сказать. Начну по порядку.

 

1. C++ Interrupts

Using the gcc "asm" keyword simplifies defining interrupt methods in C++

classes. The asm keyword as it applies to function names is described in

5.37 of the gcc manual and is mentioned in the asm cookbook section of the

avr-libc user manual. It specifies the equivalent assembler name for the

target function name and its use allows the user to define his or her own

names for class interrupt methods.

 

2. Controlling Names Used in Assembler Code

You cannot use asm in this way in a function definition; but you can get the same effect by writing a declaration for the function before its definition and putting asm there, like this:

 

extern func () asm ("FUNC");

func (x, y)
     int x, y;
...

 

Изначальный макрос у меня "с пол пинка" не завелся, но после некоторого экспериментирования, пришел к такому коду:

// Timer.h
#include <avr/interrupt.h>
#define    OS_INTERRUPT    extern "C" __attribute__((__signal__,__INTR_ATTRS))

class Timer
{
public:
    Timer( ) { }
    ~Timer( ) { }

    void Dispatch( ) { }
    static void IRQHandler( ) asm( "__vector_10" ); // Или, не 10 ( взято "с потолка" ), в любом случае, меняя нумер можно
                                                                                 //  подставить куда угодно
};

 

// Timer.cpp
#include "Timer.h"

Timer timer;

//---------------------------------------------------------------
OS_INTERRUPT void Timer::IRQHandler(void)
{
    timer.Dispatch( );
}

 

Проверяем, что получилось...

$ nm Timer.o
00000150 t _GLOBAL__D_timer
00000138 t _GLOBAL__I_timer
000000d4 t _Z41__static_initialization_and_destruction_0ii
00000054 W _ZN5Timer8DispatchEv
00000000 W _ZN5TimerC1Ev
0000002a W _ZN5TimerD1Ev
0000003e a __SP_H__
0000003d a __SP_L__
0000003f a __SREG__
         U __do_clear_bss
         U __do_copy_data
         U __do_global_ctors
         U __do_global_dtors
00000000 a __tmp_reg__
0000007e T __vector_10       <===== Оно!
00000001 a __zero_reg__
00000000 B timer

Аха-а-а! Наш вектор экспортируется под "правильным" именем!

 

Теперь глянем на дизассемблированный листинг:

Disassembly of section .text:

00000000 <__vectors>:
   0:   1b c0           rjmp    .+54           ; 0x38 <__dtors_end>
   2:   3f c0           rjmp    .+126          ; 0x82 <__bad_interrupt>
   4:   3e c0           rjmp    .+124          ; 0x82 <__bad_interrupt>
   6:   3d c0           rjmp    .+122          ; 0x82 <__bad_interrupt>
   8:   3c c0           rjmp    .+120          ; 0x82 <__bad_interrupt>
   a:   3b c0           rjmp    .+118          ; 0x82 <__bad_interrupt>
   c:   3a c0           rjmp    .+116          ; 0x82 <__bad_interrupt>
   e:   39 c0           rjmp    .+114          ; 0x82 <__bad_interrupt>
  10:   38 c0           rjmp    .+112          ; 0x82 <__bad_interrupt>
  12:   37 c0           rjmp    .+110          ; 0x82 <__bad_interrupt>
  14:   76 c0           rjmp    .+236          ; 0x102 <__vector_10>         <=== Оно!
  16:   35 c0           rjmp    .+106          ; 0x82 <__bad_interrupt>
  18:   34 c0           rjmp    .+104          ; 0x82 <__bad_interrupt>
  1a:   33 c0           rjmp    .+102          ; 0x82 <__bad_interrupt>
  1c:   32 c0           rjmp    .+100          ; 0x82 <__bad_interrupt>
  1e:   31 c0           rjmp    .+98           ; 0x82 <__bad_interrupt>
  20:   30 c0           rjmp    .+96           ; 0x82 <__bad_interrupt>
  22:   2f c0           rjmp    .+94           ; 0x82 <__bad_interrupt>
  24:   2e c0           rjmp    .+92           ; 0x82 <__bad_interrupt>
  26:   2d c0           rjmp    .+90           ; 0x82 <__bad_interrupt>
  28:   2c c0           rjmp    .+88           ; 0x82 <__bad_interrupt>
  2a:   2b c0           rjmp    .+86           ; 0x82 <__bad_interrupt>
  2c:   2a c0           rjmp    .+84           ; 0x82 <__bad_interrupt>
  2e:   29 c0           rjmp    .+82           ; 0x82 <__bad_interrupt>
  30:   28 c0           rjmp    .+80           ; 0x82 <__bad_interrupt>
  32:   27 c0           rjmp    .+78           ; 0x82 <__bad_interrupt>

 

PS: Чтоб избежать лишних вопросов о версии gcc, отвечу сразу -- самосборная под линухом, версия 4.2.2. В контроллер не заливал, ограничился (пока) статическим анализом, т.ч. если не будет работать, отпишите, не сочтите за труд.

 

PPS: Попытавшись реализовать вариацию на тему стратегий от Александреску, обломался. Не так-то легко провернуть подобное в случае шаблонного класса. Если у кого-то есть идеи, как реализовать подобное в шаблонном классе, буду очень признателен за подобное. Вопрос интересует только в контексте полного отсутствия виртуальных методов! С виртуальными методами это тривиально...

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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