エッジコンピューティングの逆襲 特集

RTOS的に使えるがRTOSではない「QP」はMATLABの代替候補にもなり得る?リアルタイムOS列伝(22)(4/4 ページ)

» 2022年05月09日 07時00分 公開
[大原雄介MONOist]
前のページへ 1|2|3|4       

MBDと言えばMATLAB+Embedded Coderだが……

 では、QPを使うとプログラムはどんな具合になるか? という実例を一つ。簡単なところでLチカのサンプルコードが記事の最後に掲載したリスト1である(ヘッダコメントは省略)。ちょっと複雑だが、まぁこの程度なら読めなくはない。ただし、ここで呼んでいるBlinky_ctor()を含むコードは、リスト1に続くリスト2の通り(ヘッダコメントは省略)。

 見て頂くと分かるが、もう人間の可読性をあんまり考慮していないというか、結構読みづらいコードになっている。というのは、これはQMを使って生成したものであって、その意味でもQPを使うならMBDを利用すべきなのである。逆に言えば、従来MBDを使ってコードを開発というと、MathWorksのMATLABとEmbedded Coderを組み合わせるなんて話になりがちだが決して安価ではない。QPは、QMと組み合わせることで、このMATLAB+Embedded Coderの良い代替になり得ると考えればよい。

 そういう意味では「普通の」RTOSを探しているユーザーにはまるでお薦めできないが、開発にMBDを考慮しているようなところでは、一度試してみる価値はあるのではないかと思う。QPと全ツールキットをまとめた「QP-bundle」がWindows/Linux/macOS用にそれぞれ用意されており、何しろオープンソースだから評価を始める際のコストはゼロ円で済む。あるいは、MBDの勉強用にもQPは向いているかもしれない。

#include "qpc.h"
#include "blinky.h"
#include "bsp.h"
Q_DEFINE_THIS_FILE
/*..........................................................................*/
int main(int argc, char *argv[]) {
    static QF_MPOOL_EL(QEvt) smlPoolSto[10]; /* storage for small pool*/
    static QEvt const *blinkyQSto[10]; /* event queue storage for Blinky */
    QF_init();  /* initialize the framework */
    /* initialize the QS software tracing */
    Q_ALLEGE(QS_INIT(argc > 1 ? argv[1] : (void *)0));
    BSP_init(); /* initialize the BSP */
    /* dictionaries... */
    QS_SIG_DICTIONARY(TIMEOUT_SIG, (void *)0);
    /* pause execution of the test and wait for the test script to continue */
    QS_TEST_PAUSE();
    /* publish-subscribe not used, no call to QF_psInit() */
    /* initialize event pools... */
    QF_poolInit(smlPoolSto, sizeof(smlPoolSto), sizeof(smlPoolSto[0]));
    /* start the active objects... */
    Blinky_ctor();
    QACTIVE_START(AO_Blinky,
                  1U,
                  blinkyQSto, Q_DIM(blinkyQSto),
                  (void *)0, 0U, (void *)0);
    return QF_run();
}
/*--------------------------------------------------------------------------*/
void QS_onTestSetup(void) {
}
/*..........................................................................*/
void QS_onTestTeardown(void) {
}
/*..........................................................................*/
void QS_onCommand(uint8_t cmdId,
                  uint32_t param1, uint32_t param2, uint32_t param3)
{
    switch (cmdId) {
       case 0U: {
           break;
       }
       default:
           break;
    }
    /* unused parameters... */
    (void)param1;
    (void)param2;
    (void)param3;
}
/*..........................................................................*/
/* host callback function to "massage" the event, if necessary */
void QS_onTestEvt(QEvt *e) {
#ifdef Q_HOST  /* is this test compiled for a desktop Host computer? */
#else /* this test is compiled for an embedded Target system */
#endif
    /* unused parameters... */
    (void)e;
}
/*..........................................................................*/
/*! callback function to output the posted QP events (not used here) */
void QS_onTestPost(void const *sender, QActive *recipient,
                   QEvt const *e, bool status)
{
    /* unused parameters... */
    (void)sender;
    (void)recipient;
    (void)e;
    (void)status;
}
リスト1 QPによるLチカのサンプルコード 出所:Quantum LeapsのGitHub
#include "qpc.h"
#include "blinky.h"
#include "bsp.h"
//Q_DEFINE_THIS_MODULE("blinky")
/*************** ask QM to declare the Blinky class ******************/
/*.$declare${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
/*.${AOs::Blinky} ..........................................................*/
typedef struct {
/* protected: */
    QActive super;
/* private: */
    QTimeEvt timeEvt;
} Blinky;
/* protected: */
static QState Blinky_initial(Blinky * const me, void const * const par);
static QState Blinky_off(Blinky * const me, QEvt const * const e);
static QState Blinky_on(Blinky * const me, QEvt const * const e);
/*.$enddecl${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
static Blinky l_blinky;
/*.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
/*. Check for the minimum required QP version */
#if (QP_VERSION < 680U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
#error qpc version 6.8.0 or higher required
#endif
/*.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*.$define${AOs::AO_Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
/* opaque pointer to the Blinky AO */
/*.${AOs::AO_Blinky} .......................................................*/
QActive * const AO_Blinky = &l_blinky.super;
/*.$enddef${AOs::AO_Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*************** ask QM to define the Blinky class  ******************/
/*.$define${AOs::Blinky_ctor} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
/*.${AOs::Blinky_ctor} .....................................................*/
void Blinky_ctor(void) {
    Blinky *me = &l_blinky;
    QActive_ctor(&me->super, Q_STATE_CAST(&Blinky_initial));
    QTimeEvt_ctorX(&me->timeEvt, &me->super, TIMEOUT_SIG, 0U);
}
/*.$enddef${AOs::Blinky_ctor} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*.$define${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
/*.${AOs::Blinky} ..........................................................*/
/*.${AOs::Blinky::SM} ......................................................*/
static QState Blinky_initial(Blinky * const me, void const * const par) {
    /*.${AOs::Blinky::SM::initial} */
    (void)par; /* unused parameter */
    QS_OBJ_DICTIONARY(&l_blinky);
    QS_OBJ_DICTIONARY(&l_blinky.timeEvt);
    QTimeEvt_armX(&me->timeEvt,
        BSP_TICKS_PER_SEC/2, BSP_TICKS_PER_SEC/2);
    QS_FUN_DICTIONARY(&Blinky_off);
    QS_FUN_DICTIONARY(&Blinky_on);
    return Q_TRAN(&Blinky_off);
}
/*.${AOs::Blinky::SM::off} .................................................*/
static QState Blinky_off(Blinky * const me, QEvt const * const e) {
    QState status_;
    switch (e->sig) {
        /*.${AOs::Blinky::SM::off} */
        case Q_ENTRY_SIG: {
            BSP_ledOff();
            status_ = Q_HANDLED();
            break;
        }
        /*.${AOs::Blinky::SM::off::TIMEOUT} */
        case TIMEOUT_SIG: {
            status_ = Q_TRAN(&Blinky_on);
            break;
        }
        default: {
            status_ = Q_SUPER(&QHsm_top);
            break;
        }
    }
    return status_;
}
/*.${AOs::Blinky::SM::on} ..................................................*/
static QState Blinky_on(Blinky * const me, QEvt const * const e) {
    QState status_;
    switch (e->sig) {
        /*.${AOs::Blinky::SM::on} */
        case Q_ENTRY_SIG: {
            BSP_ledOn();
            status_ = Q_HANDLED();
            break;
        }
        /*.${AOs::Blinky::SM::on::TIMEOUT} */
        case TIMEOUT_SIG: {
            status_ = Q_TRAN(&Blinky_off);
            break;
        }
        default: {
            status_ = Q_SUPER(&QHsm_top);
            break;
        }
    }
    return status_;
}
/*.$enddef${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
リスト2 リスト1で呼び出しているBlinky_ctor()のコード 出所:Quantum LeapsのGitHub
前のページへ 1|2|3|4       

Copyright © ITmedia, Inc. All Rights Reserved.