PRSEV ライブラリ

複数の違った振る舞いをするアプリケーションをひとつのバイナリに格納する方法と、イベント状態ごとに関数定義する方法を提供します。

App_Tag のエンドデバイスでは、複数のセンサーの取り扱いについて一つのアプリケーションにまとめて、設定により動作を切り替えています。

各 vProcessEv_???.c ファイルには、個別の振る舞いをするアプリケーションの定義や手続きが含まれます。

コールバック関数の定義

コールバック関数は静的に定義するので、複数のアプリケーション動作をひとつにまとめるには都合が良くありません。ここでは、ソースファイル中に static 定義します。

/**
 * ハードウェア割り込み
 * @param u32DeviceId
 * @param u32ItemBitmap
 * @return
 */
static uint8 cbAppToCoNet_u8HwInt(uint32 u32DeviceId, uint32 u32ItemBitmap) {
    uint8 u8handled = FALSE;
    switch (u32DeviceId) {
    default:
        break;
    }
    return u8handled;
}

/**
 * ハードウェアイベント(遅延実行)
 * @param u32DeviceId
 * @param u32ItemBitmap
 */
static void cbAppToCoNet_vHwEvent(uint32 u32DeviceId, uint32 u32ItemBitmap) {
}

/**
 * メイン処理
 */
static void cbAppToCoNet_vMain() {
    /* handle serial input */
    vHandleSerialInput();
}

/**
 * ネットワークイベント
 * @param eEvent
 * @param u32arg
 */
static void cbAppToCoNet_vNwkEvent(teEvent eEvent, uint32 u32arg) {
}

/**
 * RXイベント
 * @param pRx
 */
static void cbAppToCoNet_vRxEvent(tsRxDataApp *pRx) {
}

/**
 * TXイベント
 * @param u8CbId
 * @param bStatus
 */
static void cbAppToCoNet_vTxEvent(uint8 u8CbId, uint8 bStatus) {
    // 送信完了
    ToCoNet_Event_Process(E_ORDER_KICK, 0, vProcessEvCore);
}

最後に一覧のtsCbHandler構造体を用意します。

/**
 * アプリケーションハンドラー定義
 *   使わないものは NULL にする。
 */
static tsCbHandler sCbHandler = {
    NULL, // cbAppToCoNet_u8HwInt,
    cbAppToCoNet_vHwEvent,
    NULL, // cbAppToCoNet_vMain,
    NULL, // cbAppToCoNet_vNwkEvent,
    NULL, // cbAppToCoNet_vRxEvent,
    cbAppToCoNet_vTxEvent
};

状態の定義

利用するイベントの数だけ定義を行います。

/**
 * イベント処理関数リスト
 */
static const tsToCoNet_Event_StateHandler asStateFuncTbl[] = {
    PRSEV_HANDLER_TBL_DEF(E_STATE_IDLE),
    PRSEV_HANDLER_TBL_DEF(E_STATE_RUNNING),
    PRSEV_HANDLER_TBL_DEF(E_STATE_APP_WAIT_TX),
    PRSEV_HANDLER_TBL_DEF(E_STATE_APP_SLEEP),
    PRSEV_HANDLER_TBL_TRM
};

実体は以下のように定義します。

PRSEV_HANDLER_TBL_DEF(E_STATE_IDLE, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) {
    // 開始時の状態
    if (eEvent == E_EVENT_START_UP) {
        // 電源投入またはスリープ復帰時のイベント処理
        ...
        ToCoNet_Event_SetState(pEv, E_STATE_RUNNING);
    }
}

PRSEV_HANDLER_TBL_DEF(E_STATE_RUNNING, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) {
    // 実行中(センサーの取得、送信要求など)
    bOk = bTransmitToParent( ... ); // 送信処理を行う
    if ( bOk ) {
        ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_TX);
    } else {
        ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP);
    }
}

PRSEV_HANDLER_TBL_DEF(E_STATE_APP_WAIT_TX, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) {
    // 送信完了待ち
    if (..) {
        ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移
    }
}

PRSEV_HANDLER_DEF(E_STATE_APP_SLEEP, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) {
    // スリープ手続き(以下にコード例)
    if (eEvent == E_EVENT_NEW_STATE) {
        // Sleep は必ず E_EVENT_NEW_STATE 内など1回のみ呼び出される場所で呼び出す。
        V_PRINTF(LB"Sleeping...");
        V_FLUSH();

        // Mininode の場合、特別な処理は無いのだが、ポーズ処理を行う
        ToCoNet_Nwk_bPause(sAppData.pContextNwk);

        // 周期スリープに入る
        //  - 初回は5秒あけて、次回以降はスリープ復帰を基点に5秒
        vSleep(sAppData.sFlash.sData.u32Slp, sAppData.u16frame_count == 1 ? FALSE : TRUE, FALSE);
    }
}

イベント処理関数

イベント処理関数を以下のように定義しておきます。先程の状態の定義で用意した asStateFuncTbl に従って、イベント処理が行われます。

/**
 * イベント処理関数
 * @param pEv
 * @param eEvent
 * @param u32evarg
 */
static void vProcessEvCore(tsEvent *pEv, teEvent eEvent, uint32 u32evarg) {
    ToCoNet_Event_StateExec(asStateFuncTbl, pEv, eEvent, u32evarg);
}

初期化処理

以下のようにグローバル変数として用意した psCbHandler, pvProcessEv1 に値を格納する初期化関数を用意しておきます。

/**
 * アプリケーション初期化
 */
void vInitAppStandard() {
    psCbHandler = &sCbHandler;
    pvProcessEv1 = vProcessEvCore;
}

アプリケーションの実行

コールバック関数を格納するメインファイルについて説明します。メインファイルでは、上記で定義した個々の処理用の関数を呼び出す処理を行います。

ユーザ定義イベント処理関数とTWELITE NET のコールバック関数は以下のように定義しておきます。関数ポインタで指定されるアプリケーション独自のコールバック関数を呼び出し、アプリケーション独自のユーザ定義イベント処理を実行します。

void cbAppColdStart(bool_t bInit) {
    if (bInit == FALSE) {
        ...
    } else {
        switch(u8AppType) {
        case 0x00: vInitAppStandard(); break;// AppStandard で起動
        ...
        }
        ...
        ToCoNet_Event_Register_State_Machine(pvProcessEv1);
    }
}

/**
 * メイン処理
 */
void cbToCoNet_vMain(void) {
    if (psCbHandler && psCbHandler->pf_cbToCoNet_vMain) {
        (*psCbHandler->pf_cbToCoNet_vMain)();
    }
}

/**
 * 受信処理
 */
void cbToCoNet_vRxEvent(tsRxDataApp *pRx) {
    if (psCbHandler && psCbHandler->pf_cbToCoNet_vRxEvent) {
        (*psCbHandler->pf_cbToCoNet_vRxEvent)(pRx);
    }
}

/**
 * 送信完了イベント
 */
void cbToCoNet_vTxEvent(uint8 u8CbId, uint8 bStatus) {
    if (psCbHandler && psCbHandler->pf_cbToCoNet_vTxEvent) {
        (*psCbHandler->pf_cbToCoNet_vTxEvent)(u8CbId, bStatus);
    }
}

/**
 * ネットワークイベント
 * @param eEvent
 * @param u32arg
 */
void cbToCoNet_vNwkEvent(teEvent eEvent, uint32 u32arg) {
    if (psCbHandler && psCbHandler->pf_cbToCoNet_vNwkEvent) {
        (*psCbHandler->pf_cbToCoNet_vNwkEvent)(eEvent, u32arg);
    }
}

/**
 * ハードウェアイベント処理(割り込み遅延実行)
 */
void cbToCoNet_vHwEvent(uint32 u32DeviceId, uint32 u32ItemBitmap) {
    if (psCbHandler && psCbHandler->pf_cbToCoNet_vHwEvent) {
        (*psCbHandler->pf_cbToCoNet_vHwEvent)(u32DeviceId, u32ItemBitmap);
    }
}

/**
 * ハードウェア割り込みハンドラ
 */
uint8 cbToCoNet_u8HwInt(uint32 u32DeviceId, uint32 u32ItemBitmap) {
    bool_t bRet = FALSE;
    if (psCbHandler && psCbHandler->pf_cbToCoNet_u8HwInt) {
        bRet = (*psCbHandler->pf_cbToCoNet_u8HwInt)(u32DeviceId, u32ItemBitmap);
    }
    return bRet;
}