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

C++ и макросы имени Аскольда Волкова.

Тема не совсем про scmRTOS, но тут много спецов по плюсам:)

 

Сделал такую штуку:

class BasePin
{
    public:
        virtual void On() = 0;
        virtual void Off() = 0;
        virtual void Cpl() = 0;
...
};

Это базовый абстрактный класс. Нужен, чтоб можно было передавать ссылку на любую ножку куда угодно. Например, класс TDAC(spi& spiRef, BasePin& CS), конструктору передаётся ссылка на spi и ссылка на ножку чипселекта.

 

Дальше начинаю городить шаблоны:

template<int port, int pin, char activestate = 'H'> class Pin;

template<int pin>
class Pin<1, pin>: public BasePin
{
    public:
        virtual void On() { P1OUT |= 1<<pin; }\
...
};

template<int pin>
class Pin<1, pin, 'L'>: public BasePin
{
    public:
        virtual void On(){ P1OUT &= ~(1<<pin); }
...
};

 

И так 5 раз (для портов 1-5). Как-то коряво...

 

Пробовал так:

template<int port, int pin, char activestate = 'H'>
class Pin: public BasePin
{
    public:
        virtual void On() {
            if (port == 1) P1OUT |= 1<<pin;
            if (port == 2) P2OUT |= 1<<pin;
            if (port == 3) P3OUT |= 1<<pin;
            if (port == 4) P4OUT |= 1<<pin;
            if (port == 5) P5OUT |= 1<<pin;
        }
...
};

 

Так вроде поменьше писанины, но тоже корявенько.

 

Теперь внимание, вопрос:)

Есть ли какая-нибудь возможность получить вот такое:

template<int port, int pin, char activestate = 'H'>
class Pin: public BasePin
{
    public:
        virtual void On() {P##portOUT |= 1<<pin; }
...
};

 

То есть, хочу нечто вроде макроподстановки. Вроде где-то что-то встречал подобное, но никак не вспомню, куда копать.

 

 

ЗЫ. А работает вроде хорошо. То есть,

 

Pin<1, 2, 'L'> PIN12;
#define PIN_12 1, 2, L
Pin<2, 3> PIN23;
#define PIN_23 2, 3, H
...
    PIN12.On();
    on(PIN_12);
    PIN23.On();
    on(PIN_23);

 

компилится в

    1808:    e2 c2 21 00     bic.b    #4,    &0x0021  ;r2 As==10
    180c:    e2 c2 21 00     bic.b    #4,    &0x0021  ;r2 As==10
    1810:    f2 d2 29 00     bis.b    #8,    &0x0029  ;r2 As==11
    1814:    f2 d2 29 00     bis.b    #8,    &0x0029  ;r2 As==11

 

Накладные расходы - vtable+процедуры на каждую созданную ножку. За это я получаю возможность передавать ссылку на ножку. Я давно этого хотел.

 

При обращении по ссылке (в TDAC) вызовы уже из vtable, но это для меня приемлемо.

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


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

А зачем нужен параметр шаблона activestate, если он нигде не используется?

 

Вот же он ("L"):

template<int pin>
class Pin<1, pin, 'L'>: public BasePin

 

Он же: Pin<1, 2, 'L'> PIN12;

 

Суть в том, что On() переводит ногу в состояние activestate ("L" - низкий уровень, "H" - высокий). Так сделано в макросах Волкова, я к этому привык.

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


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

Пробовал так:

template<int port, int pin, char activestate = 'H'>
class Pin: public BasePin
{
    public:
        virtual void On() {
            if (port == 1) P1OUT |= 1<<pin;
            if (port == 2) P2OUT |= 1<<pin;
            if (port == 3) P3OUT |= 1<<pin;
            if (port == 4) P4OUT |= 1<<pin;
            if (port == 5) P5OUT |= 1<<pin;
        }
...
};

 

Так вроде поменьше писанины, но тоже корявенько.

Я делал так. это не совсем по теме, но...:
#ifndef USCIA_H__
#define USCIA_H__
#include    <io.h>

#ifndef USCIB_H__
enum usci_module_t { USCI0, USCI1 };
#endif


template <usci_module_t const module>
class uscia_t
{
public:
    class usca_ctl0_t    /* USCI Ax Control Register 0 */
    {
    public:
        uint8_t operator=(uint8_t value) { module ? UCA1CTL0 = value : UCA0CTL0 = value; return value; }
        void operator|=(uint8_t value) { module ? UCA1CTL0 |= value : UCA0CTL0 |= value; }
        void operator&=(uint8_t value) { module ? UCA1CTL0 &= value : UCA0CTL0 &= value; }
        operator uint8_t() { return module ? UCA1CTL0 : UCA0CTL0; }
    } static CTL0;
...
// pins
    class txd_bit
    {
    public:
        operator uint8_t() { return module ? (1 << 6) : (1 << 4); }
    }  static TXD_BIT;

    class rxd_bit
    {
    public:
        operator uint8_t() { return module ? (1 << 7) : (1 << 5); }
    }  static RXD_BIT;
};

template <usci_module_t module>
class uart_t
{
    typedef uscia_t<module> UCA;
public:
    static INLINE inline void init(uint32_t const divider);
....
};

template <usci_module_t module>
void uart_t<module>::init(uint32_t const divider)
{
    UCA::CTL1 |= (1  * UCSWRST);
    UCA::CTL1 = 0
        |(0 * UCRXEIE)|(0 * UCBRKIE)|(0 * UCTXADDR)
        |(1 * UCSWRST)
        |(1 * UCSSEL1)|(0 * UCSSEL0)
      ;
    UCA::CTL0 = (0 * UCPEN)|(0 * UCMSB)|(0 * UC7BIT)|(0 * UCSPB)|(0 * UCMODE1)|(0 * UCMODE0)|(0 * UCSYNC);

    UCA::BR0 = (divider / 16) & 0xFF;
    UCA::BR1 = (divider / 16) >> 8;
    UCA::MCTL = ((divider - (divider / 16) * 16) * UCBRF0)
        |(0 * UCBRS0)|(1 * UCOS16);
    UCA::CTL1 &= ~(1  * UCSWRST);
    P3SEL |= UCA::RXD_BIT | UCA::TXD_BIT;
    UCA::IFG |= UCA::TXIFG;
    UCA::IE |= UCA::RXIE;
}

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


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

Я делал так. это не совсем по теме, но...:

 

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

enum uart_num_t {UART0, UART1};

class TBaseUart
{
private:
    static const int RxSize = 32;
    static const int TxSize = 32;
protected:
    bool tx_pending;
    RingBuf<RxSize> RxBuf;
    RingBuf<TxSize> TxBuf;
    virtual void write_tx_reg(char ch) = 0;
    virtual void disable_tx_interrupt() = 0;
    virtual void enable_tx_interrupt() = 0;
public:
    TBaseUart() : RxBuf(), TxBuf(), tx_pending(false) {}
    char getch(void) { return RxBuf.get(); }
    bool keypressed(void) { return RxBuf.count(); }
//    ... весь остальной полезный фарш
};

template<uart_num_t uart_num> class TUart;

template<>
class TUart<UART0> : public TBaseUart
{
private:
    void hw_init(uint32_t baudrate);
protected:
    virtual void write_tx_reg(char ch) { TXBUF0 = ch; }
    virtual void disable_tx_interrupt() { IE1 &= ~UTXIE0; }
    virtual void enable_tx_interrupt() { IE1 |= UTXIE0; }
public:
    TUart(uint32_t baudrate) : TBaseUart() { hw_init(baudrate); }
};

template<>
class TUart<UART1> : public TBaseUart
...

 

В плюсе - оба UARTа имеют тип TBaseUart, весь фарш типа gets, puts, << и проч. - реализован один раз (в TBaseUart). В минусе - небольшие накладные расходы на вызов виртуальных фанкций. По моим наблюдениям они невелики:)

 

ЗЫ. Пока решил проблему вот так:

#define DECLARE_PORT(portN)                                                    \
template<int pin>                                                            \
class Pin<portN, pin>: public BasePin                                        \
{                                                                            \
    public:                                                                 \
        virtual void On() { P##portN##OUT |= 1<<pin; }                        \
...
};                                                                            \
                                                                            \
template<int pin>                                                            \
class Pin<portN, pin, 'L'>: public BasePin                                    \
{                                                                            \
    public:                                                                    \
        virtual void On(){ P##portN##OUT &= ~(1<<pin); }                    \
...
};                                                                            \

DECLARE_PORT(1)
DECLARE_PORT(2)
DECLARE_PORT(3)
DECLARE_PORT(4)
DECLARE_PORT(5)

 

Всё же без макросов пока никуда:)

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


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

Да, это немножко другое. Выбор из пары возможных вариантов.
Можно и из бОльшего количества:
    class dma_ctl_t    /* DMA channel x control */
    {
    public:
        uint16_t operator=(uint16_t value) 
                { 
                      channel == DMA0 ? DMA0CTL = value
                    : channel == DMA1 ? DMA1CTL = value
                    : DMA2CTL = value; 
                    return value; 
                }

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

    static uint8_t const RXIFG = module == USCI0 ? UCB0RXIFG : UCB1RXIFG;

Вы, кстати, зря избегаете виртуализации. С ней то же самое можно сделать гораздо изящнее:
Есть такой недостаток. Буду работать над собой.

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


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

А в чем навар в объявлении

 

template<>
class TUart<UART0> : public TBaseUart

 

по сравнению с

class TUart0 : public TBaseUart

 

Вы же все равно в каждом шаблонном классе все руками прописываете?

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


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

Это я к тому, что тернарный оператор короче if в записи.

 

А, понял. Но при пяти портах уже и то и то выглядит громоздко.

 

 

А в чем навар в объявлении

 

Ну я урезАл пример, и перестарался:) Но даже в этом, минимальном примере, вариант с шаблонами будет компилироваться при наличии только одного UART, а вариант с прямым прописыванием - нет.

 

А если применить подход Сергея из поста номер 4, то можно обойтись всего одной реализацией на все UART-ы. Но тут опять же, при возрастании числа UART-ов изящность решения снижается.

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


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

Ну я урезАл пример, и перестарался:) Но даже в этом, минимальном примере, вариант с шаблонами будет компилироваться при наличии только одного UART, а вариант с прямым прописыванием - нет.

 

Что-то вы любезный какими-то загадками все время говорите. Вам надо какое-то псевдоизящество, или эффективная работа с периферией?

 

Почему не будет компилироваться вариант с прямым прописыванием? С чего-бы это?

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


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

virtual void On() {
            if (port == 1) P1OUT |= 1<<pin;
            if (port == 2) P2OUT |= 1<<pin;
            if (port == 3) P3OUT |= 1<<pin;
            if (port == 4) P4OUT |= 1<<pin;
            if (port == 5) P5OUT |= 1<<pin;
        }

5 ифов подряд - по-моему, коряво...

Причём, это ведь для каждой операции?

 

В mspgcc есть iostructures.h, там порты объявлены в виде структур.

Тогда можно просто подставить адрес нужного порта, а дальше действовать в манере

#define SPI         port1

#define RST_PIN     pin2
#define DI_PIN      pin3    // DI - вход мк, выход АЦП DO
#define RDY_PIN     pin5
#define CLK_PIN     pin6
#define DO_PIN      pin7    // DO - выход со стороны мк, вход АЦП DI

#define CLR_SCLK    SPI.out.CLK_PIN = 0
#define SET_SCLK    SPI.out.CLK_PIN = 1

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


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

Что-то вы любезный какими-то загадками все время говорите. Вам надо какое-то псевдоизящество, или эффективная работа с периферией?

 

Почему не будет компилироваться вариант с прямым прописыванием? С чего-бы это?

 

Если вам что-то непонятно, просто перечитайте. Снова не поймёте - переспросите. К чему этот надрыв? :)

 

Я же написал: "вариант с шаблонами будет компилироваться при наличии только одного UART, а вариант с прямым прописыванием - нет". Вы это отцитировали. Значит, прочитали? И не поняли? Хорошо, я переформулирую: "при наличии только одного UART" = "при отсутствии второго UART". В системе. Так яснее? Нет? Хорошо, поясню на примере.

 

class TUart1 : public TBaseUart
{
protected:
     virtual void write_tx_reg(char ch) { TXBUF0 = ch; }
...
};

class TUart2 : public TBaseUart
{
protected:
     virtual void write_tx_reg(char ch) { TXBUF1 = ch; }
};

 

Если у проца нет второго UART, то на последней строчке компилятор скажет, что не знает, что такое TXBUF1.

 

В случае с шаблонами - не скажет, пока вы не попытаетесь создать экземпляр TUart<UART2>.

 

5 ифов подряд - по-моему, коряво...

Причём, это ведь для каждой операции?

 

Да не, это всё выкидывается компилятором, ибо сравнение константы с константой. Остаётся один bis.

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


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

Если вам что-то непонятно, просто перечитайте. Снова не поймёте - переспросите. К чему этот надрыв? :)

 

Я же написал: "вариант с шаблонами будет компилироваться при наличии только одного UART, а вариант с прямым прописыванием - нет". Вы это отцитировали. Значит, прочитали? И не поняли? Хорошо, я переформулирую: "при наличии только одного UART" = "при отсутствии второго UART". В системе. Так яснее? Нет?

 

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

 

По поводу "при наличии только одного UART" = "при отсутствии второго UART" - это тоже пример того, что вы хотите нам сказать и что за этим вы сами подразумеваете. Четче надо свои мысли излагать.

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


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

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

 

Ой да ладно. Тот мой пост (с кусками кода) был адресован Сергею Борщу, и я уверен, что он там всё понял. Для иллюстрации моей мысли кода там достаточно. Если вы не догадались - сочувствую.

 

По поводу "при наличии только одного UART" = "при отсутствии второго UART" - это тоже пример того, что вы хотите нам сказать и что за этим вы сами подразумеваете. Четче надо свои мысли излагать.

 

Хм. Приведён код для двух UART. Разве в этом случае фраза "наличие только одного UART" не тождественна фразе "отсутствие второго UART"? Так что верну вам упрёк - внимательнее (вдумчивее) надо читать.

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


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

Так что верну вам упрёк - внимательнее (вдумчивее) надо читать.

 

1. Жизненная позиция, основанная на принципе "все вокруг недоделанные идиоты, а я самый крутой", не есть правильная.

2. Вдумчивее читать то, чего не написано - это разгадывание ребусов. Дело в принципе тоже полезное, но, как мне сдается, наш форум не для этого создан.

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


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

1. Жизненная позиция, основанная на принципе "все вокруг недоделанные идиоты, а я самый крутой", не есть правильная.

2. Вдумчивее читать то, чего не написано - это разгадывание ребусов. Дело в принципе тоже полезное, но, как мне сдается, наш форум не для этого создан.

 

Интересная беседа получается:)

 

1. Каким образом из того, что вы лично что-то не поняли, следует вывод, что я всех считаю идиотами? И кто начал всю эту бодягу? Вы спокойно спросили про activestate, - я спокойно ответил. Вы спокойно спросили, в чём навар в использовании шаблонов по сравнению с явным прописыванием - я спокойно ответил. Вы не поняли ответа, и спокойствие исчезло из нашего диалога. Сразу я стал "любезный", стал "говорить загадками" и делать "псевдоизящество"... Не поняли - разозлились. Это, извините, ваши комплексы. Я тут не при чём.

 

2. Не всё, что вы не понимаете - ребус.

 

ЗЫ. Вы, кстати, испортили мне тему.

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


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

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

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

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

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

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

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

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

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

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