Jump to content

    

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, но это для меня приемлемо.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
А зачем нужен параметр шаблона activestate, если он нигде не используется?

 

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

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

 

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

 

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

Share this post


Link to post
Share on other sites
Пробовал так:

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;
}

Share this post


Link to post
Share on other sites
Я делал так. это не совсем по теме, но...:

 

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

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)

 

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

Share this post


Link to post
Share on other sites
Да, это немножко другое. Выбор из пары возможных вариантов.
Можно и из бОльшего количества:
    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;

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

Share this post


Link to post
Share on other sites

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

 

template<>
class TUart<UART0> : public TBaseUart

 

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

class TUart0 : public TBaseUart

 

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

Share this post


Link to post
Share on other sites
Это я к тому, что тернарный оператор короче if в записи.

 

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

 

 

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

 

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

 

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

Share this post


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

 

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

 

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

Share this post


Link to post
Share on other sites

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

Share this post


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

 

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

 

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

 

Я же написал: "вариант с шаблонами будет компилироваться при наличии только одного 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.

Share this post


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

 

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

 

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

 

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

Share this post


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

 

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

 

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

 

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

Share this post


Link to post
Share on other sites
Так что верну вам упрёк - внимательнее (вдумчивее) надо читать.

 

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

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

Share this post


Link to post
Share on other sites
1. Жизненная позиция, основанная на принципе "все вокруг недоделанные идиоты, а я самый крутой", не есть правильная.

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

 

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

 

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

 

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

 

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now