/** * アプリケーション再送の条件判定と短いスリープ処理 * * @param E_SATET_APP_RETRY * @param pEv * @param eEvent * @param u32evarg */ PRSEV_HANDLER_DEF(E_STATE_APP_RETRY, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { V_PRINTF(LB"!E_STATE_APP_RETRY (%d)", u8RetryCount); if (!bRetry || u8RetryCount == 0) { ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 return; } // 遷移してきたとき if (eEvent == E_EVENT_NEW_STATE) { if (u8RetryCount == 0xff) { u8RetryCount = sAppData.sFlash.sData.u8wait % 10; } // 短いスリープを行う (u8RetryCount > 0) pEv->bKeepStateOnSetAll = TRUE; V_FLUSH(); uint16 u16dur = u16RetryDur / 2 + (ToCoNet_u32GetRand() % u16RetryDur); // +/-50% のランダム化 ToCoNet_vSleep(E_AHI_WAKE_TIMER_1, u16dur, FALSE, FALSE); return; } // スリープ復帰 if (eEvent == E_EVENT_START_UP) { V_PRINTF(LB"!woke from mini sleep(%d)", u8RetryCount); if (IS_APPCONF_OPT_SECURE()) { bRegAesKey(sAppData.sFlash.sData.u32EncKey); } ToCoNet_Nwk_bResume(sAppData.pContextNwk); ToCoNet_Event_SetState(pEv, E_STATE_APP_RETRY_TX); u8RetryCount--; // 再送回数を減らす return; } }
PRSEV_HANDLER_DEF(E_STATE_RUNNING, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { // 短期間スリープからの起床をしたので、センサーの値をとる if ((eEvent == E_EVENT_START_UP) && (u32evarg & EVARG_START_UP_WAKEUP_RAMHOLD_MASK)) { V_PRINTF("#"); vProcessLIS3DH(E_EVENT_START_UP); } // 2回スリープすると完了 if (u8sns_cmplt != E_SNS_ALL_CMP && (u8sns_cmplt & E_SNS_ADC_CMP_MASK)) { // ADC 完了後、この状態が来たらスリープする pEv->bKeepStateOnSetAll = TRUE; // スリープ復帰の状態を維持 vAHI_UartDisable(UART_PORT); // UART を解除してから(このコードは入っていなくても動作は同じ) vAHI_DioWakeEnable(0, 0); // スリープを行うが、WAKE_TIMER_0 は定周期スリープのためにカウントを続けているため // 空いている WAKE_TIMER_1 を利用する ToCoNet_vSleep(E_AHI_WAKE_TIMER_1, 50, FALSE, FALSE); // PERIODIC RAM OFF SLEEP USING WK1 } // 送信処理に移行 if (u8sns_cmplt == E_SNS_ALL_CMP) { ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_TX); } // タイムアウト if (ToCoNet_Event_u32TickFrNewState(pEv) > 100) { V_PRINTF(LB"! TIME OUT (E_STATE_RUNNING)"); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 } }
/** * 送信完了待ち * * @param E_STATE_APP_WAIT_TX * @param pEv * @param eEvent * @param u32evarg */ PRSEV_HANDLER_DEF(E_STATE_APP_WAIT_TX, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { if (eEvent == E_ORDER_KICK) { // 送信完了イベントが来たのでスリープする ToCoNet_Event_SetState(pEv, E_STATE_APP_RETRY); // 再送条件へ遷移 } // タイムアウト if (ToCoNet_Event_u32TickFrNewState(pEv) > 100) { V_PRINTF(LB"! TIME OUT (E_STATE_APP_WAIT_TX)"); ToCoNet_Event_SetState(pEv, E_STATE_APP_RETRY); // 再送条件へ遷移 } }
/** * 始動時の処理 * * @param E_STATE_IDLE * @param pEv * @param eEvent * @param u32evarg */ PRSEV_HANDLER_DEF(E_STATE_IDLE, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { if (eEvent == E_EVENT_START_UP) { // 起動メッセージ vSerInitMessage(); // 暗号化鍵の登録 if (IS_APPCONF_OPT_SECURE()) { bool_t bRes = bRegAesKey(sAppData.sFlash.sData.u32EncKey); V_PRINTF(LB "*** Register AES key (%d) ***", bRes); } if (u32evarg & EVARG_START_UP_WAKEUP_RAMHOLD_MASK) { // Warm start message V_PRINTF(LB "*** Warm starting woke by %s. ***", sAppData.bWakeupByButton ? "DIO" : "WakeTimer"); ToCoNet_Nwk_bResume(sAppData.pContextNwk); ToCoNet_Event_SetState(pEv, E_STATE_RUNNING); // RTS を設定 vPortSetLo(PORT_RTS0); } else { // 開始する // start up message V_PRINTF(LB "*** Cold starting(UART)"); V_PRINTF(LB "* start end device[%d]", u32TickCount_ms & 0xFFFF); sAppData.sNwkLayerTreeConfig.u8Role = TOCONET_NWK_ROLE_ENDDEVICE; // ネットワークの初期化 sAppData.pContextNwk = ToCoNet_NwkLyTr_psConfig_MiniNodes(&sAppData.sNwkLayerTreeConfig); if (sAppData.pContextNwk) { // とりあえず初期化だけしておく ToCoNet_Nwk_bInit(sAppData.pContextNwk); ToCoNet_Nwk_bStart(sAppData.pContextNwk); } // 直ぐにスリープ ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // RTS を設定 vPortSetHi(PORT_RTS0); // 再送フラグ bRetry = ((sAppData.sFlash.sData.u8wait % 10) != 0); u16RetryDur = sAppData.sFlash.sData.u8wait * 10; } // ポート出力する vPortAsOutput(PORT_RTS0); // RC クロックのキャリブレーションを行う ToCoNet_u16RcCalib(sAppData.sFlash.sData.u16RcClock); } }
PRSEV_HANDLER_DEF(E_STATE_APP_WAIT_TX, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { if (eEvent == E_EVENT_NEW_STATE) { // ネットワークの初期化 if (!sAppData.pContextNwk) { // 初回のみ sAppData.sNwkLayerTreeConfig.u8Role = TOCONET_NWK_ROLE_ENDDEVICE; sAppData.pContextNwk = ToCoNet_NwkLyTr_psConfig_MiniNodes(&sAppData.sNwkLayerTreeConfig); if (sAppData.pContextNwk) { ToCoNet_Nwk_bInit(sAppData.pContextNwk); ToCoNet_Nwk_bStart(sAppData.pContextNwk); } else { ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 return; } } else { // 一度初期化したら RESUME ToCoNet_Nwk_bResume(sAppData.pContextNwk); } uint8 au8Data[12]; uint8* q = au8Data; S_OCTET(sAppData.sSns.u8Batt); S_BE_WORD(sAppData.sSns.u16Adc1); S_BE_WORD(sAppData.sSns.u16Adc2); S_BE_WORD(sObjBME280.i16Temp); S_BE_WORD(sObjBME280.u16Hum); S_BE_WORD(sObjBME280.u16Pres); if ( bSendMessage( au8Data, q-au8Data ) ) { } else { ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // 送信失敗 } #ifdef LITE2525A vPortSetHi(LED); #else vPortSetLo(LED); #endif V_PRINTF(" FR=%04X", sAppData.u16frame_count); } if (eEvent == E_ORDER_KICK) { // 送信完了イベントが来たのでスリープする ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 } // タイムアウト if (ToCoNet_Event_u32TickFrNewState(pEv) > 100) { V_PRINTF(LB"! TIME OUT (E_STATE_APP_WAIT_TX)"); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 } }
/** * アプリケーション再送 * * @param E_STATE_APP_RETRY_TX * @param pEv * @param eEvent * @param u32evarg */ PRSEV_HANDLER_DEF(E_STATE_APP_RETRY_TX, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { // 遷移してきたとき if (eEvent == E_EVENT_NEW_STATE) { if (ToCoNet_Nwk_bTx(sAppData.pContextNwk, &sTx_Retry)) { V_PRINTF(LB"TxOk"); ToCoNet_Tx_vProcessQueue(); // 送信処理をタイマーを待たずに実行する ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_TX); } else { V_PRINTF(LB"TxFl"); ToCoNet_Event_SetState(pEv, E_STATE_APP_RETRY); } V_PRINTF(" FR=%04X", sAppData.u16frame_count); } }
/* * ADC 計測をしてデータ送信するアプリケーション制御 */ PRSEV_HANDLER_DEF(E_STATE_IDLE, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { static bool_t bFirst = TRUE; if (eEvent == E_EVENT_START_UP) { if (u32evarg & EVARG_START_UP_WAKEUP_RAMHOLD_MASK) { // Warm start message V_PRINTF(LB "*** Warm starting woke by %s. ***", sAppData.bWakeupByButton ? "DIO" : "WakeTimer"); } else { // 開始する // start up message vSerInitMessage(); V_PRINTF(LB "*** Cold starting"); V_PRINTF(LB "* start end device[%d]", u32TickCount_ms & 0xFFFF); // BME280 の初期化 } // RC クロックのキャリブレーションを行う ToCoNet_u16RcCalib(sAppData.sFlash.sData.u16RcClock); // センサーがらみの変数の初期化 u8sns_cmplt = 0; vBME280_Init( &sObjBME280, &sSnsObj ); if( bFirst ){ V_PRINTF(LB "*** BME280 Setting..."); bFirst = FALSE; bBME280_Setting(); } vSnsObj_Process(&sSnsObj, E_ORDER_KICK); if (bSnsObj_isComplete(&sSnsObj)) { // 即座に完了した時はセンサーが接続されていない、通信エラー等 u8sns_cmplt |= E_SNS_BME280_CMP; V_PRINTF(LB "*** BME280 comm err?"); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 return; } // ADC の取得 vADC_WaitInit(); vSnsObj_Process(&sAppData.sADC, E_ORDER_KICK); // RUNNING 状態 ToCoNet_Event_SetState(pEv, E_STATE_RUNNING); } else { V_PRINTF(LB "*** unexpected state."); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 } }
PRSEV_HANDLER_DEF(E_STATE_RUNNING, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { // 短期間スリープからの起床をしたので、センサーの値をとる if ((eEvent == E_EVENT_START_UP) && (u32evarg & EVARG_START_UP_WAKEUP_RAMHOLD_MASK)) { V_PRINTF("#"); vProcessBME280(E_EVENT_START_UP); } // 送信処理に移行 if (u8sns_cmplt == E_SNS_ALL_CMP) { ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_TX); } // タイムアウト if (ToCoNet_Event_u32TickFrNewState(pEv) > 100) { V_PRINTF(LB"! TIME OUT (E_STATE_RUNNING)"); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 } }
/* * 最初に遷移してくる状態 */ PRSEV_HANDLER_DEF(E_STATE_IDLE, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { // この状態から始まったときモジュールIDなどを表示する if (eEvent == E_EVENT_START_UP) { // 起床メッセージ vSerInitMessage(); // 暗号化鍵の登録 if (IS_APPCONF_OPT_SECURE()) { bool_t bRes = bRegAesKey(sAppData.sFlash.sData.u32EncKey); V_PRINTF(LB "*** Register AES key (%d) ***", bRes); } // 初回起動(リセット)かスリープからの復帰かで表示するメッセージを変える if (u32evarg & EVARG_START_UP_WAKEUP_RAMHOLD_MASK) { // Warm start message V_PRINTF(LB "*** Warm starting woke by %s. ***", sAppData.bWakeupByButton ? "DIO" : "WakeTimer"); // RESUME ToCoNet_Nwk_bResume(sAppData.pContextNwk); // RUNNING状態へ遷移 ToCoNet_Event_SetState(pEv, E_STATE_RUNNING); } else { // 開始する // start up message V_PRINTF(LB "*** Cold starting"); V_PRINTF(LB "* start end device[%d]", u32TickCount_ms & 0xFFFF); sAppData.sNwkLayerTreeConfig.u8Role = TOCONET_NWK_ROLE_ENDDEVICE; // ネットワークの初期化 sAppData.pContextNwk = ToCoNet_NwkLyTr_psConfig_MiniNodes(&sAppData.sNwkLayerTreeConfig); if (sAppData.pContextNwk) { ToCoNet_Nwk_bInit(sAppData.pContextNwk); ToCoNet_Nwk_bStart(sAppData.pContextNwk); } // 最初にパケットを送りたくないのでチャタリング対策状態へ遷移後、割り込みがあるまでスリープ ToCoNet_Event_SetState(pEv, E_STATE_APP_CHAT_SLEEP); } } }
/** * 設定処理用の状態マシン(未使用) */ static void vProcessEvCoreConfig(tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { switch (pEv->eState) { case E_STATE_IDLE: if (eEvent == E_EVENT_START_UP) { Interactive_vSetMode(TRUE, 0); vSerInitMessage(); vfPrintf(&sSerStream, LB LB "*** Entering Config Mode ***"); ToCoNet_Event_SetState(pEv, E_STATE_RUNNING); } break; case E_STATE_RUNNING: break; default: break; } }
PRIVATE void vProcessEvCore(tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { switch (pEv->eState) { case E_STATE_IDLE: if (eEvent == E_EVENT_START_UP) { // フラッシュからの読み込みが成功すれば、その Layer を採用する sAppData.sNwkLayerTreeConfig.u8Layer = 0; if (bFlash_Read(&sAppData.sFlash, FLASH_SECTOR_NUMBER-1, 0)) { sAppData.sNwkLayerTreeConfig.u8Layer = sAppData.sFlash.sData.u8Layer; } if (sAppData.sNwkLayerTreeConfig.u8Layer == 0) { sAppData.sNwkLayerTreeConfig.u8Layer = 1; } sAppData.sNwkLayerTreeConfig.u16TxMinDelayUp_ms = 100; sAppData.sNwkLayerTreeConfig.u16TxMaxDelayUp_ms = 200; #ifdef USE_AES // 暗号化鍵の登録 ToCoNet_bRegisterAesKey((void*)au8EncKey, NULL); #endif // Router として始動 sAppData.sNwkLayerTreeConfig.u8Role = TOCONET_NWK_ROLE_ROUTER; sAppData.pContextNwk = ToCoNet_NwkLyTr_psConfig(&sAppData.sNwkLayerTreeConfig); if (sAppData.pContextNwk) { vfPrintf(&sSerStream, LB "* start router (layer %d)", sAppData.sFlash.sData.u8Layer); ToCoNet_Nwk_bInit(sAppData.pContextNwk); ToCoNet_Nwk_bStart(sAppData.pContextNwk); ToCoNet_Event_SetState(pEv, E_STATE_RUNNING); } else { // fatal error } // start with verbose mode bSerCmd_VerboseMode = TRUE; } break; case E_STATE_RUNNING: break; default: break; } }
/* * 送信後のチャタリング対策を行う状態 */ PRSEV_HANDLER_DEF(E_STATE_APP_CHAT_SLEEP, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { /* 遷移してきたとき一旦眠る */ if(eEvent == E_EVENT_NEW_STATE){ V_PRINTF(LB"Safe Chattering..."); V_FLUSH(); // Mininode の場合、特別な処理は無いのだが、ポーズ処理を行う ToCoNet_Nwk_bPause(sAppData.pContextNwk); // 割り込み禁止でスリープ pEv->bKeepStateOnSetAll = TRUE; // この状態から起床 vAHI_DioWakeEnable(0, PORT_INPUT_MASK); // DISABLE DIO WAKE SOURCE ToCoNet_vSleep(E_AHI_WAKE_TIMER_1, 200UL, FALSE, FALSE); /* 起床後すぐこの状態になったときずっと眠る状態へ */ }else if(eEvent == E_EVENT_START_UP){ pEv->bKeepStateOnSetAll = FALSE; ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 } }
/**************************************************************************** * * NAME: vProcessEvent * * DESCRIPTION: * The Application Main State Machine. * * RETURNS: * ****************************************************************************/ static void vProcessEvCore(tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { switch (pEv->eState) { case E_STATE_IDLE: if (eEvent == E_EVENT_START_UP) { // フラッシュからの読み込みが成功すれば、その Layer を採用する sAppData.sNwkLayerTreeConfig.u8Layer = sAppData.sFlash.sData.u8layer; if (IS_APPCONF_OPT_SECURE()) { bool_t bRes = bRegAesKey(sAppData.sFlash.sData.u32EncKey); V_PRINTF(LB "*** Register AES key (%d) ***", bRes); } // Router として始動 sAppData.sNwkLayerTreeConfig.u8Role = TOCONET_NWK_ROLE_ROUTER; sAppData.sNwkLayerTreeConfig.u16TxMaxDelayUp_ms = 100; sAppData.pContextNwk = ToCoNet_NwkLyTr_psConfig(&sAppData.sNwkLayerTreeConfig); if (sAppData.pContextNwk) { vfPrintf(&sSerStream, LB "* start router (layer %d)", sAppData.sFlash.sData.u8layer); ToCoNet_Nwk_bInit(sAppData.pContextNwk); ToCoNet_Nwk_bStart(sAppData.pContextNwk); ToCoNet_Event_SetState(pEv, E_STATE_RUNNING); } else { // fatal error } // start with verbose mode Interactive_vSetMode(TRUE, 0); } break; case E_STATE_RUNNING: break; default: break; } }
/* 送信完了状態 */ PRSEV_HANDLER_DEF(E_STATE_APP_WAIT_TX, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { if (eEvent == E_ORDER_KICK) { // 送信完了イベントが来たのでスリープする ToCoNet_Event_SetState(pEv, E_STATE_APP_CHAT_SLEEP); // スリープ状態へ遷移 } }
PRSEV_HANDLER_DEF(E_STATE_APP_WAIT_TX, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { if (eEvent == E_EVENT_NEW_STATE) { // 暗号化鍵の登録 if (IS_APPCONF_OPT_SECURE()) { bool_t bRes = bRegAesKey(sAppData.sFlash.sData.u32EncKey); V_PRINTF(LB "*** Register AES key (%d) ***", bRes); } // ネットワークの初期化 if (!sAppData.pContextNwk) { // 初回のみ sAppData.sNwkLayerTreeConfig.u8Role = TOCONET_NWK_ROLE_ENDDEVICE; sAppData.pContextNwk = ToCoNet_NwkLyTr_psConfig_MiniNodes(&sAppData.sNwkLayerTreeConfig); if (sAppData.pContextNwk) { ToCoNet_Nwk_bInit(sAppData.pContextNwk); ToCoNet_Nwk_bStart(sAppData.pContextNwk); } else { ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 return; } } else { // 一度初期化したら RESUME ToCoNet_Nwk_bResume(sAppData.pContextNwk); } // 初期化後速やかに送信要求 V_PRINTF(LB"[SNS_COMP/TX]"); sAppData.u16frame_count++; // シリアル番号を更新する tsTxDataApp sTx; memset(&sTx, 0, sizeof(sTx)); // 必ず0クリアしてから使う! uint8 *q = sTx.auData; sTx.u32SrcAddr = ToCoNet_u32GetSerial(); if (IS_APPCONF_OPT_TO_ROUTER()) { // ルータがアプリ中で一度受信して、ルータから親機に再配送 sTx.u32DstAddr = TOCONET_NWK_ADDR_NEIGHBOUR_ABOVE; } else { // ルータがアプリ中では受信せず、単純に中継する sTx.u32DstAddr = TOCONET_NWK_ADDR_PARENT; } // ペイロードの準備 S_OCTET('T'); S_OCTET(sAppData.sFlash.sData.u8id); S_BE_WORD(sAppData.u16frame_count); S_OCTET(PKT_ID_LIS3DH); // パケット識別子 S_OCTET(sAppData.sSns.u8Batt); S_BE_WORD(sAppData.sSns.u16Adc1); S_BE_WORD(sAppData.sSns.u16Adc2); S_BE_WORD(sObjLIS3DH.ai16Result[LIS3DH_IDX_X]); S_BE_WORD(sObjLIS3DH.ai16Result[LIS3DH_IDX_Y]); S_BE_WORD(sObjLIS3DH.ai16Result[LIS3DH_IDX_Z]); /* DIの入力状態を取得 */ uint8 DI_Bitmap = readInput(); S_OCTET( DI_Bitmap ); sTx.u8Len = q - sTx.auData; // パケットのサイズ sTx.u8CbId = sAppData.u16frame_count & 0xFF; // TxEvent で通知される番号、送信先には通知されない sTx.u8Seq = sAppData.u16frame_count & 0xFF; // シーケンス番号(送信先に通知される) sTx.u8Cmd = 0; // 0..7 の値を取る。パケットの種別を分けたい時に使用する //sTx.u8Retry = 0x81; // 強制2回送信 if (IS_APPCONF_OPT_SECURE()) { sTx.bSecurePacket = TRUE; } if (ToCoNet_Nwk_bTx(sAppData.pContextNwk, &sTx)) { V_PRINTF(LB"TxOk"); ToCoNet_Tx_vProcessQueue(); // 送信処理をタイマーを待たずに実行する } else { V_PRINTF(LB"TxFl"); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // 送信失敗 } V_PRINTF(" FR=%04X", sAppData.u16frame_count); } if (eEvent == E_ORDER_KICK) { // 送信完了イベントが来たのでスリープする ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 } // タイムアウト if (ToCoNet_Event_u32TickFrNewState(pEv) > 100) { V_PRINTF(LB"! TIME OUT (E_STATE_APP_WAIT_TX)"); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 } }
/* パケットを送信する状態 */ PRSEV_HANDLER_DEF(E_STATE_RUNNING, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { if (eEvent == E_EVENT_NEW_STATE) { // ADC の開始 vADC_WaitInit(); vSnsObj_Process(&sAppData.sADC, E_ORDER_KICK); } if (eEvent == E_ORDER_KICK) { V_PRINTF(LB"[E_STATE_RUNNING/SNS_COMP]"); sAppData.u16frame_count++; // シリアル番号を更新する tsTxDataApp sTx; memset(&sTx, 0, sizeof(sTx)); // 必ず0クリアしてから使う! uint8 *q = sTx.auData; sTx.u32SrcAddr = ToCoNet_u32GetSerial(); sTx.u16DelayMin = 0; sTx.u16DelayMax = 0; sTx.u16RetryDur = 0; sTx.u8Retry = 0; if (IS_APPCONF_OPT_TO_ROUTER()) { // ルータがアプリ中で一度受信して、ルータから親機に再配送 sTx.u32DstAddr = TOCONET_NWK_ADDR_NEIGHBOUR_ABOVE; } else { // ルータがアプリ中では受信せず、単純に中継する sTx.u32DstAddr = TOCONET_NWK_ADDR_PARENT; } // ペイロードの準備 S_OCTET('T'); S_OCTET(sAppData.sFlash.sData.u8id); S_BE_WORD(sAppData.u16frame_count); S_OCTET(sAppData.sFlash.sData.u8mode); // パケット識別子 S_OCTET(sAppData.sSns.u8Batt); S_BE_WORD(sAppData.sSns.u16Adc1); S_BE_WORD(sAppData.sSns.u16Adc2); // 立ち上がりで起動 or 立ち下がりで起動 if( sAppData.sFlash.sData.i16param == 1 ){ S_OCTET(0x01); } else { S_OCTET(0x00); } /* DIの入力状態を取得 */ uint8 DI_Bitmap = readInput(); S_OCTET( DI_Bitmap ); sAppData.bDI1_Now_Opened = ((DI_Bitmap & 1) == 0); sTx.u8Len = q - sTx.auData; // パケットのサイズ sTx.u8CbId = sAppData.u16frame_count & 0xFF; // TxEvent で通知される番号、送信先には通知されない sTx.u8Seq = sAppData.u16frame_count & 0xFF; // シーケンス番号(送信先に通知される) sTx.u8Cmd = 0; // 0..7 の値を取る。パケットの種別を分けたい時に使用する //sTx.u8Retry = 0x81; // 強制2回送信 if (IS_APPCONF_OPT_SECURE()) { sTx.bSecurePacket = TRUE; } if (ToCoNet_Nwk_bTx(sAppData.pContextNwk, &sTx)) { V_PRINTF(LB"TxOk"); ToCoNet_Tx_vProcessQueue(); // 送信処理をタイマーを待たずに実行する ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_TX); } else { V_PRINTF(LB"TxFl"); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); } V_PRINTF(" FR=%04X", sAppData.u16frame_count); } }
static void vProcessEvCore(tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { switch (pEv->eState) { /* * 起動時の状態 * ToCoNetの接続を行う。 * - スリープ復帰時は直前のアドレスに対して復帰をかける。失敗した場合は再探索を行う。 */ case E_STATE_IDLE: // start up message V_PRINTF(LB "*** ToCoSamp IO Monitor %d.%02d-%d %s ***", VERSION_MAIN, VERSION_SUB, VERSION_VAR, sAppData.bWakeupByButton ? "BTN" : "OTR"); V_PRINTF(LB "* App ID:%08x Long Addr:%08x Short Addr %04x", sToCoNet_AppContext.u32AppId, ToCoNet_u32GetSerial(), sToCoNet_AppContext.u16ShortAddress); SERIAL_vFlush(UART_PORT); if (eEvent == E_EVENT_START_UP) { if (IS_APPCONF_OPT_SECURE()) { bool_t bRes = bRegAesKey(sAppData.sFlash.sData.u32EncKey); V_PRINTF(LB "*** Register AES key (%d) ***", bRes); } #ifdef USE_LCD vLcdInit(); // register sLcd // 最下行を表示する V_PRINTF_LCD_BTM("*** ToCoSamp IO Monitor %d.%02d-%d ***", VERSION_MAIN, VERSION_SUB, VERSION_VAR); vLcdRefresh(); #endif } if (eEvent == E_EVENT_START_UP && (u32evarg & EVARG_START_UP_WAKEUP_RAMHOLD_MASK)) { V_PRINTF(LB "* Warm starting woke by %s.", sAppData.bWakeupByButton ? "DIO" : "WakeTimer"); /* * 接続復帰(スリープ後) */ sAppData.eLedState = E_LED_WAIT; ToCoNet_Nwk_bResume(sAppData.pContextNwk); // ネットワークの復元 ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_NW_START); } else if (eEvent == E_EVENT_START_UP) { V_PRINTF(LB "* start end device[%d]", u32TickCount_ms & 0xFFFF); /* * ネットワークの接続 */ sAppData.sNwkLayerTreeConfig.u8Role = TOCONET_NWK_ROLE_ENDDEVICE; // EndDevice として構成する sAppData.sNwkLayerTreeConfig.u8ScanDur_10ms = 4; // 探索時間(中継機の数が数個程度なら 40ms 程度で十分) sAppData.pContextNwk = ToCoNet_NwkLyTr_psConfig(&sAppData.sNwkLayerTreeConfig); // 設定 if (sAppData.pContextNwk) { ToCoNet_Nwk_bInit(sAppData.pContextNwk); // ネットワーク初期化 ToCoNet_Nwk_bStart(sAppData.pContextNwk); // ネットワーク開始 } sAppData.eLedState = E_LED_WAIT; ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_NW_START); break; } break; /* * ネットワークの開始待ち */ case E_STATE_APP_WAIT_NW_START: if (eEvent == E_EVENT_TOCONET_NWK_START) { ToCoNet_Event_SetState(pEv, E_STATE_RUNNING); } if (ToCoNet_Event_u32TickFrNewState(pEv) > 500) { ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); } break; /* * 実行時の状態 * - ネットワーク開始後、メッセージプール要求を行う * - ネットワークがエラーになったり、タイムアウトが発生した場合はエラー状態とし、 * 再びスリープする */ case E_STATE_RUNNING: if (eEvent == E_EVENT_NEW_STATE) { // ネットワーク開始 V_PRINTF(LB"[NWK STARTED and REQUEST IO STATE:%d]", u32TickCount_ms & 0xFFFF); static uint8 u8Ct; #ifdef MSGPL_SLOT_TEST // メッセージプールの複数スロットのテストを行う // 起動ごとにスロット番号を変更して取得する u8Ct++; #else u8Ct = 0; #endif // メッセージプールの要求 if (ToCoNet_MsgPl_bRequest(u8Ct % TOCONET_MOD_MESSAGE_POOL_MAX_ENTITY)) { ToCoNet_Event_SetState(pEv, E_STATE_APP_IO_WAIT_RX); } else { ToCoNet_Event_SetState(pEv, E_STATE_APP_IO_RECV_ERROR); } } else if (eEvent == E_EVENT_TOCONET_NWK_DISCONNECT) { ToCoNet_Event_SetState(pEv, E_STATE_APP_IO_RECV_ERROR); } else { if (ToCoNet_Event_u32TickFrNewState(pEv) > ENDD_TIMEOUT_CONNECT_ms) { ToCoNet_Event_SetState(pEv, E_STATE_APP_IO_RECV_ERROR); } } break; /* * メッセージプールからの伝達待ち。 * - メッセージプールは cbToCoNet_vNwkEvent() に通知され、 * その関数中でE_EVENT_APP_GET_IC_INFOイベントを発行する。 */ case E_STATE_APP_IO_WAIT_RX: if (eEvent == E_EVENT_NEW_STATE) { V_PRINTF(LB"[E_STATE_APP_IO_WAIT_RX:%d]", u32TickCount_ms & 0xFFFF); } if (eEvent == E_EVENT_APP_GET_IC_INFO) { // メッセージが届いた if (u32evarg) { V_PRINTF(LB"[E_STATE_APP_IO_WAIT_RX:GOTDATA:%d]", u32TickCount_ms & 0xFFFF); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); } else { ToCoNet_Event_SetState(pEv, E_STATE_APP_IO_RECV_ERROR); } } else { // タイムアウト if (ToCoNet_Event_u32TickFrNewState(pEv) > ENDD_TIMEOUT_WAIT_MSG_ms) { V_PRINTF(LB"[E_STATE_APP_IO_WAIT_RX:TIMEOUT:%d]", u32TickCount_ms & 0xFFFF); ToCoNet_Event_SetState(pEv, E_STATE_APP_IO_RECV_ERROR); } } break; /* * 送信完了の処理 * - スリープ実行 */ case E_STATE_APP_IO_RECV_ERROR: case E_STATE_APP_SLEEP: if (eEvent == E_EVENT_NEW_STATE) { if (pEv->eState == E_STATE_APP_SLEEP) { V_PRINTF(LB"[E_STATE_APP_SLEEP_LED:%d]", u32TickCount_ms & 0xFFFF); sAppData.eLedState = E_LED_RESULT; } else { V_PRINTF(LB"[E_STATE_APP_IO_RECV_ERROR:%d]", u32TickCount_ms & 0xFFFF); sAppData.eLedState = E_LED_ERROR; } vPortSetHi(PORT_KIT_LED1); vPortSetHi(PORT_KIT_LED2); #ifdef NO_SLEEP ToCoNet_Event_SetState(pEv, E_STATE_APP_PREUDO_SLEEP); #else ToCoNet_Nwk_bPause(sAppData.pContextNwk); SERIAL_vFlush(UART_PORT); vSleep(0, FALSE, FALSE); #endif } break; case E_STATE_APP_PREUDO_SLEEP: // 指定時間スリープ相当の時間待ちを行う if (ToCoNet_Event_u32TickFrNewState(pEv) > ENDD_SLEEP_PERIOD_s * 1000UL) { ToCoNet_Event_SetState(pEv, E_STATE_RUNNING); } break; default: break; } }
/** * UART コマンド待ち * @param E_STATE_RUNNING * @param pEv * @param eEvent * @param u32evarg */ PRSEV_HANDLER_DEF(E_STATE_RUNNING, tsEvent *pEv, teEvent eEvent, uint32 u32evarg) { if (eEvent == E_EVENT_NEW_STATE) { uint8 au8msg[16], *q = au8msg; V_PRINTF(LB "[RUNNING]"); V_FLUSH(); // 起動メッセージとしてシリアル番号を出力する S_BE_DWORD(ToCoNet_u32GetSerial()); sSerCmdOut.au8data = au8msg; sSerCmdOut.u16len = q - au8msg; sSerCmdOut.vOutput(&sSerCmdOut, &sSerStream); } else #if 0 if (!bPortRead(DIO_BUTTON)) { // DIO_BUTTON が Hi に戻ったらスリープに戻す ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); } else #endif if (eEvent == E_ORDER_KICK) { // UARTのコマンドが入力されるまで待って、送信 tsSerCmd_Context *pCmd = NULL; if (u32evarg) { pCmd = (void*)u32evarg; } if (pCmd && pCmd->u16len <= 80) { ; // この場合は処理する } else { ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); return; } V_PRINTF(LB"[RUNNING/UARTRECV ln=%d]", pCmd->u16len); sAppData.u16frame_count++; // シリアル番号を更新する tsTxDataApp sTx; memset(&sTx, 0, sizeof(sTx)); // 必ず0クリアしてから使う! uint8 *q = sTx.auData; sTx.u32SrcAddr = ToCoNet_u32GetSerial(); if (IS_APPCONF_OPT_TO_ROUTER()) { // ルータがアプリ中で一度受信して、ルータから親機に再配送 sTx.u32DstAddr = TOCONET_NWK_ADDR_NEIGHBOUR_ABOVE; } else { // ルータがアプリ中では受信せず、単純に中継する sTx.u32DstAddr = TOCONET_NWK_ADDR_PARENT; } // ペイロードの準備 S_OCTET('T'); S_OCTET(sAppData.sFlash.sData.u8id); S_BE_WORD(sAppData.u16frame_count); S_OCTET(PKT_ID_UART); // パケット識別子 S_OCTET(pCmd->u16len); // ペイロードサイズ memcpy(q, pCmd->au8data, pCmd->u16len); // データ部 q += pCmd->u16len; sTx.u8Len = q - sTx.auData; // パケットのサイズ sTx.u8CbId = sAppData.u16frame_count & 0xFF; // TxEvent で通知される番号、送信先には通知されない sTx.u8Seq = sAppData.u16frame_count & 0xFF; // シーケンス番号(送信先に通知される) sTx.u8Cmd = 0; // 0..7 の値を取る。パケットの種別を分けたい時に使用する //sTx.u8Retry = 0x81; // 強制2回送信 if (IS_APPCONF_OPT_SECURE()) { sTx.bSecurePacket = TRUE; } if (ToCoNet_Nwk_bTx(sAppData.pContextNwk, &sTx)) { V_PRINTF(LB"TxOk"); ToCoNet_Tx_vProcessQueue(); // 送信処理をタイマーを待たずに実行する ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_TX); } else { V_PRINTF(LB"TxFl"); ToCoNet_Event_SetState(pEv, E_STATE_APP_RETRY); } if (bRetry) { sTx_Retry = sTx; } V_PRINTF(" FR=%04X", sAppData.u16frame_count); } // タイムアウト(期待の時間までにデータが来なかった) if (ToCoNet_Event_u32TickFrNewState(pEv) > sAppData.sFlash.sData.u32Slp) { V_PRINTF(LB"! TIME OUT (E_STATE_RUNNING)"); ToCoNet_Event_SetState(pEv, E_STATE_APP_SLEEP); // スリープ状態へ遷移 } }